mirror of
https://github.com/versia-pub/server.git
synced 2025-12-06 08:28:19 +01:00
Implement WebFinger, rework TS
This commit is contained in:
parent
29f63dfcb7
commit
c573052450
35
database/entities/Application.ts
Normal file
35
database/entities/Application.ts
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
}
|
||||
30
database/entities/Emoji.ts
Normal file
30
database/entities/Emoji.ts
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
23
database/entities/Favourite.ts
Normal file
23
database/entities/Favourite.ts
Normal 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;
|
||||
}
|
||||
66
database/entities/Instance.ts
Normal file
66
database/entities/Instance.ts
Normal 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,
|
||||
};
|
||||
}
|
||||
}
|
||||
18
database/entities/RawObject.ts
Normal file
18
database/entities/RawObject.ts
Normal 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;
|
||||
}
|
||||
29
database/entities/Renote.ts
Normal file
29
database/entities/Renote.ts
Normal 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
114
database/entities/Status.ts
Normal 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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -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<APIAccount> {
|
||||
return {
|
||||
acct: `@${this.username}@${getHost()}`,
|
||||
avatar: "",
|
||||
1
index.ts
1
index.ts
|
|
@ -1,4 +1,5 @@
|
|||
import { getConfig } from "@config";
|
||||
import "reflect-metadata";
|
||||
|
||||
const router = new Bun.FileSystemRouter({
|
||||
style: "nextjs",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"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"
|
||||
|
|
@ -13,7 +14,9 @@
|
|||
"typescript": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"jsonld": "^8.3.1",
|
||||
"pg": "^8.11.3",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"typeorm": "^0.3.17"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
39
server/api/.well-known/webfinger/index.ts
Normal file
39
server/api/.well-known/webfinger/index.ts
Normal 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`
|
||||
},
|
||||
]
|
||||
})
|
||||
};
|
||||
19
server/api/object/[uuid]/index.ts
Normal file
19
server/api/object/[uuid]/index.ts
Normal 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);
|
||||
};
|
||||
|
|
@ -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<Response> => {
|
||||
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());
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export interface Activity {
|
||||
export interface APIActivity {
|
||||
week: string;
|
||||
statuses: string;
|
||||
logins: string;
|
||||
|
|
|
|||
|
|
@ -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[];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export interface Application {
|
||||
export interface APIApplication {
|
||||
name: string;
|
||||
website?: string | null;
|
||||
vapid_key?: string | null;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export interface Card {
|
||||
export interface APICard {
|
||||
url: string;
|
||||
title: string;
|
||||
description: string;
|
||||
|
|
|
|||
|
|
@ -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[];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export interface Emoji {
|
||||
export interface APIEmoji {
|
||||
shortcode: string;
|
||||
static_url: string;
|
||||
url: string;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export interface FeaturedTag {
|
||||
export interface APIFeaturedTag {
|
||||
id: string;
|
||||
name: string;
|
||||
statuses_count: number;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export interface Field {
|
||||
export interface APIField {
|
||||
name: string;
|
||||
value: string;
|
||||
verified_at: string | null;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export interface Filter {
|
||||
export interface APIFilter {
|
||||
id: string;
|
||||
phrase: string;
|
||||
context: FilterContext[];
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export interface History {
|
||||
export interface APIHistory {
|
||||
day: string;
|
||||
uses: number;
|
||||
accounts: number;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export interface IdentityProof {
|
||||
export interface APIIdentityProof {
|
||||
provider: string;
|
||||
provider_username: string;
|
||||
updated_at: string;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export interface Marker {
|
||||
export interface APIMarker {
|
||||
home: {
|
||||
last_read_id: string;
|
||||
version: number;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export interface Mention {
|
||||
export interface APIMention {
|
||||
id: string;
|
||||
username: string;
|
||||
url: string;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export interface PollOption {
|
||||
export interface APIPollOption {
|
||||
title: string;
|
||||
votes_count: number | null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export interface Relationship {
|
||||
export interface APIRelationship {
|
||||
id: string;
|
||||
following: boolean;
|
||||
followed_by: boolean;
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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[];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
export interface Role {
|
||||
export interface APIRole {
|
||||
name: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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[];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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[];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export interface Stats {
|
||||
export interface APIStats {
|
||||
user_count: number;
|
||||
status_count: number;
|
||||
domain_count: number;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export interface StatusParams {
|
||||
export interface APIStatusParams {
|
||||
text: string;
|
||||
in_reply_to_id: string | null;
|
||||
media_ids: string[] | null;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export interface StatusSource {
|
||||
export interface APIStatusSource {
|
||||
id: string;
|
||||
text: string;
|
||||
spoiler_text: string;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export interface Token {
|
||||
export interface APIToken {
|
||||
access_token: string;
|
||||
token_type: string;
|
||||
scope: string;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
export interface URLs {
|
||||
export interface APIURLs {
|
||||
streaming_api: string;
|
||||
}
|
||||
|
|
|
|||
0
types/entity.ts
Normal file
0
types/entity.ts
Normal file
|
|
@ -6,3 +6,9 @@ export const jsonResponse = (data: object, status = 200) => {
|
|||
status,
|
||||
});
|
||||
}
|
||||
|
||||
export const errorResponse = (error: string, status = 500) => {
|
||||
return jsonResponse({
|
||||
error: error
|
||||
}, status);
|
||||
}
|
||||
Loading…
Reference in a new issue