Enable verbatim module syntax + more API routes

This commit is contained in:
Jesse Wierzbinski 2023-11-22 18:10:37 -10:00
parent 991a2cba84
commit be9b2e3376
No known key found for this signature in database
84 changed files with 438 additions and 192 deletions

View file

@ -16,5 +16,7 @@ module.exports = {
"@typescript-eslint/no-unsafe-assignment": "off",
"@typescript-eslint/no-unsafe-argument": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/consistent-type-exports": "error",
"@typescript-eslint/consistent-type-imports": "error"
},
};

View file

@ -154,16 +154,20 @@ Working endpoints are:
- `/oauth/authorize`
- `/oauth/token`
Endpoints left:
Tests needed but completed:
- `/api/v2/media`
- `/api/v1/media/:id`
- `/api/v1/blocks`
- `/api/v1/mutes`
Endpoints left:
- `/api/v1/reports`
- `/api/v1/accounts/:id/lists`
- `/api/v1/favourites`
- `/api/v1/accounts/:id/following`
- `/api/v1/mutes`
- `/api/v1/blocks`
- `/api/v1/follow_requests`
- `/api/v1/follow_requests/:account_id/authorize`
- `/api/v1/follow_requests/:account_id/reject`

View file

@ -1,4 +1,4 @@
import { APActivity, APActor } from "activitypub-types";
import type { APActivity, APActor } from "activitypub-types";
export class RemoteActor {
private actorData: APActor | null;

View file

@ -1,10 +1,10 @@
import type { GetObjectCommandOutput } from "@aws-sdk/client-s3";
import {
GetObjectCommand,
GetObjectCommandOutput,
PutObjectCommand,
S3Client,
} from "@aws-sdk/client-s3";
import { ConfigType } from "@config";
import type { ConfigType } from "@config";
import sharp from "sharp";
import { exists, mkdir } from "fs/promises";
class MediaBackend {

View file

@ -1,5 +1,5 @@
import { APIApplication } from "~types/entities/application";
import { Application } from "@prisma/client";
import type { APIApplication } from "~types/entities/application";
import type { Application } from "@prisma/client";
import { client } from "~database/datasource";
/**

View file

@ -1,7 +1,7 @@
import { ConfigType } from "@config";
import { Attachment } from "@prisma/client";
import { APIAsyncAttachment } from "~types/entities/async_attachment";
import { APIAttachment } from "~types/entities/attachment";
import type { ConfigType } from "@config";
import type { Attachment } from "@prisma/client";
import type { APIAsyncAttachment } from "~types/entities/async_attachment";
import type { APIAttachment } from "~types/entities/attachment";
export const attachmentToAPI = (
attachment: Attachment

View file

@ -1,7 +1,7 @@
import { APIEmoji } from "~types/entities/emoji";
import { Emoji as LysandEmoji } from "~types/lysand/extensions/org.lysand/custom_emojis";
import type { APIEmoji } from "~types/entities/emoji";
import type { Emoji as LysandEmoji } from "~types/lysand/extensions/org.lysand/custom_emojis";
import { client } from "~database/datasource";
import { Emoji } from "@prisma/client";
import type { Emoji } from "@prisma/client";
/**
* Represents an emoji entity in the database.

View file

@ -1,6 +1,6 @@
import { Instance } from "@prisma/client";
import type { Instance } from "@prisma/client";
import { client } from "~database/datasource";
import { ServerMetadata } from "~types/lysand/Object";
import type { ServerMetadata } from "~types/lysand/Object";
/**
* Represents an instance in the database.

View file

@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import { Like as LysandLike } from "~types/lysand/Object";
import type { Like as LysandLike } from "~types/lysand/Object";
import { getConfig } from "@config";
import { Like } from "@prisma/client";
import type { Like } from "@prisma/client";
/**
* Represents a Like entity in the database.

View file

@ -0,0 +1,23 @@
import type { Notification } from "@prisma/client";
import type { APINotification } from "~types/entities/notification";
import { type StatusWithRelations, statusToAPI } from "./Status";
import { type UserWithRelations, userToAPI } from "./User";
export type NotificationWithRelations = Notification & {
status: StatusWithRelations | null;
account: UserWithRelations;
};
export const notificationToAPI = async (
notification: NotificationWithRelations
): Promise<APINotification> => {
return {
account: userToAPI(notification.account),
created_at: notification.createdAt.toISOString(),
id: notification.id,
type: notification.type,
status: notification.status
? await statusToAPI(notification.status)
: undefined,
};
};

View file

@ -1,8 +1,8 @@
/* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import { LysandObject } from "@prisma/client";
import type { LysandObject } from "@prisma/client";
import { client } from "~database/datasource";
import { LysandObjectType } from "~types/lysand/Object";
import type { LysandObjectType } from "~types/lysand/Object";
/**
* Represents a Lysand object in the database.

View file

@ -1,5 +1,5 @@
import { Relationship, User } from "@prisma/client";
import { APIRelationship } from "~types/entities/relationship";
import type { Relationship, User } from "@prisma/client";
import type { APIRelationship } from "~types/entities/relationship";
import { client } from "~database/datasource";
/**

View file

@ -1,17 +1,17 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import { getConfig } from "@config";
import type { UserWithRelations } from "./User";
import {
UserWithRelations,
fetchRemoteUser,
parseMentionsUris,
userRelations,
userToAPI,
} from "./User";
import { client } from "~database/datasource";
import { LysandPublication, Note } from "~types/lysand/Object";
import type { LysandPublication, Note } from "~types/lysand/Object";
import { htmlToText } from "html-to-text";
import { getBestContentType } from "@content_types";
import {
import type {
Application,
Emoji,
Instance,
@ -21,7 +21,7 @@ import {
User,
} from "@prisma/client";
import { emojiToAPI, emojiToLysand, parseEmojis } from "./Emoji";
import { APIStatus } from "~types/entities/status";
import type { APIStatus } from "~types/entities/status";
import { applicationToAPI } from "./Application";
const config = getConfig();

View file

@ -1,8 +1,9 @@
import { ConfigType, getConfig } from "@config";
import { APIAccount } from "~types/entities/account";
import { User as LysandUser } from "~types/lysand/Object";
import type { ConfigType } from "@config";
import { getConfig } from "@config";
import type { APIAccount } from "~types/entities/account";
import type { User as LysandUser } from "~types/lysand/Object";
import { htmlToText } from "html-to-text";
import {
import type {
Emoji,
Instance,
Like,
@ -13,7 +14,7 @@ import {
import { client } from "~database/datasource";
import { addEmojiIfNotExists, emojiToAPI, emojiToLysand } from "./Emoji";
import { addInstanceIfNotExists } from "./Instance";
import { APISource } from "~types/entities/source";
import type { APISource } from "~types/entities/source";
export interface AuthData {
user: UserWithRelations | null;

View file

@ -1,15 +1,16 @@
import { getConfig } from "@config";
import { jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import chalk from "chalk";
import { appendFile } from "fs/promises";
import { matches } from "ip-matching";
import "reflect-metadata";
import { AuthData, getFromRequest } from "~database/entities/User";
import { APIRouteMeta } from "~types/api";
import type { AuthData } from "~database/entities/User";
import { getFromRequest } from "~database/entities/User";
import type { APIRouteMeta } from "~types/api";
import { mkdir } from "fs/promises";
import { client } from "~database/datasource";
import { PrismaClientInitializationError } from "@prisma/client/runtime/library";
import type { PrismaClientInitializationError } from "@prisma/client/runtime/library";
import { HookTypes, Server } from "~plugins/types";
const server = new Server();

View file

@ -1,4 +1,5 @@
import { HookTypes, Server } from "./types";
import type { Server } from "./types";
import { HookTypes } from "./types";
const registerPlugin = (server: Server) => {
server.on(HookTypes.OnPostCreate, (req, newPost, author) => {

View file

@ -1,7 +1,7 @@
import EventEmitter from "eventemitter3";
import { StatusWithRelations } from "~database/entities/Status";
import { UserWithRelations } from "~database/entities/User";
import { LysandObjectType } from "~types/lysand/Object";
import type { StatusWithRelations } from "~database/entities/Status";
import type { UserWithRelations } from "~database/entities/User";
import type { LysandObjectType } from "~types/lysand/Object";
export enum HookTypes {
/**

View file

@ -0,0 +1,22 @@
-- CreateTable
CREATE TABLE "Attachment" (
"id" UUID NOT NULL DEFAULT uuid_generate_v7(),
"url" TEXT NOT NULL,
"remote_url" TEXT,
"thumbnail_url" TEXT,
"mime_type" TEXT NOT NULL,
"description" TEXT,
"blurhash" TEXT,
"sha256" TEXT,
"fps" INTEGER,
"duration" INTEGER,
"width" INTEGER,
"height" INTEGER,
"size" INTEGER,
"statusId" UUID,
CONSTRAINT "Attachment_pkey" PRIMARY KEY ("id")
);
-- AddForeignKey
ALTER TABLE "Attachment" ADD CONSTRAINT "Attachment_statusId_fkey" FOREIGN KEY ("statusId") REFERENCES "Status"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View file

@ -92,36 +92,37 @@ model Relationship {
}
model Status {
id String @id @default(dbgenerated("uuid_generate_v7()")) @db.Uuid
uri String @unique
author User @relation("UserStatuses", fields: [authorId], references: [id], onDelete: Cascade)
authorId String @db.Uuid
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
reblog Status? @relation("StatusToStatus", fields: [reblogId], references: [id], onDelete: Cascade)
reblogId String? @db.Uuid
isReblog Boolean
content String @default("")
contentType String @default("text/plain")
visibility String
inReplyToPost Status? @relation("StatusToStatusReply", fields: [inReplyToPostId], references: [id], onDelete: SetNull)
inReplyToPostId String? @db.Uuid
quotingPost Status? @relation("StatusToStatusQuote", fields: [quotingPostId], references: [id], onDelete: SetNull)
quotingPostId String? @db.Uuid
instance Instance? @relation(fields: [instanceId], references: [id], onDelete: Cascade)
instanceId String? @db.Uuid
sensitive Boolean
spoilerText String @default("")
application Application? @relation(fields: [applicationId], references: [id], onDelete: SetNull)
applicationId String? @db.Uuid
emojis Emoji[] @relation
mentions User[]
likes Like[] @relation("LikedToStatus")
reblogs Status[] @relation("StatusToStatus")
replies Status[] @relation("StatusToStatusReply")
quotes Status[] @relation("StatusToStatusQuote")
pinnedBy User[] @relation("UserPinnedNotes")
attachments Attachment[]
id String @id @default(dbgenerated("uuid_generate_v7()")) @db.Uuid
uri String @unique
author User @relation("UserStatuses", fields: [authorId], references: [id], onDelete: Cascade)
authorId String @db.Uuid
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
reblog Status? @relation("StatusToStatus", fields: [reblogId], references: [id], onDelete: Cascade)
reblogId String? @db.Uuid
isReblog Boolean
content String @default("")
contentType String @default("text/plain")
visibility String
inReplyToPost Status? @relation("StatusToStatusReply", fields: [inReplyToPostId], references: [id], onDelete: SetNull)
inReplyToPostId String? @db.Uuid
quotingPost Status? @relation("StatusToStatusQuote", fields: [quotingPostId], references: [id], onDelete: SetNull)
quotingPostId String? @db.Uuid
instance Instance? @relation(fields: [instanceId], references: [id], onDelete: Cascade)
instanceId String? @db.Uuid
sensitive Boolean
spoilerText String @default("")
application Application? @relation(fields: [applicationId], references: [id], onDelete: SetNull)
applicationId String? @db.Uuid
emojis Emoji[] @relation
mentions User[]
likes Like[] @relation("LikedToStatus")
reblogs Status[] @relation("StatusToStatus")
replies Status[] @relation("StatusToStatusReply")
quotes Status[] @relation("StatusToStatusQuote")
pinnedBy User[] @relation("UserPinnedNotes")
attachments Attachment[]
relatedNotifications Notification[]
}
model Token {
@ -138,21 +139,33 @@ model Token {
}
model Attachment {
id String @id @default(dbgenerated("uuid_generate_v7()")) @db.Uuid
url String
remote_url String?
id String @id @default(dbgenerated("uuid_generate_v7()")) @db.Uuid
url String
remote_url String?
thumbnail_url String?
mime_type String
description String?
blurhash String?
sha256 String?
fps Int?
duration Int?
width Int?
height Int?
size Int?
status Status? @relation(fields: [statusId], references: [id], onDelete: Cascade)
statusId String? @db.Uuid
mime_type String
description String?
blurhash String?
sha256 String?
fps Int?
duration Int?
width Int?
height Int?
size Int?
status Status? @relation(fields: [statusId], references: [id], onDelete: Cascade)
statusId String? @db.Uuid
}
model Notification {
id String @id @default(dbgenerated("uuid_generate_v7()")) @db.Uuid
type String
createdAt DateTime @default(now())
notified User @relation("NotificationToNotified", fields: [notifiedId], references: [id], onDelete: Cascade)
notifiedId String @db.Uuid
account User @relation(fields: [accountId], references: [id], onDelete: Cascade)
accountId String @db.Uuid
status Status? @relation(fields: [statusId], references: [id], onDelete: Cascade)
statusId String? @db.Uuid
}
model User {
@ -186,4 +199,6 @@ model User {
tokens Token[] // One to many relation with Token
likes Like[] @relation("UserLiked") // One to many relation with Like
statusesMentioned Status[] // Many to many relation with Status
notifications Notification[] // One to many relation with Notification
notified Notification[] @relation("NotificationToNotified") // One to many relation with Notification
}

View file

@ -1,5 +1,5 @@
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import {
createNewRelationship,
relationshipToAPI,

View file

@ -1,6 +1,6 @@
import { parseRequest } from "@request";
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import {
createNewRelationship,
relationshipToAPI,

View file

@ -1,7 +1,7 @@
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import type { UserWithRelations } from "~database/entities/User";
import {
UserWithRelations,
getFromRequest,
userRelations,
userToAPI,

View file

@ -1,6 +1,6 @@
import { parseRequest } from "@request";
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import {
createNewRelationship,
relationshipToAPI,

View file

@ -1,6 +1,6 @@
import { parseRequest } from "@request";
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import {
createNewRelationship,
relationshipToAPI,

View file

@ -1,5 +1,5 @@
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import {
createNewRelationship,
relationshipToAPI,

View file

@ -1,5 +1,5 @@
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import {
createNewRelationship,
relationshipToAPI,

View file

@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import { statusAndUserRelations, statusToAPI } from "~database/entities/Status";
import { userRelations } from "~database/entities/User";
import { applyConfig } from "@api";

View file

@ -1,5 +1,5 @@
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import {
createNewRelationship,
relationshipToAPI,

View file

@ -1,5 +1,5 @@
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import {
createNewRelationship,
relationshipToAPI,

View file

@ -1,5 +1,5 @@
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import {
createNewRelationship,
relationshipToAPI,

View file

@ -1,5 +1,5 @@
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import {
createNewRelationship,
relationshipToAPI,

View file

@ -0,0 +1,40 @@
import { errorResponse, jsonResponse } from "@response";
import {
getFromRequest,
userRelations,
userToAPI,
} from "~database/entities/User";
import { applyConfig } from "@api";
import { client } from "~database/datasource";
export const meta = applyConfig({
allowedMethods: ["GET"],
route: "/api/v1/blocks",
ratelimits: {
max: 100,
duration: 60,
},
auth: {
required: true,
},
});
export default async (req: Request): Promise<Response> => {
const { user } = await getFromRequest(req);
if (!user) return errorResponse("Unauthorized", 401);
const blocks = await client.user.findMany({
where: {
relationshipSubjects: {
every: {
ownerId: user.id,
blocking: true,
},
},
},
include: userRelations,
});
return jsonResponse(blocks.map(u => userToAPI(u)));
};

View file

@ -2,11 +2,11 @@ import { applyConfig } from "@api";
import { errorResponse, jsonResponse } from "@response";
import { client } from "~database/datasource";
import { getFromRequest } from "~database/entities/User";
import { APIRouteMeta } from "~types/api";
import type { APIRouteMeta } from "~types/api";
import { uploadFile } from "~classes/media";
import { getConfig } from "@config";
import { attachmentToAPI, getUrl } from "~database/entities/Attachment";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import { parseRequest } from "@request";
export const meta: APIRouteMeta = applyConfig({

View file

@ -0,0 +1,40 @@
import { errorResponse, jsonResponse } from "@response";
import {
getFromRequest,
userRelations,
userToAPI,
} from "~database/entities/User";
import { applyConfig } from "@api";
import { client } from "~database/datasource";
export const meta = applyConfig({
allowedMethods: ["GET"],
route: "/api/v1/mutes",
ratelimits: {
max: 100,
duration: 60,
},
auth: {
required: true,
},
});
export default async (req: Request): Promise<Response> => {
const { user } = await getFromRequest(req);
if (!user) return errorResponse("Unauthorized", 401);
const blocks = await client.user.findMany({
where: {
relationshipSubjects: {
every: {
ownerId: user.id,
muting: true,
},
},
},
include: userRelations,
});
return jsonResponse(blocks.map(u => userToAPI(u)));
};

View file

@ -0,0 +1,83 @@
import { errorResponse, jsonResponse } from "@response";
import { getFromRequest, userRelations } from "~database/entities/User";
import { applyConfig } from "@api";
import { client } from "~database/datasource";
import { statusAndUserRelations } from "~database/entities/Status";
import { parseRequest } from "@request";
import { notificationToAPI } from "~database/entities/Notification";
export const meta = applyConfig({
allowedMethods: ["GET"],
route: "/api/v1/notifications",
ratelimits: {
max: 100,
duration: 60,
},
auth: {
required: true,
},
});
export default async (req: Request): Promise<Response> => {
const { user } = await getFromRequest(req);
if (!user) return errorResponse("Unauthorized", 401);
const {
account_id,
exclude_types,
limit = 15,
max_id,
min_id,
since_id,
types,
} = await parseRequest<{
max_id?: string;
since_id?: string;
min_id?: string;
limit?: number;
exclude_types?: string[];
types?: string[];
account_id?: string;
}>(req);
if (limit > 30) return errorResponse("Limit too high", 400);
if (limit <= 0) return errorResponse("Limit too low", 400);
if (types && exclude_types) {
return errorResponse("Can't use both types and exclude_types", 400);
}
const notifications = await client.notification.findMany({
where: {
notifiedId: user.id,
id: {
lt: max_id,
gt: min_id,
gte: since_id,
},
type: {
in: types,
notIn: exclude_types,
},
accountId: account_id,
},
include: {
account: {
include: userRelations,
},
status: {
include: statusAndUserRelations,
},
},
orderBy: {
id: "asc",
},
take: limit,
});
return jsonResponse(
await Promise.all(notifications.map(n => notificationToAPI(n)))
);
};

View file

@ -6,7 +6,7 @@ import {
userRelations,
userToAPI,
} from "~database/entities/User";
import { APIRouteMeta } from "~types/api";
import type { APIRouteMeta } from "~types/api";
export const meta: APIRouteMeta = applyConfig({
allowedMethods: ["DELETE"],

View file

@ -6,7 +6,7 @@ import {
userRelations,
userToAPI,
} from "~database/entities/User";
import { APIRouteMeta } from "~types/api";
import type { APIRouteMeta } from "~types/api";
export const meta: APIRouteMeta = applyConfig({
allowedMethods: ["DELETE"],

View file

@ -1,6 +1,6 @@
import { applyConfig } from "@api";
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import { client } from "~database/datasource";
import {
getAncestors,
@ -9,7 +9,7 @@ import {
statusToAPI,
} from "~database/entities/Status";
import { getFromRequest } from "~database/entities/User";
import { APIRouteMeta } from "~types/api";
import type { APIRouteMeta } from "~types/api";
export const meta: APIRouteMeta = applyConfig({
allowedMethods: ["GET"],

View file

@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import { applyConfig } from "@api";
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import { client } from "~database/datasource";
import {
isViewableByUser,
@ -9,8 +9,8 @@ import {
statusToAPI,
} from "~database/entities/Status";
import { getFromRequest } from "~database/entities/User";
import { APIRouteMeta } from "~types/api";
import { APIStatus } from "~types/entities/status";
import type { APIRouteMeta } from "~types/api";
import type { APIStatus } from "~types/entities/status";
export const meta: APIRouteMeta = applyConfig({
allowedMethods: ["POST"],

View file

@ -2,7 +2,7 @@
import { applyConfig } from "@api";
import { parseRequest } from "@request";
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import { client } from "~database/datasource";
import {
isViewableByUser,
@ -13,7 +13,7 @@ import {
userRelations,
userToAPI,
} from "~database/entities/User";
import { APIRouteMeta } from "~types/api";
import type { APIRouteMeta } from "~types/api";
export const meta: APIRouteMeta = applyConfig({
allowedMethods: ["GET"],

View file

@ -1,6 +1,6 @@
import { applyConfig } from "@api";
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import { client } from "~database/datasource";
import {
isViewableByUser,
@ -8,7 +8,7 @@ import {
statusToAPI,
} from "~database/entities/Status";
import { getFromRequest } from "~database/entities/User";
import { APIRouteMeta } from "~types/api";
import type { APIRouteMeta } from "~types/api";
export const meta: APIRouteMeta = applyConfig({
allowedMethods: ["GET", "DELETE"],

View file

@ -3,7 +3,7 @@ import { applyConfig } from "@api";
import { getConfig } from "@config";
import { parseRequest } from "@request";
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import { client } from "~database/datasource";
import {
isViewableByUser,
@ -11,7 +11,7 @@ import {
statusToAPI,
} from "~database/entities/Status";
import { getFromRequest } from "~database/entities/User";
import { APIRouteMeta } from "~types/api";
import type { APIRouteMeta } from "~types/api";
export const meta: APIRouteMeta = applyConfig({
allowedMethods: ["POST"],

View file

@ -2,7 +2,7 @@
import { applyConfig } from "@api";
import { parseRequest } from "@request";
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import { client } from "~database/datasource";
import {
isViewableByUser,
@ -13,7 +13,7 @@ import {
userRelations,
userToAPI,
} from "~database/entities/User";
import { APIRouteMeta } from "~types/api";
import type { APIRouteMeta } from "~types/api";
export const meta: APIRouteMeta = applyConfig({
allowedMethods: ["GET"],

View file

@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import { applyConfig } from "@api";
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import { client } from "~database/datasource";
import {
isViewableByUser,
@ -9,8 +9,8 @@ import {
statusToAPI,
} from "~database/entities/Status";
import { getFromRequest } from "~database/entities/User";
import { APIRouteMeta } from "~types/api";
import { APIStatus } from "~types/entities/status";
import type { APIRouteMeta } from "~types/api";
import type { APIStatus } from "~types/entities/status";
export const meta: APIRouteMeta = applyConfig({
allowedMethods: ["POST"],

View file

@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import { applyConfig } from "@api";
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import { client } from "~database/datasource";
import {
isViewableByUser,
@ -9,8 +9,8 @@ import {
statusToAPI,
} from "~database/entities/Status";
import { getFromRequest } from "~database/entities/User";
import { APIRouteMeta } from "~types/api";
import { APIStatus } from "~types/entities/status";
import type { APIRouteMeta } from "~types/api";
import type { APIStatus } from "~types/entities/status";
export const meta: APIRouteMeta = applyConfig({
allowedMethods: ["POST"],

View file

@ -6,18 +6,18 @@ import { getConfig } from "@config";
import { parseRequest } from "@request";
import { errorResponse, jsonResponse } from "@response";
import { sanitizeHtml } from "@sanitization";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import { parse } from "marked";
import { client } from "~database/datasource";
import { getFromToken } from "~database/entities/Application";
import type { StatusWithRelations } from "~database/entities/Status";
import {
StatusWithRelations,
createNewStatus,
statusAndUserRelations,
statusToAPI,
} from "~database/entities/Status";
import { AuthData, UserWithRelations } from "~database/entities/User";
import { APIRouteMeta } from "~types/api";
import type { AuthData, UserWithRelations } from "~database/entities/User";
import type { APIRouteMeta } from "~types/api";
export const meta: APIRouteMeta = applyConfig({
allowedMethods: ["POST"],

View file

@ -5,7 +5,7 @@ import { errorResponse, jsonResponse } from "@response";
import { client } from "~database/datasource";
import { statusAndUserRelations, statusToAPI } from "~database/entities/Status";
import { getFromRequest } from "~database/entities/User";
import { APIRouteMeta } from "~types/api";
import type { APIRouteMeta } from "~types/api";
export const meta: APIRouteMeta = applyConfig({
allowedMethods: ["GET"],

View file

@ -3,7 +3,7 @@ import { parseRequest } from "@request";
import { errorResponse, jsonResponse } from "@response";
import { client } from "~database/datasource";
import { statusAndUserRelations, statusToAPI } from "~database/entities/Status";
import { APIRouteMeta } from "~types/api";
import type { APIRouteMeta } from "~types/api";
export const meta: APIRouteMeta = applyConfig({
allowedMethods: ["GET"],

View file

@ -3,7 +3,7 @@ import { errorResponse, jsonResponse } from "@response";
import { client } from "~database/datasource";
import { encode } from "blurhash";
import { getFromRequest } from "~database/entities/User";
import { APIRouteMeta } from "~types/api";
import type { APIRouteMeta } from "~types/api";
import sharp from "sharp";
import { uploadFile } from "~classes/media";
import { getConfig } from "@config";

View file

@ -1,11 +1,11 @@
import { applyConfig } from "@api";
import { errorResponse } from "@response";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import { randomBytes } from "crypto";
import { client } from "~database/datasource";
import { TokenType } from "~database/entities/Token";
import { userRelations } from "~database/entities/User";
import { APIRouteMeta } from "~types/api";
import type { APIRouteMeta } from "~types/api";
export const meta: APIRouteMeta = applyConfig({
allowedMethods: ["POST"],

View file

@ -1,5 +1,5 @@
import { applyConfig } from "@api";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
export const meta = applyConfig({
allowedMethods: ["GET"],

View file

@ -2,7 +2,7 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { applyConfig } from "@api";
import { jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
export const meta = applyConfig({
allowedMethods: ["GET"],

View file

@ -4,7 +4,7 @@ import { applyConfig } from "@api";
import { getConfig } from "@config";
import { getBestContentType } from "@content_types";
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import { client } from "~database/datasource";
import { parseEmojis } from "~database/entities/Emoji";
import { createFromObject } from "~database/entities/Object";
@ -14,7 +14,11 @@ import {
statusAndUserRelations,
} from "~database/entities/Status";
import { parseMentionsUris, userRelations } from "~database/entities/User";
import { LysandAction, LysandPublication, Patch } from "~types/lysand/Object";
import type {
LysandAction,
LysandPublication,
Patch,
} from "~types/lysand/Object";
export const meta = applyConfig({
allowedMethods: ["POST"],

View file

@ -3,7 +3,7 @@
import { applyConfig } from "@api";
import { getConfig } from "@config";
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import { client } from "~database/datasource";
import { userRelations, userToLysand } from "~database/entities/User";

View file

@ -1,5 +1,5 @@
import { jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import type { MatchedRoute } from "bun";
import { getConfig, getHost } from "@config";
import { applyConfig } from "@api";
import {

View file

@ -1,13 +1,16 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-explicit-any */
import { getConfig } from "@config";
import { Token } from "@prisma/client";
import type { Token } from "@prisma/client";
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
import { client } from "~database/datasource";
import { TokenType } from "~database/entities/Token";
import { UserWithRelations, createNewLocalUser } from "~database/entities/User";
import { APIEmoji } from "~types/entities/emoji";
import { APIInstance } from "~types/entities/instance";
import {
type UserWithRelations,
createNewLocalUser,
} from "~database/entities/User";
import type { APIEmoji } from "~types/entities/emoji";
import type { APIInstance } from "~types/entities/instance";
const config = getConfig();

View file

@ -1,14 +1,17 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-explicit-any */
import { getConfig } from "@config";
import { Token } from "@prisma/client";
import type { Token } from "@prisma/client";
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
import { client } from "~database/datasource";
import { TokenType } from "~database/entities/Token";
import { UserWithRelations, createNewLocalUser } from "~database/entities/User";
import { APIAccount } from "~types/entities/account";
import { APIRelationship } from "~types/entities/relationship";
import { APIStatus } from "~types/entities/status";
import {
type UserWithRelations,
createNewLocalUser,
} from "~database/entities/User";
import type { APIAccount } from "~types/entities/account";
import type { APIRelationship } from "~types/entities/relationship";
import type { APIStatus } from "~types/entities/status";
const config = getConfig();

View file

@ -1,14 +1,17 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-explicit-any */
import { getConfig } from "@config";
import { Token } from "@prisma/client";
import type { Token } from "@prisma/client";
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
import { client } from "~database/datasource";
import { TokenType } from "~database/entities/Token";
import { UserWithRelations, createNewLocalUser } from "~database/entities/User";
import { APIAccount } from "~types/entities/account";
import { APIContext } from "~types/entities/context";
import { APIStatus } from "~types/entities/status";
import {
type UserWithRelations,
createNewLocalUser,
} from "~database/entities/User";
import type { APIAccount } from "~types/entities/account";
import type { APIContext } from "~types/entities/context";
import type { APIStatus } from "~types/entities/status";
const config = getConfig();

View file

@ -1,4 +1,4 @@
import { ConfigType, getConfig } from "@config";
import { type ConfigType, getConfig } from "@config";
import { afterAll, beforeAll, describe, expect, it } from "bun:test";
import { LocalBackend, S3Backend } from "~classes/media";
import { unlink } from "fs/promises";

View file

@ -1,5 +1,5 @@
import { getConfig } from "@config";
import { Application, Token } from "@prisma/client";
import type { Application, Token } from "@prisma/client";
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
import { client } from "~database/datasource";
import { createNewLocalUser } from "~database/entities/User";

View file

@ -20,6 +20,7 @@
"allowJs": true,
"emitDecoratorMetadata": false,
"experimentalDecorators": true,
"verbatimModuleSyntax": true,
"types": [
"bun-types" // add Bun global
],

View file

@ -1,7 +1,7 @@
import { APIEmoji } from "./emoji";
import { APIField } from "./field";
import { APIRole } from "./role";
import { APISource } from "./source";
import type { APIEmoji } from "./emoji";
import type { APIField } from "./field";
import type { APIRole } from "./role";
import type { APISource } from "./source";
export interface APIAccount {
id: string;

View file

@ -1,5 +1,5 @@
import { APIEmoji } from "./emoji";
import { APIStatusTag } from "./status";
import type { APIEmoji } from "./emoji";
import type { APIStatusTag } from "./status";
export interface APIAnnouncement {
id: string;

View file

@ -1,4 +1,4 @@
import { APIMeta } from "./attachment";
import type { APIMeta } from "./attachment";
export interface APIAsyncAttachment {
id: string;

View file

@ -1,4 +1,4 @@
import { APIStatus } from "./status";
import type { APIStatus } from "./status";
export interface APIContext {
ancestors: APIStatus[];

View file

@ -1,5 +1,5 @@
import { APIAccount } from "./account";
import { APIStatus } from "./status";
import type { APIAccount } from "./account";
import type { APIStatus } from "./status";
export interface APIConversation {
id: string;

View file

@ -1,6 +1,6 @@
import { APIAccount } from "./account";
import { APIStats } from "./stats";
import { APIURLs } from "./urls";
import type { APIAccount } from "./account";
import type { APIStats } from "./stats";
import type { APIURLs } from "./urls";
export interface APIInstance {
uri: string;

View file

@ -1,5 +1,5 @@
import { APIAccount } from "./account";
import { APIStatus } from "./status";
import type { APIAccount } from "./account";
import type { APIStatus } from "./status";
export interface APINotification {
account: APIAccount;

View file

@ -1,4 +1,4 @@
import { APIPollOption } from "./poll_option";
import type { APIPollOption } from "./poll_option";
export interface APIPoll {
id: string;

View file

@ -1,4 +1,4 @@
import { APIAccount } from "./account";
import type { APIAccount } from "./account";
export interface APIReport {
id: string;

View file

@ -1,6 +1,6 @@
import { APIAccount } from "./account";
import { APIStatus } from "./status";
import { APITag } from "./tag";
import type { APIAccount } from "./account";
import type { APIStatus } from "./status";
import type { APITag } from "./tag";
export interface APIResults {
accounts: APIAccount[];

View file

@ -1,5 +1,5 @@
import { APIAttachment } from "./attachment";
import { APIStatusParams } from "./status_params";
import type { APIAttachment } from "./attachment";
import type { APIStatusParams } from "./status_params";
export interface APIScheduledStatus {
id: string;

View file

@ -1,4 +1,4 @@
import { APIField } from "./field";
import type { APIField } from "./field";
export interface APISource {
privacy: string | null;

View file

@ -1,10 +1,10 @@
import { APIAccount } from "./account";
import { APIApplication } from "./application";
import { APIAttachment } from "./attachment";
import { APICard } from "./card";
import { APIEmoji } from "./emoji";
import { APIMention } from "./mention";
import { APIPoll } from "./poll";
import type { APIAccount } from "./account";
import type { APIApplication } from "./application";
import type { APIAttachment } from "./attachment";
import type { APICard } from "./card";
import type { APIEmoji } from "./emoji";
import type { APIMention } from "./mention";
import type { APIPoll } from "./poll";
export interface APIStatus {
id: string;

View file

@ -1,4 +1,4 @@
import { APIHistory } from "./history";
import type { APIHistory } from "./history";
export interface APITag {
name: string;

View file

@ -1,4 +1,4 @@
import { LysandObjectType } from "./Object";
import type { LysandObjectType } from "./Object";
export interface ExtensionType extends LysandObjectType {
type: "Extension";

View file

@ -1,4 +1,4 @@
import { Emoji } from "./extensions/org.lysand/custom_emojis";
import type { Emoji } from "./extensions/org.lysand/custom_emojis";
export interface LysandObjectType {
type: string;

View file

@ -1,4 +1,4 @@
import { ContentFormat } from "../../Object";
import type { ContentFormat } from "../../Object";
export interface Emoji {
name: string;

View file

@ -1,4 +1,4 @@
import { ExtensionType } from "../../Extension";
import type { ExtensionType } from "../../Extension";
export interface OrgLysandPollsVoteType extends ExtensionType {
extension_type: "org.lysand:polls/Vote";

View file

@ -1,4 +1,4 @@
import { ExtensionType } from "../../Extension";
import type { ExtensionType } from "../../Extension";
export interface OrgLysandReactionsType extends ExtensionType {
extension_type: "org.lysand:reactions/Reaction";

View file

@ -1,5 +1,5 @@
import { getConfig } from "@config";
import { APIRouteMeta } from "~types/api";
import type { APIRouteMeta } from "~types/api";
export const applyConfig = (routeMeta: APIRouteMeta) => {
const config = getConfig();

View file

@ -1,4 +1,4 @@
import { ContentFormat } from "~types/lysand/Object";
import type { ContentFormat } from "~types/lysand/Object";
export const getBestContentType = (contents: ContentFormat[]) => {
// Find the best content and content type

View file

@ -1,4 +1,4 @@
import { Application } from "@prisma/client";
import type { Application } from "@prisma/client";
/**
* Check if an OAuth application is valid for a route

View file

@ -1,5 +1,5 @@
import { APActivity, APObject } from "activitypub-types";
import { NodeObject } from "jsonld";
import type { APActivity, APObject } from "activitypub-types";
import type { NodeObject } from "jsonld";
export const jsonResponse = (
data: object,