diff --git a/bun.lockb b/bun.lockb index 86abf0f9..d4ae0e9b 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/database/entities/Application.ts b/database/entities/Application.ts new file mode 100644 index 00000000..10eb7fef --- /dev/null +++ b/database/entities/Application.ts @@ -0,0 +1,35 @@ +import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from "typeorm"; +import { APIApplication } from "~types/entities/application"; + +/** + * Applications from clients + */ +@Entity({ + name: "applications", +}) +export class Application extends BaseEntity { + @PrimaryGeneratedColumn("uuid") + id!: string; + + @Column("varchar") + name!: string; + + @Column("varchar", { + nullable: true, + }) + website!: string | null; + + @Column("varchar", { + nullable: true, + }) + vapid_key!: string | null; + + // eslint-disable-next-line @typescript-eslint/require-await + async toAPI(): Promise { + return { + name: "", + website: null, + vapid_key: null, + } + } +} \ No newline at end of file diff --git a/database/entities/DBStatus.ts b/database/entities/DBStatus.ts deleted file mode 100644 index e28df093..00000000 --- a/database/entities/DBStatus.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { getConfig } from "@config"; -import { - BaseEntity, - Column, - CreateDateColumn, - Entity, - ManyToOne, - PrimaryGeneratedColumn, - UpdateDateColumn, -} from "typeorm"; -import { Status } from "~types/entities/status"; -import { DBUser } from "./DBUser"; - -const config = getConfig(); - -@Entity({ - name: "statuses", -}) -export class DBStatus extends BaseEntity { - @PrimaryGeneratedColumn("uuid") - id!: string; - - @ManyToOne(() => DBUser, (user) => user.id) - account!: DBUser; - - @CreateDateColumn() - created_at!: Date; - - @UpdateDateColumn() - updated_at!: Date; - - @ManyToOne(() => DBStatus, (status) => status.id, { - nullable: true, - }) - reblog?: DBStatus; - - @Column("boolean") - isReblog!: boolean; - - toAPI(): Status { - return { - account: this.account.toAPI(), - application: null, - bookmarked: false, - created_at: this.created_at.toISOString(), - emojis: [], - favourited: false, - favourites_count: 0, - id: this.id, - in_reply_to_account_id: null, - in_reply_to_id: null, - language: null, - media_attachments: [], - mentions: [], - muted: false, - pinned: false, - poll: null, - reblog: this.isReblog ? this.reblog?.toAPI() ?? null : null, - reblogged: false, - reblogs_count: 0, - replies_count: 0, - sensitive: false, - spoiler_text: "", - tags: [], - card: null, - content: "", - uri: `${config.http.base_url}/@${this.account.username}/${this.id}`, - url: `${config.http.base_url}/@${this.account.username}/${this.id}`, - visibility: "public", - quote: null, - }; - } -} diff --git a/database/entities/Emoji.ts b/database/entities/Emoji.ts new file mode 100644 index 00000000..53b59691 --- /dev/null +++ b/database/entities/Emoji.ts @@ -0,0 +1,30 @@ +import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from "typeorm"; +import { APIEmoji } from "~types/entities/emoji"; + +@Entity({ + name: "emojis", +}) +export class Emoji extends BaseEntity { + @PrimaryGeneratedColumn("uuid") + id!: string; + + @Column("varchar") + shortcode!: string; + + @Column("varchar") + url!: string; + + @Column("boolean") + visible_in_picker!: boolean; + + // eslint-disable-next-line @typescript-eslint/require-await + async toAPI(): Promise { + return { + shortcode: this.shortcode, + static_url: "", + url: "", + visible_in_picker: false, + category: undefined, + } + } +} \ No newline at end of file diff --git a/database/entities/Favourite.ts b/database/entities/Favourite.ts new file mode 100644 index 00000000..2c61fe9e --- /dev/null +++ b/database/entities/Favourite.ts @@ -0,0 +1,23 @@ +import { BaseEntity, Column, Entity, ManyToOne, PrimaryGeneratedColumn } from "typeorm"; +import { User } from "./User"; +import { Status } from "./Status"; + +/** + * Stores an ActivityPub Like event + */ +@Entity({ + name: "favourites", +}) +export class Favourite extends BaseEntity { + @PrimaryGeneratedColumn("uuid") + id!: string; + + @ManyToOne(() => User, (user) => user.id) + actor!: User; + + @ManyToOne(() => Status, (status) => status.id) + object!: Status; + + @Column("datetime") + published!: Date; +} \ No newline at end of file diff --git a/database/entities/Instance.ts b/database/entities/Instance.ts new file mode 100644 index 00000000..c54aff58 --- /dev/null +++ b/database/entities/Instance.ts @@ -0,0 +1,66 @@ +import { BaseEntity, Column, Entity, ManyToOne, PrimaryGeneratedColumn } from "typeorm"; +import { APIInstance } from "~types/entities/instance"; +import { User } from "./User"; + +@Entity({ + name: "instances", +}) +export class Instance extends BaseEntity { + @PrimaryGeneratedColumn("uuid") + id!: string; + + @ManyToOne(() => User, (user) => user.id) + contact_account!: User; + + @Column("jsonb", { + default: { + media_attachments: { + image_matrix_limit: 0, + image_size_limit: 0, + supported_mime_types: [], + video_frame_limit: 0, + video_matrix_limit: 0, + video_size_limit: 0, + }, + polls: { + max_options: 0, + max_characters_per_option: 0, + max_expiration: 0, + min_expiration: 0, + }, + statuses: { + characters_reserved_per_url: 0, + max_characters: 0, + max_media_attachments: 0, + }, + }, + }) + configuration!: APIInstance["configuration"]; + + async toAPI(): Promise { + return { + uri: "", + approval_required: false, + email: "", + thumbnail: "", + title: "", + version: "", + configuration: this.configuration, + contact_account: await this.contact_account.toAPI(), + description: "", + invites_enabled: false, + languages: [], + registrations: false, + rules: [], + stats: { + domain_count: 0, + status_count: 0, + user_count: 0, + }, + urls: { + streaming_api: "", + }, + max_toot_chars: 0, + }; + } +} \ No newline at end of file diff --git a/database/entities/RawObject.ts b/database/entities/RawObject.ts new file mode 100644 index 00000000..983b100f --- /dev/null +++ b/database/entities/RawObject.ts @@ -0,0 +1,18 @@ +import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from "typeorm"; +import { + APObject, +} from "activitypub-types"; + +/** + * Stores an ActivityPub object as raw JSON-LD data + */ +@Entity({ + name: "objects", +}) +export class RawObject extends BaseEntity { + @PrimaryGeneratedColumn("uuid") + id!: string; + + @Column("json") + data!: APObject; +} \ No newline at end of file diff --git a/database/entities/Renote.ts b/database/entities/Renote.ts new file mode 100644 index 00000000..45f789b0 --- /dev/null +++ b/database/entities/Renote.ts @@ -0,0 +1,29 @@ +import { + BaseEntity, + Column, + Entity, + ManyToOne, + PrimaryGeneratedColumn, +} from "typeorm"; +import { User } from "./User"; +import { Status } from "./Status"; + +/** + * Stores an ActivityPub Renote event + */ +@Entity({ + name: "renotes", +}) +export class Renote extends BaseEntity { + @PrimaryGeneratedColumn("uuid") + id!: string; + + @ManyToOne(() => User, (user) => user.id) + actor!: User; + + @ManyToOne(() => Status, (status) => status.id) + object!: Status; + + @Column("datetime") + published!: Date; +} diff --git a/database/entities/Status.ts b/database/entities/Status.ts new file mode 100644 index 00000000..ee6a2a68 --- /dev/null +++ b/database/entities/Status.ts @@ -0,0 +1,114 @@ +import { getConfig } from "@config"; +import { + BaseEntity, + Column, + CreateDateColumn, + Entity, + ManyToMany, + ManyToOne, + PrimaryGeneratedColumn, + UpdateDateColumn, +} from "typeorm"; +import { APIStatus } from "~types/entities/status"; +import { User } from "./User"; +import { Application } from "./Application"; +import { Emoji } from "./Emoji"; +import { Favourite } from "./Favourite"; + +const config = getConfig(); + +/** + * Stores ActivityPub notes + */ +@Entity({ + name: "statuses", +}) +export class Status extends BaseEntity { + @PrimaryGeneratedColumn("uuid") + id!: string; + + @ManyToOne(() => User, (user) => user.id) + account!: User; + + @CreateDateColumn() + created_at!: Date; + + @UpdateDateColumn() + updated_at!: Date; + + @ManyToOne(() => Status, (status) => status.id, { + nullable: true, + }) + reblog?: Status; + + @Column("boolean") + isReblog!: boolean; + + @Column("varchar", { + default: "", + }) + content!: string; + + @Column("varchar") + visibility!: APIStatus["visibility"]; + + @Column("boolean") + sensitive!: boolean; + + @Column("varchar", { + default: "", + }) + spoiler_text!: string; + + @ManyToOne(() => Application, (app) => app.id, { + nullable: true + }) + application!: Application | null; + + @ManyToMany(() => Emoji, (emoji) => emoji.id) + emojis!: Emoji[]; + + async getFavourites(): Promise { + return Favourite.find({ + where: { + object: { + id: this.id + }, + }, + }); + } + + async toAPI(): Promise { + return { + account: await this.account.toAPI(), + application: await this.application?.toAPI() ?? null, + bookmarked: false, + created_at: this.created_at.toISOString(), + emojis: await Promise.all(this.emojis.map(async (emoji) => await emoji.toAPI())), + favourited: false, + favourites_count: (await this.getFavourites()).length, + id: this.id, + in_reply_to_account_id: null, + in_reply_to_id: null, + language: null, + media_attachments: [], + mentions: [], + muted: false, + pinned: false, + poll: null, + reblog: this.isReblog ? await this.reblog?.toAPI() ?? null : null, + reblogged: false, + reblogs_count: 0, + replies_count: 0, + sensitive: false, + spoiler_text: "", + tags: [], + card: null, + content: "", + uri: `${config.http.base_url}/@${this.account.username}/${this.id}`, + url: `${config.http.base_url}/@${this.account.username}/${this.id}`, + visibility: "public", + quote: null, + }; + } +} diff --git a/database/entities/DBUser.ts b/database/entities/User.ts similarity index 77% rename from database/entities/DBUser.ts rename to database/entities/User.ts index 0c4ca44f..6a8c3e4b 100644 --- a/database/entities/DBUser.ts +++ b/database/entities/User.ts @@ -1,13 +1,16 @@ import { getConfig, getHost } from "@config"; import { BaseEntity, Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from "typeorm"; -import { Account } from "~types/entities/account"; +import { APIAccount } from "~types/entities/account"; const config = getConfig(); +/** + * Stores local and remote users + */ @Entity({ name: "users", }) -export class DBUser extends BaseEntity { +export class User extends BaseEntity { @PrimaryGeneratedColumn("uuid") id!: string; @@ -16,8 +19,10 @@ export class DBUser extends BaseEntity { }) username!: string; - @Column("varchar") - password!: string; + @Column("varchar", { + nullable: true, + }) + password!: string | null; @Column("varchar", { unique: true, @@ -35,7 +40,11 @@ export class DBUser extends BaseEntity { @UpdateDateColumn() updated_at!: Date; - toAPI(): Account { + @Column("boolean") + isRemote!: boolean; + + // eslint-disable-next-line @typescript-eslint/require-await + async toAPI(): Promise { return { acct: `@${this.username}@${getHost()}`, avatar: "", diff --git a/index.ts b/index.ts index bc6bb8ef..f44d8fde 100644 --- a/index.ts +++ b/index.ts @@ -1,4 +1,5 @@ import { getConfig } from "@config"; +import "reflect-metadata"; const router = new Bun.FileSystemRouter({ style: "nextjs", diff --git a/package.json b/package.json index 75e85fd0..459dcd8d 100644 --- a/package.json +++ b/package.json @@ -1,19 +1,22 @@ { - "name": "fedi-project", - "module": "index.ts", - "type": "module", - "devDependencies": { - "@typescript-eslint/eslint-plugin": "^6.6.0", - "@typescript-eslint/parser": "^6.6.0", - "bun-types": "latest", - "eslint": "^8.49.0", - "typescript": "^5.2.2" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "dependencies": { - "pg": "^8.11.3", - "typeorm": "^0.3.17" - } + "name": "fedi-project", + "module": "index.ts", + "type": "module", + "devDependencies": { + "@typescript-eslint/eslint-plugin": "^6.6.0", + "@typescript-eslint/parser": "^6.6.0", + "activitypub-types": "^1.0.3", + "bun-types": "latest", + "eslint": "^8.49.0", + "typescript": "^5.2.2" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "dependencies": { + "jsonld": "^8.3.1", + "pg": "^8.11.3", + "reflect-metadata": "^0.1.13", + "typeorm": "^0.3.17" + } } diff --git a/server/api/.well-known/webfinger/index.ts b/server/api/.well-known/webfinger/index.ts new file mode 100644 index 00000000..415990d9 --- /dev/null +++ b/server/api/.well-known/webfinger/index.ts @@ -0,0 +1,39 @@ +import { errorResponse, jsonResponse } from "@response"; +import { MatchedRoute } from "bun"; +import { User } from "~database/entities/User"; +import { getHost } from "@config"; + +/** + * ActivityPub WebFinger endpoint + */ +export default async ( + req: Request, + matchedRoute: MatchedRoute +): Promise => { + // In the format acct:name@example.com + const resource = matchedRoute.query.resource; + const requestedUser = resource.split("acct:")[1]; + + // Check if user is a local user + if (requestedUser.split("@")[1] !== getHost()) { + return errorResponse("User is a remote user", 404); + } + + const user = await User.findOneBy({ username: requestedUser.split("@")[0] }); + + if (!user) { + return errorResponse("User not found", 404); + } + + return jsonResponse({ + subject: `acct:${user.username}@${getHost()}`, + + links: [ + { + rel: "self", + type: "application/activity+json", + href: `${getHost()}/@${user.username}/actor` + }, + ] + }) +}; diff --git a/server/api/object/[uuid]/index.ts b/server/api/object/[uuid]/index.ts new file mode 100644 index 00000000..30a68e3e --- /dev/null +++ b/server/api/object/[uuid]/index.ts @@ -0,0 +1,19 @@ +import { errorResponse, jsonResponse } from "@response"; +import { MatchedRoute } from "bun"; +import { RawObject } from "~database/entities/RawObject"; + +/** + * Fetch a user + */ +export default async ( + req: Request, + matchedRoute: MatchedRoute +): Promise => { + const object = await RawObject.findOneBy({ + id: matchedRoute.params.id + }); + + if (!object) return errorResponse("Object not found", 404) + + return jsonResponse(object); +}; diff --git a/server/api/v1/accounts/[id]/index.ts b/server/api/v1/accounts/[id]/index.ts index c7253c64..a4102bb8 100644 --- a/server/api/v1/accounts/[id]/index.ts +++ b/server/api/v1/accounts/[id]/index.ts @@ -1,24 +1,22 @@ -import { jsonResponse } from "@response"; +import { errorResponse, jsonResponse } from "@response"; import { MatchedRoute } from "bun"; -import { DBUser } from "~database/entities/DBUser"; +import { User } from "~database/entities/User"; +/** + * Fetch a user + */ export default async ( req: Request, matchedRoute: MatchedRoute ): Promise => { const id = matchedRoute.params.id; - const user = await DBUser.findOneBy({ + const user = await User.findOneBy({ id, }); if (!user) - return jsonResponse( - { - error: "User not found", - }, - 404 - ); + return errorResponse("User not found", 404) return jsonResponse(user.toAPI()); }; diff --git a/server/api/v1/accounts/[id]/statuses.ts b/server/api/v1/accounts/[id]/statuses.ts index cdc08534..1e5db16e 100644 --- a/server/api/v1/accounts/[id]/statuses.ts +++ b/server/api/v1/accounts/[id]/statuses.ts @@ -1,8 +1,11 @@ -import { jsonResponse } from "@response"; +import { errorResponse, jsonResponse } from "@response"; import { MatchedRoute } from "bun"; -import { DBStatus } from "~database/entities/DBStatus"; -import { DBUser } from "~database/entities/DBUser"; +import { Status } from "~database/entities/Status"; +import { User } from "~database/entities/User"; +/** + * Fetch all statuses for a user + */ export default async ( req: Request, matchedRoute: MatchedRoute @@ -24,19 +27,14 @@ export default async ( tagged?: string; } = matchedRoute.query; - const user = await DBUser.findOneBy({ + const user = await User.findOneBy({ id, }); if (!user) - return jsonResponse( - { - error: "User not found", - }, - 404 - ); + return errorResponse("User not found", 404) - const statuses = await DBStatus.find({ + const statuses = await Status.find({ where: { account: { id: user.id, diff --git a/tsconfig.json b/tsconfig.json index efa87a01..a26f7689 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,6 +18,7 @@ "strictFunctionTypes": true, "forceConsistentCasingInFileNames": true, "allowJs": true, + "emitDecoratorMetadata": true, "experimentalDecorators": true, "types": [ "bun-types" // add Bun global @@ -25,6 +26,11 @@ "paths": { "@*": ["./utils/*"], "~*": ["./*"] - } - } + }, + }, + "include": [ + "*.ts", + "**/*.ts", + "server/api/.well-known/**/*.ts" + ] } diff --git a/types/entities/account.ts b/types/entities/account.ts index 52a5e532..311342c2 100644 --- a/types/entities/account.ts +++ b/types/entities/account.ts @@ -1,9 +1,9 @@ -import { Emoji } from "./emoji"; -import { Field } from "./field"; -import { Role } from "./role"; -import { Source } from "./source"; +import { APIEmoji } from "./emoji"; +import { APIField } from "./field"; +import { APIRole } from "./role"; +import { APISource } from "./source"; -export interface Account { +export interface APIAccount { id: string; username: string; acct: string; @@ -24,11 +24,11 @@ export interface Account { avatar_static: string; header: string; header_static: string; - emojis: Emoji[]; - moved: Account | null; - fields: Field[]; + emojis: APIEmoji[]; + moved: APIAccount | null; + fields: APIField[]; bot: boolean; - source?: Source; - role?: Role; + source?: APISource; + role?: APIRole; mute_expires_at?: string; } diff --git a/types/entities/activity.ts b/types/entities/activity.ts index 5e1b4d10..5b21fdc2 100644 --- a/types/entities/activity.ts +++ b/types/entities/activity.ts @@ -1,4 +1,4 @@ -export interface Activity { +export interface APIActivity { week: string; statuses: string; logins: string; diff --git a/types/entities/announcement.ts b/types/entities/announcement.ts index 953c3eb7..73955b0b 100644 --- a/types/entities/announcement.ts +++ b/types/entities/announcement.ts @@ -1,7 +1,7 @@ -import { Emoji } from "./emoji"; -import { StatusTag } from "./status"; +import { APIEmoji } from "./emoji"; +import { APIStatusTag } from "./status"; -export interface Announcement { +export interface APIAnnouncement { id: string; content: string; starts_at: string | null; @@ -13,8 +13,8 @@ export interface Announcement { read: boolean | null; mentions: AnnouncementAccount[]; statuses: AnnouncementStatus[]; - tags: StatusTag[]; - emojis: Emoji[]; + tags: APIStatusTag[]; + emojis: APIEmoji[]; reactions: AnnouncementReaction[]; } diff --git a/types/entities/application.ts b/types/entities/application.ts index f95d6630..3439df77 100644 --- a/types/entities/application.ts +++ b/types/entities/application.ts @@ -1,4 +1,4 @@ -export interface Application { +export interface APIApplication { name: string; website?: string | null; vapid_key?: string | null; diff --git a/types/entities/async_attachment.ts b/types/entities/async_attachment.ts index 71817c1b..e46cd2c9 100644 --- a/types/entities/async_attachment.ts +++ b/types/entities/async_attachment.ts @@ -1,13 +1,13 @@ -import { Meta } from "./attachment"; +import { APIMeta } from "./attachment"; -export interface AsyncAttachment { +export interface APIAsyncAttachment { id: string; type: "unknown" | "image" | "gifv" | "video" | "audio"; url: string | null; remote_url: string | null; preview_url: string; text_url: string | null; - meta: Meta | null; + meta: APIMeta | null; description: string | null; blurhash: string | null; } diff --git a/types/entities/attachment.ts b/types/entities/attachment.ts index 2933fd6c..b494fdd0 100644 --- a/types/entities/attachment.ts +++ b/types/entities/attachment.ts @@ -1,4 +1,4 @@ -export interface Sub { +export interface APISub { // For Image, Gifv, and Video width?: number; height?: number; @@ -13,15 +13,15 @@ export interface Sub { bitrate?: number; } -export interface Focus { +export interface APIFocus { x: number; y: number; } -export interface Meta { - original?: Sub; - small?: Sub; - focus?: Focus; +export interface APIMeta { + original?: APISub; + small?: APISub; + focus?: APIFocus; length?: string; duration?: number; fps?: number; @@ -34,14 +34,14 @@ export interface Meta { audio_channel?: string; } -export interface Attachment { +export interface APIAttachment { id: string; type: "unknown" | "image" | "gifv" | "video" | "audio"; url: string; remote_url: string | null; preview_url: string | null; text_url: string | null; - meta: Meta | null; + meta: APIMeta | null; description: string | null; blurhash: string | null; } diff --git a/types/entities/card.ts b/types/entities/card.ts index bd496cd9..1e139ad0 100644 --- a/types/entities/card.ts +++ b/types/entities/card.ts @@ -1,4 +1,4 @@ -export interface Card { +export interface APICard { url: string; title: string; description: string; diff --git a/types/entities/context.ts b/types/entities/context.ts index e73a0180..79dfeac3 100644 --- a/types/entities/context.ts +++ b/types/entities/context.ts @@ -1,6 +1,6 @@ -import { Status } from "./status"; +import { APIStatus } from "./status"; -export interface Context { - ancestors: Status[]; - descendants: Status[]; +export interface APIContext { + ancestors: APIStatus[]; + descendants: APIStatus[]; } diff --git a/types/entities/conversation.ts b/types/entities/conversation.ts index d8eeeda3..ef05c835 100644 --- a/types/entities/conversation.ts +++ b/types/entities/conversation.ts @@ -1,9 +1,9 @@ -import { Account } from "./account"; -import { Status } from "./status"; +import { APIAccount } from "./account"; +import { APIStatus } from "./status"; -export interface Conversation { +export interface APIConversation { id: string; - accounts: Account[]; - last_status: Status | null; + accounts: APIAccount[]; + last_status: APIStatus | null; unread: boolean; } diff --git a/types/entities/emoji.ts b/types/entities/emoji.ts index 32e4437f..ea725c8e 100644 --- a/types/entities/emoji.ts +++ b/types/entities/emoji.ts @@ -1,4 +1,4 @@ -export interface Emoji { +export interface APIEmoji { shortcode: string; static_url: string; url: string; diff --git a/types/entities/featured_tag.ts b/types/entities/featured_tag.ts index 765acb0b..e8a04d2d 100644 --- a/types/entities/featured_tag.ts +++ b/types/entities/featured_tag.ts @@ -1,4 +1,4 @@ -export interface FeaturedTag { +export interface APIFeaturedTag { id: string; name: string; statuses_count: number; diff --git a/types/entities/field.ts b/types/entities/field.ts index f5e5cb83..2030e80d 100644 --- a/types/entities/field.ts +++ b/types/entities/field.ts @@ -1,4 +1,4 @@ -export interface Field { +export interface APIField { name: string; value: string; verified_at: string | null; diff --git a/types/entities/filter.ts b/types/entities/filter.ts index 496dfe4e..e3fd6d43 100644 --- a/types/entities/filter.ts +++ b/types/entities/filter.ts @@ -1,4 +1,4 @@ -export interface Filter { +export interface APIFilter { id: string; phrase: string; context: FilterContext[]; diff --git a/types/entities/history.ts b/types/entities/history.ts index 4c9d55d3..985b52f0 100644 --- a/types/entities/history.ts +++ b/types/entities/history.ts @@ -1,4 +1,4 @@ -export interface History { +export interface APIHistory { day: string; uses: number; accounts: number; diff --git a/types/entities/identity_proof.ts b/types/entities/identity_proof.ts index a7aff6e1..513925ff 100644 --- a/types/entities/identity_proof.ts +++ b/types/entities/identity_proof.ts @@ -1,4 +1,4 @@ -export interface IdentityProof { +export interface APIIdentityProof { provider: string; provider_username: string; updated_at: string; diff --git a/types/entities/instance.ts b/types/entities/instance.ts index f111c4c5..ba3c270e 100644 --- a/types/entities/instance.ts +++ b/types/entities/instance.ts @@ -1,16 +1,16 @@ -import { Account } from "./account"; -import { Stats } from "./stats"; -import { URLs } from "./urls"; +import { APIAccount } from "./account"; +import { APIStats } from "./stats"; +import { APIURLs } from "./urls"; -export interface Instance { +export interface APIInstance { uri: string; title: string; description: string; email: string; version: string; thumbnail: string | null; - urls: URLs; - stats: Stats; + urls: APIURLs; + stats: APIStats; languages: string[]; registrations: boolean; approval_required: boolean; @@ -37,11 +37,11 @@ export interface Instance { max_expiration: number; }; }; - contact_account: Account; - rules: InstanceRule[]; + contact_account: APIAccount; + rules: APIInstanceRule[]; } -export interface InstanceRule { +export interface APIInstanceRule { id: string; text: string; } diff --git a/types/entities/list.ts b/types/entities/list.ts index d61ccb53..85ccbf52 100644 --- a/types/entities/list.ts +++ b/types/entities/list.ts @@ -1,7 +1,7 @@ -export interface List { +export interface APIList { id: string; title: string; - replies_policy: RepliesPolicy; + replies_policy: APIRepliesPolicy; } -export type RepliesPolicy = "followed" | "list" | "none"; +export type APIRepliesPolicy = "followed" | "list" | "none"; diff --git a/types/entities/marker.ts b/types/entities/marker.ts index 8668487c..d81b47aa 100644 --- a/types/entities/marker.ts +++ b/types/entities/marker.ts @@ -1,4 +1,4 @@ -export interface Marker { +export interface APIMarker { home: { last_read_id: string; version: number; diff --git a/types/entities/mention.ts b/types/entities/mention.ts index b323e149..f229af90 100644 --- a/types/entities/mention.ts +++ b/types/entities/mention.ts @@ -1,4 +1,4 @@ -export interface Mention { +export interface APIMention { id: string; username: string; url: string; diff --git a/types/entities/notification.ts b/types/entities/notification.ts index cca7fbba..6e8b4288 100644 --- a/types/entities/notification.ts +++ b/types/entities/notification.ts @@ -1,12 +1,12 @@ -import { Account } from "./account"; -import { Status } from "./status"; +import { APIAccount } from "./account"; +import { APIStatus } from "./status"; -export interface Notification { - account: Account; +export interface APINotification { + account: APIAccount; created_at: string; id: string; - status?: Status; - type: NotificationType; + status?: APIStatus; + type: APINotificationType; } -export type NotificationType = string; +export type APINotificationType = string; diff --git a/types/entities/poll.ts b/types/entities/poll.ts index efa3e357..1de2bf1d 100644 --- a/types/entities/poll.ts +++ b/types/entities/poll.ts @@ -1,11 +1,11 @@ -import { PollOption } from "./poll_option"; +import { APIPollOption } from "./poll_option"; -export interface Poll { +export interface APIPoll { id: string; expires_at: string | null; expired: boolean; multiple: boolean; votes_count: number; - options: PollOption[]; + options: APIPollOption[]; voted: boolean; } diff --git a/types/entities/poll_option.ts b/types/entities/poll_option.ts index 89375a56..86017868 100644 --- a/types/entities/poll_option.ts +++ b/types/entities/poll_option.ts @@ -1,4 +1,4 @@ -export interface PollOption { +export interface APIPollOption { title: string; votes_count: number | null; } diff --git a/types/entities/preferences.ts b/types/entities/preferences.ts index eb144ab6..1ad5b14f 100644 --- a/types/entities/preferences.ts +++ b/types/entities/preferences.ts @@ -1,4 +1,4 @@ -export interface Preferences { +export interface APIPreferences { "posting:default:visibility": "public" | "unlisted" | "private" | "direct"; "posting:default:sensitive": boolean; "posting:default:language": string | null; diff --git a/types/entities/push_subscription.ts b/types/entities/push_subscription.ts index 907a996e..ab48c6dc 100644 --- a/types/entities/push_subscription.ts +++ b/types/entities/push_subscription.ts @@ -1,4 +1,4 @@ -export interface Alerts { +export interface APIAlerts { follow: boolean; favourite: boolean; mention: boolean; @@ -6,9 +6,9 @@ export interface Alerts { poll: boolean; } -export interface PushSubscription { +export interface APIPushSubscription { id: string; endpoint: string; server_key: string; - alerts: Alerts; + alerts: APIAlerts; } diff --git a/types/entities/relationship.ts b/types/entities/relationship.ts index 330a7f17..5dffd082 100644 --- a/types/entities/relationship.ts +++ b/types/entities/relationship.ts @@ -1,4 +1,4 @@ -export interface Relationship { +export interface APIRelationship { id: string; following: boolean; followed_by: boolean; diff --git a/types/entities/report.ts b/types/entities/report.ts index 487fd7b0..efc7d3ff 100644 --- a/types/entities/report.ts +++ b/types/entities/report.ts @@ -1,15 +1,15 @@ -import { Account } from "./account"; +import { APIAccount } from "./account"; -export interface Report { +export interface APIReport { id: string; action_taken: boolean; action_taken_at: string | null; - category: Category; + category: APICategory; comment: string; forwarded: boolean; status_ids: string[] | null; rule_ids: string[] | null; - target_account: Account; + target_account: APIAccount; } -export type Category = "spam" | "violation" | "other"; +export type APICategory = "spam" | "violation" | "other"; diff --git a/types/entities/results.ts b/types/entities/results.ts index ba10872d..54c1d2bd 100644 --- a/types/entities/results.ts +++ b/types/entities/results.ts @@ -1,9 +1,9 @@ -import { Account } from "./account"; -import { Status } from "./status"; -import { Tag } from "./tag"; +import { APIAccount } from "./account"; +import { APIStatus } from "./status"; +import { APITag } from "./tag"; -export interface Results { - accounts: Account[]; - statuses: Status[]; - hashtags: Tag[]; +export interface APIResults { + accounts: APIAccount[]; + statuses: APIStatus[]; + hashtags: APITag[]; } diff --git a/types/entities/role.ts b/types/entities/role.ts index 4566feac..6bb0f4b6 100644 --- a/types/entities/role.ts +++ b/types/entities/role.ts @@ -1,3 +1,3 @@ -export interface Role { +export interface APIRole { name: string; } diff --git a/types/entities/scheduled_status.ts b/types/entities/scheduled_status.ts index 58330967..10b9f505 100644 --- a/types/entities/scheduled_status.ts +++ b/types/entities/scheduled_status.ts @@ -1,9 +1,9 @@ -import { Attachment } from "./attachment"; -import { StatusParams } from "./status_params"; +import { APIAttachment } from "./attachment"; +import { APIStatusParams } from "./status_params"; -export interface ScheduledStatus { +export interface APIScheduledStatus { id: string; scheduled_at: string; - params: StatusParams; - media_attachments: Attachment[]; + params: APIStatusParams; + media_attachments: APIAttachment[]; } diff --git a/types/entities/source.ts b/types/entities/source.ts index b11c0b33..bd18094a 100644 --- a/types/entities/source.ts +++ b/types/entities/source.ts @@ -1,9 +1,9 @@ -import { Field } from "./field"; +import { APIField } from "./field"; -export interface Source { +export interface APISource { privacy: string | null; sensitive: boolean | null; language: string | null; note: string; - fields: Field[]; + fields: APIField[]; } diff --git a/types/entities/stats.ts b/types/entities/stats.ts index 4f3e825d..3effffe9 100644 --- a/types/entities/stats.ts +++ b/types/entities/stats.ts @@ -1,4 +1,4 @@ -export interface Stats { +export interface APIStats { user_count: number; status_count: number; domain_count: number; diff --git a/types/entities/status.ts b/types/entities/status.ts index 4a0eb2a9..6fb21a5d 100644 --- a/types/entities/status.ts +++ b/types/entities/status.ts @@ -1,22 +1,22 @@ -import { Account } from "./account"; -import { Application } from "./application"; -import { Attachment } from "./attachment"; -import { Card } from "./card"; -import { Emoji } from "./emoji"; -import { Mention } from "./mention"; -import { Poll } from "./poll"; +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"; -export interface Status { +export interface APIStatus { id: string; uri: string; url: string; - account: Account; + account: APIAccount; in_reply_to_id: string | null; in_reply_to_account_id: string | null; - reblog: Status | null; + reblog: APIStatus | null; content: string; created_at: string; - emojis: Emoji[]; + emojis: APIEmoji[]; replies_count: number; reblogs_count: number; favourites_count: number; @@ -26,21 +26,21 @@ export interface Status { sensitive: boolean; spoiler_text: string; visibility: "public" | "unlisted" | "private" | "direct"; - media_attachments: Attachment[]; - mentions: Mention[]; - tags: StatusTag[]; - card: Card | null; - poll: Poll | null; - application: Application | null; + media_attachments: APIAttachment[]; + mentions: APIMention[]; + tags: APIStatusTag[]; + card: APICard | null; + poll: APIPoll | null; + application: APIApplication | null; language: string | null; pinned: boolean | null; bookmarked?: boolean; // These parameters are unique parameters in fedibird.com for quote. quote_id?: string; - quote?: Status | null; + quote?: APIStatus | null; } -export interface StatusTag { +export interface APIStatusTag { name: string; url: string; } diff --git a/types/entities/status_params.ts b/types/entities/status_params.ts index 3f67a6c0..7c74bb56 100644 --- a/types/entities/status_params.ts +++ b/types/entities/status_params.ts @@ -1,4 +1,4 @@ -export interface StatusParams { +export interface APIStatusParams { text: string; in_reply_to_id: string | null; media_ids: string[] | null; diff --git a/types/entities/status_source.ts b/types/entities/status_source.ts index 095d4682..3f82d1b8 100644 --- a/types/entities/status_source.ts +++ b/types/entities/status_source.ts @@ -1,4 +1,4 @@ -export interface StatusSource { +export interface APIStatusSource { id: string; text: string; spoiler_text: string; diff --git a/types/entities/tag.ts b/types/entities/tag.ts index 7022eccb..a519dca2 100644 --- a/types/entities/tag.ts +++ b/types/entities/tag.ts @@ -1,8 +1,8 @@ -import { History } from "./history"; +import { APIHistory } from "./history"; -export interface Tag { +export interface APITag { name: string; url: string; - history: History[]; + history: APIHistory[]; following?: boolean; } diff --git a/types/entities/token.ts b/types/entities/token.ts index 90b94280..54450272 100644 --- a/types/entities/token.ts +++ b/types/entities/token.ts @@ -1,4 +1,4 @@ -export interface Token { +export interface APIToken { access_token: string; token_type: string; scope: string; diff --git a/types/entities/urls.ts b/types/entities/urls.ts index 1f877fe2..8a7134f1 100644 --- a/types/entities/urls.ts +++ b/types/entities/urls.ts @@ -1,3 +1,3 @@ -export interface URLs { +export interface APIURLs { streaming_api: string; } diff --git a/types/entity.ts b/types/entity.ts new file mode 100644 index 00000000..e69de29b diff --git a/utils/response.ts b/utils/response.ts index eb820d94..f6148dbd 100644 --- a/utils/response.ts +++ b/utils/response.ts @@ -5,4 +5,10 @@ export const jsonResponse = (data: object, status = 200) => { }, status, }); +} + +export const errorResponse = (error: string, status = 500) => { + return jsonResponse({ + error: error + }, status); } \ No newline at end of file