Implement WebFinger, rework TS

This commit is contained in:
Jesse Wierzbinski 2023-09-12 10:48:10 -10:00
parent 29f63dfcb7
commit c573052450
No known key found for this signature in database
GPG key ID: F9A1E418934E40B0
56 changed files with 560 additions and 239 deletions

BIN
bun.lockb

Binary file not shown.

View file

@ -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<APIApplication> {
return {
name: "",
website: null,
vapid_key: null,
}
}
}

View file

@ -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,
};
}
}

View file

@ -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<APIEmoji> {
return {
shortcode: this.shortcode,
static_url: "",
url: "",
visible_in_picker: false,
category: undefined,
}
}
}

View file

@ -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;
}

View file

@ -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<APIInstance> {
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,
};
}
}

View file

@ -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;
}

View file

@ -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;
}

114
database/entities/Status.ts Normal file
View file

@ -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<Favourite[]> {
return Favourite.find({
where: {
object: {
id: this.id
},
},
});
}
async toAPI(): Promise<APIStatus> {
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,
};
}
}

View file

@ -1,13 +1,16 @@
import { getConfig, getHost } from "@config"; import { getConfig, getHost } from "@config";
import { BaseEntity, Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from "typeorm"; import { BaseEntity, Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from "typeorm";
import { Account } from "~types/entities/account"; import { APIAccount } from "~types/entities/account";
const config = getConfig(); const config = getConfig();
/**
* Stores local and remote users
*/
@Entity({ @Entity({
name: "users", name: "users",
}) })
export class DBUser extends BaseEntity { export class User extends BaseEntity {
@PrimaryGeneratedColumn("uuid") @PrimaryGeneratedColumn("uuid")
id!: string; id!: string;
@ -16,8 +19,10 @@ export class DBUser extends BaseEntity {
}) })
username!: string; username!: string;
@Column("varchar") @Column("varchar", {
password!: string; nullable: true,
})
password!: string | null;
@Column("varchar", { @Column("varchar", {
unique: true, unique: true,
@ -35,7 +40,11 @@ export class DBUser extends BaseEntity {
@UpdateDateColumn() @UpdateDateColumn()
updated_at!: Date; updated_at!: Date;
toAPI(): Account { @Column("boolean")
isRemote!: boolean;
// eslint-disable-next-line @typescript-eslint/require-await
async toAPI(): Promise<APIAccount> {
return { return {
acct: `@${this.username}@${getHost()}`, acct: `@${this.username}@${getHost()}`,
avatar: "", avatar: "",

View file

@ -1,4 +1,5 @@
import { getConfig } from "@config"; import { getConfig } from "@config";
import "reflect-metadata";
const router = new Bun.FileSystemRouter({ const router = new Bun.FileSystemRouter({
style: "nextjs", style: "nextjs",

View file

@ -1,19 +1,22 @@
{ {
"name": "fedi-project", "name": "fedi-project",
"module": "index.ts", "module": "index.ts",
"type": "module", "type": "module",
"devDependencies": { "devDependencies": {
"@typescript-eslint/eslint-plugin": "^6.6.0", "@typescript-eslint/eslint-plugin": "^6.6.0",
"@typescript-eslint/parser": "^6.6.0", "@typescript-eslint/parser": "^6.6.0",
"bun-types": "latest", "activitypub-types": "^1.0.3",
"eslint": "^8.49.0", "bun-types": "latest",
"typescript": "^5.2.2" "eslint": "^8.49.0",
}, "typescript": "^5.2.2"
"peerDependencies": { },
"typescript": "^5.0.0" "peerDependencies": {
}, "typescript": "^5.0.0"
"dependencies": { },
"pg": "^8.11.3", "dependencies": {
"typeorm": "^0.3.17" "jsonld": "^8.3.1",
} "pg": "^8.11.3",
"reflect-metadata": "^0.1.13",
"typeorm": "^0.3.17"
}
} }

View file

@ -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<Response> => {
// 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`
},
]
})
};

View file

@ -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<Response> => {
const object = await RawObject.findOneBy({
id: matchedRoute.params.id
});
if (!object) return errorResponse("Object not found", 404)
return jsonResponse(object);
};

View file

@ -1,24 +1,22 @@
import { jsonResponse } from "@response"; import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun"; import { MatchedRoute } from "bun";
import { DBUser } from "~database/entities/DBUser"; import { User } from "~database/entities/User";
/**
* Fetch a user
*/
export default async ( export default async (
req: Request, req: Request,
matchedRoute: MatchedRoute matchedRoute: MatchedRoute
): Promise<Response> => { ): Promise<Response> => {
const id = matchedRoute.params.id; const id = matchedRoute.params.id;
const user = await DBUser.findOneBy({ const user = await User.findOneBy({
id, id,
}); });
if (!user) if (!user)
return jsonResponse( return errorResponse("User not found", 404)
{
error: "User not found",
},
404
);
return jsonResponse(user.toAPI()); return jsonResponse(user.toAPI());
}; };

View file

@ -1,8 +1,11 @@
import { jsonResponse } from "@response"; import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun"; import { MatchedRoute } from "bun";
import { DBStatus } from "~database/entities/DBStatus"; import { Status } from "~database/entities/Status";
import { DBUser } from "~database/entities/DBUser"; import { User } from "~database/entities/User";
/**
* Fetch all statuses for a user
*/
export default async ( export default async (
req: Request, req: Request,
matchedRoute: MatchedRoute matchedRoute: MatchedRoute
@ -24,19 +27,14 @@ export default async (
tagged?: string; tagged?: string;
} = matchedRoute.query; } = matchedRoute.query;
const user = await DBUser.findOneBy({ const user = await User.findOneBy({
id, id,
}); });
if (!user) if (!user)
return jsonResponse( return errorResponse("User not found", 404)
{
error: "User not found",
},
404
);
const statuses = await DBStatus.find({ const statuses = await Status.find({
where: { where: {
account: { account: {
id: user.id, id: user.id,

View file

@ -18,6 +18,7 @@
"strictFunctionTypes": true, "strictFunctionTypes": true,
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"allowJs": true, "allowJs": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true, "experimentalDecorators": true,
"types": [ "types": [
"bun-types" // add Bun global "bun-types" // add Bun global
@ -25,6 +26,11 @@
"paths": { "paths": {
"@*": ["./utils/*"], "@*": ["./utils/*"],
"~*": ["./*"] "~*": ["./*"]
} },
} },
"include": [
"*.ts",
"**/*.ts",
"server/api/.well-known/**/*.ts"
]
} }

View file

@ -1,9 +1,9 @@
import { Emoji } from "./emoji"; import { APIEmoji } from "./emoji";
import { Field } from "./field"; import { APIField } from "./field";
import { Role } from "./role"; import { APIRole } from "./role";
import { Source } from "./source"; import { APISource } from "./source";
export interface Account { export interface APIAccount {
id: string; id: string;
username: string; username: string;
acct: string; acct: string;
@ -24,11 +24,11 @@ export interface Account {
avatar_static: string; avatar_static: string;
header: string; header: string;
header_static: string; header_static: string;
emojis: Emoji[]; emojis: APIEmoji[];
moved: Account | null; moved: APIAccount | null;
fields: Field[]; fields: APIField[];
bot: boolean; bot: boolean;
source?: Source; source?: APISource;
role?: Role; role?: APIRole;
mute_expires_at?: string; mute_expires_at?: string;
} }

View file

@ -1,4 +1,4 @@
export interface Activity { export interface APIActivity {
week: string; week: string;
statuses: string; statuses: string;
logins: string; logins: string;

View file

@ -1,7 +1,7 @@
import { Emoji } from "./emoji"; import { APIEmoji } from "./emoji";
import { StatusTag } from "./status"; import { APIStatusTag } from "./status";
export interface Announcement { export interface APIAnnouncement {
id: string; id: string;
content: string; content: string;
starts_at: string | null; starts_at: string | null;
@ -13,8 +13,8 @@ export interface Announcement {
read: boolean | null; read: boolean | null;
mentions: AnnouncementAccount[]; mentions: AnnouncementAccount[];
statuses: AnnouncementStatus[]; statuses: AnnouncementStatus[];
tags: StatusTag[]; tags: APIStatusTag[];
emojis: Emoji[]; emojis: APIEmoji[];
reactions: AnnouncementReaction[]; reactions: AnnouncementReaction[];
} }

View file

@ -1,4 +1,4 @@
export interface Application { export interface APIApplication {
name: string; name: string;
website?: string | null; website?: string | null;
vapid_key?: string | null; vapid_key?: string | null;

View file

@ -1,13 +1,13 @@
import { Meta } from "./attachment"; import { APIMeta } from "./attachment";
export interface AsyncAttachment { export interface APIAsyncAttachment {
id: string; id: string;
type: "unknown" | "image" | "gifv" | "video" | "audio"; type: "unknown" | "image" | "gifv" | "video" | "audio";
url: string | null; url: string | null;
remote_url: string | null; remote_url: string | null;
preview_url: string; preview_url: string;
text_url: string | null; text_url: string | null;
meta: Meta | null; meta: APIMeta | null;
description: string | null; description: string | null;
blurhash: string | null; blurhash: string | null;
} }

View file

@ -1,4 +1,4 @@
export interface Sub { export interface APISub {
// For Image, Gifv, and Video // For Image, Gifv, and Video
width?: number; width?: number;
height?: number; height?: number;
@ -13,15 +13,15 @@ export interface Sub {
bitrate?: number; bitrate?: number;
} }
export interface Focus { export interface APIFocus {
x: number; x: number;
y: number; y: number;
} }
export interface Meta { export interface APIMeta {
original?: Sub; original?: APISub;
small?: Sub; small?: APISub;
focus?: Focus; focus?: APIFocus;
length?: string; length?: string;
duration?: number; duration?: number;
fps?: number; fps?: number;
@ -34,14 +34,14 @@ export interface Meta {
audio_channel?: string; audio_channel?: string;
} }
export interface Attachment { export interface APIAttachment {
id: string; id: string;
type: "unknown" | "image" | "gifv" | "video" | "audio"; type: "unknown" | "image" | "gifv" | "video" | "audio";
url: string; url: string;
remote_url: string | null; remote_url: string | null;
preview_url: string | null; preview_url: string | null;
text_url: string | null; text_url: string | null;
meta: Meta | null; meta: APIMeta | null;
description: string | null; description: string | null;
blurhash: string | null; blurhash: string | null;
} }

View file

@ -1,4 +1,4 @@
export interface Card { export interface APICard {
url: string; url: string;
title: string; title: string;
description: string; description: string;

View file

@ -1,6 +1,6 @@
import { Status } from "./status"; import { APIStatus } from "./status";
export interface Context { export interface APIContext {
ancestors: Status[]; ancestors: APIStatus[];
descendants: Status[]; descendants: APIStatus[];
} }

View file

@ -1,9 +1,9 @@
import { Account } from "./account"; import { APIAccount } from "./account";
import { Status } from "./status"; import { APIStatus } from "./status";
export interface Conversation { export interface APIConversation {
id: string; id: string;
accounts: Account[]; accounts: APIAccount[];
last_status: Status | null; last_status: APIStatus | null;
unread: boolean; unread: boolean;
} }

View file

@ -1,4 +1,4 @@
export interface Emoji { export interface APIEmoji {
shortcode: string; shortcode: string;
static_url: string; static_url: string;
url: string; url: string;

View file

@ -1,4 +1,4 @@
export interface FeaturedTag { export interface APIFeaturedTag {
id: string; id: string;
name: string; name: string;
statuses_count: number; statuses_count: number;

View file

@ -1,4 +1,4 @@
export interface Field { export interface APIField {
name: string; name: string;
value: string; value: string;
verified_at: string | null; verified_at: string | null;

View file

@ -1,4 +1,4 @@
export interface Filter { export interface APIFilter {
id: string; id: string;
phrase: string; phrase: string;
context: FilterContext[]; context: FilterContext[];

View file

@ -1,4 +1,4 @@
export interface History { export interface APIHistory {
day: string; day: string;
uses: number; uses: number;
accounts: number; accounts: number;

View file

@ -1,4 +1,4 @@
export interface IdentityProof { export interface APIIdentityProof {
provider: string; provider: string;
provider_username: string; provider_username: string;
updated_at: string; updated_at: string;

View file

@ -1,16 +1,16 @@
import { Account } from "./account"; import { APIAccount } from "./account";
import { Stats } from "./stats"; import { APIStats } from "./stats";
import { URLs } from "./urls"; import { APIURLs } from "./urls";
export interface Instance { export interface APIInstance {
uri: string; uri: string;
title: string; title: string;
description: string; description: string;
email: string; email: string;
version: string; version: string;
thumbnail: string | null; thumbnail: string | null;
urls: URLs; urls: APIURLs;
stats: Stats; stats: APIStats;
languages: string[]; languages: string[];
registrations: boolean; registrations: boolean;
approval_required: boolean; approval_required: boolean;
@ -37,11 +37,11 @@ export interface Instance {
max_expiration: number; max_expiration: number;
}; };
}; };
contact_account: Account; contact_account: APIAccount;
rules: InstanceRule[]; rules: APIInstanceRule[];
} }
export interface InstanceRule { export interface APIInstanceRule {
id: string; id: string;
text: string; text: string;
} }

View file

@ -1,7 +1,7 @@
export interface List { export interface APIList {
id: string; id: string;
title: string; title: string;
replies_policy: RepliesPolicy; replies_policy: APIRepliesPolicy;
} }
export type RepliesPolicy = "followed" | "list" | "none"; export type APIRepliesPolicy = "followed" | "list" | "none";

View file

@ -1,4 +1,4 @@
export interface Marker { export interface APIMarker {
home: { home: {
last_read_id: string; last_read_id: string;
version: number; version: number;

View file

@ -1,4 +1,4 @@
export interface Mention { export interface APIMention {
id: string; id: string;
username: string; username: string;
url: string; url: string;

View file

@ -1,12 +1,12 @@
import { Account } from "./account"; import { APIAccount } from "./account";
import { Status } from "./status"; import { APIStatus } from "./status";
export interface Notification { export interface APINotification {
account: Account; account: APIAccount;
created_at: string; created_at: string;
id: string; id: string;
status?: Status; status?: APIStatus;
type: NotificationType; type: APINotificationType;
} }
export type NotificationType = string; export type APINotificationType = string;

View file

@ -1,11 +1,11 @@
import { PollOption } from "./poll_option"; import { APIPollOption } from "./poll_option";
export interface Poll { export interface APIPoll {
id: string; id: string;
expires_at: string | null; expires_at: string | null;
expired: boolean; expired: boolean;
multiple: boolean; multiple: boolean;
votes_count: number; votes_count: number;
options: PollOption[]; options: APIPollOption[];
voted: boolean; voted: boolean;
} }

View file

@ -1,4 +1,4 @@
export interface PollOption { export interface APIPollOption {
title: string; title: string;
votes_count: number | null; votes_count: number | null;
} }

View file

@ -1,4 +1,4 @@
export interface Preferences { export interface APIPreferences {
"posting:default:visibility": "public" | "unlisted" | "private" | "direct"; "posting:default:visibility": "public" | "unlisted" | "private" | "direct";
"posting:default:sensitive": boolean; "posting:default:sensitive": boolean;
"posting:default:language": string | null; "posting:default:language": string | null;

View file

@ -1,4 +1,4 @@
export interface Alerts { export interface APIAlerts {
follow: boolean; follow: boolean;
favourite: boolean; favourite: boolean;
mention: boolean; mention: boolean;
@ -6,9 +6,9 @@ export interface Alerts {
poll: boolean; poll: boolean;
} }
export interface PushSubscription { export interface APIPushSubscription {
id: string; id: string;
endpoint: string; endpoint: string;
server_key: string; server_key: string;
alerts: Alerts; alerts: APIAlerts;
} }

View file

@ -1,4 +1,4 @@
export interface Relationship { export interface APIRelationship {
id: string; id: string;
following: boolean; following: boolean;
followed_by: boolean; followed_by: boolean;

View file

@ -1,15 +1,15 @@
import { Account } from "./account"; import { APIAccount } from "./account";
export interface Report { export interface APIReport {
id: string; id: string;
action_taken: boolean; action_taken: boolean;
action_taken_at: string | null; action_taken_at: string | null;
category: Category; category: APICategory;
comment: string; comment: string;
forwarded: boolean; forwarded: boolean;
status_ids: string[] | null; status_ids: string[] | null;
rule_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";

View file

@ -1,9 +1,9 @@
import { Account } from "./account"; import { APIAccount } from "./account";
import { Status } from "./status"; import { APIStatus } from "./status";
import { Tag } from "./tag"; import { APITag } from "./tag";
export interface Results { export interface APIResults {
accounts: Account[]; accounts: APIAccount[];
statuses: Status[]; statuses: APIStatus[];
hashtags: Tag[]; hashtags: APITag[];
} }

View file

@ -1,3 +1,3 @@
export interface Role { export interface APIRole {
name: string; name: string;
} }

View file

@ -1,9 +1,9 @@
import { Attachment } from "./attachment"; import { APIAttachment } from "./attachment";
import { StatusParams } from "./status_params"; import { APIStatusParams } from "./status_params";
export interface ScheduledStatus { export interface APIScheduledStatus {
id: string; id: string;
scheduled_at: string; scheduled_at: string;
params: StatusParams; params: APIStatusParams;
media_attachments: Attachment[]; media_attachments: APIAttachment[];
} }

View file

@ -1,9 +1,9 @@
import { Field } from "./field"; import { APIField } from "./field";
export interface Source { export interface APISource {
privacy: string | null; privacy: string | null;
sensitive: boolean | null; sensitive: boolean | null;
language: string | null; language: string | null;
note: string; note: string;
fields: Field[]; fields: APIField[];
} }

View file

@ -1,4 +1,4 @@
export interface Stats { export interface APIStats {
user_count: number; user_count: number;
status_count: number; status_count: number;
domain_count: number; domain_count: number;

View file

@ -1,22 +1,22 @@
import { Account } from "./account"; import { APIAccount } from "./account";
import { Application } from "./application"; import { APIApplication } from "./application";
import { Attachment } from "./attachment"; import { APIAttachment } from "./attachment";
import { Card } from "./card"; import { APICard } from "./card";
import { Emoji } from "./emoji"; import { APIEmoji } from "./emoji";
import { Mention } from "./mention"; import { APIMention } from "./mention";
import { Poll } from "./poll"; import { APIPoll } from "./poll";
export interface Status { export interface APIStatus {
id: string; id: string;
uri: string; uri: string;
url: string; url: string;
account: Account; account: APIAccount;
in_reply_to_id: string | null; in_reply_to_id: string | null;
in_reply_to_account_id: string | null; in_reply_to_account_id: string | null;
reblog: Status | null; reblog: APIStatus | null;
content: string; content: string;
created_at: string; created_at: string;
emojis: Emoji[]; emojis: APIEmoji[];
replies_count: number; replies_count: number;
reblogs_count: number; reblogs_count: number;
favourites_count: number; favourites_count: number;
@ -26,21 +26,21 @@ export interface Status {
sensitive: boolean; sensitive: boolean;
spoiler_text: string; spoiler_text: string;
visibility: "public" | "unlisted" | "private" | "direct"; visibility: "public" | "unlisted" | "private" | "direct";
media_attachments: Attachment[]; media_attachments: APIAttachment[];
mentions: Mention[]; mentions: APIMention[];
tags: StatusTag[]; tags: APIStatusTag[];
card: Card | null; card: APICard | null;
poll: Poll | null; poll: APIPoll | null;
application: Application | null; application: APIApplication | null;
language: string | null; language: string | null;
pinned: boolean | null; pinned: boolean | null;
bookmarked?: boolean; bookmarked?: boolean;
// These parameters are unique parameters in fedibird.com for quote. // These parameters are unique parameters in fedibird.com for quote.
quote_id?: string; quote_id?: string;
quote?: Status | null; quote?: APIStatus | null;
} }
export interface StatusTag { export interface APIStatusTag {
name: string; name: string;
url: string; url: string;
} }

View file

@ -1,4 +1,4 @@
export interface StatusParams { export interface APIStatusParams {
text: string; text: string;
in_reply_to_id: string | null; in_reply_to_id: string | null;
media_ids: string[] | null; media_ids: string[] | null;

View file

@ -1,4 +1,4 @@
export interface StatusSource { export interface APIStatusSource {
id: string; id: string;
text: string; text: string;
spoiler_text: string; spoiler_text: string;

View file

@ -1,8 +1,8 @@
import { History } from "./history"; import { APIHistory } from "./history";
export interface Tag { export interface APITag {
name: string; name: string;
url: string; url: string;
history: History[]; history: APIHistory[];
following?: boolean; following?: boolean;
} }

View file

@ -1,4 +1,4 @@
export interface Token { export interface APIToken {
access_token: string; access_token: string;
token_type: string; token_type: string;
scope: string; scope: string;

View file

@ -1,3 +1,3 @@
export interface URLs { export interface APIURLs {
streaming_api: string; streaming_api: string;
} }

0
types/entity.ts Normal file
View file

View file

@ -5,4 +5,10 @@ export const jsonResponse = (data: object, status = 200) => {
}, },
status, status,
}); });
}
export const errorResponse = (error: string, status = 500) => {
return jsonResponse({
error: error
}, status);
} }