mirror of
https://github.com/versia-pub/server.git
synced 2025-12-06 08:28:19 +01:00
feat(api): ✨ Add OpenAPI visualizer
Some checks failed
CodeQL Scan / Analyze (javascript-typescript) (push) Failing after 53s
Build Docker Images / lint (push) Failing after 10s
Build Docker Images / check (push) Failing after 10s
Build Docker Images / tests (push) Failing after 6s
Build Docker Images / build (server, Dockerfile, ${{ github.repository_owner }}/server) (push) Has been skipped
Build Docker Images / build (worker, Worker.Dockerfile, ${{ github.repository_owner }}/worker) (push) Has been skipped
Deploy Docs to GitHub Pages / build (push) Failing after 5s
Mirror to Codeberg / Mirror (push) Failing after 0s
Deploy Docs to GitHub Pages / Deploy (push) Has been skipped
Nix Build / check (push) Failing after 5s
Some checks failed
CodeQL Scan / Analyze (javascript-typescript) (push) Failing after 53s
Build Docker Images / lint (push) Failing after 10s
Build Docker Images / check (push) Failing after 10s
Build Docker Images / tests (push) Failing after 6s
Build Docker Images / build (server, Dockerfile, ${{ github.repository_owner }}/server) (push) Has been skipped
Build Docker Images / build (worker, Worker.Dockerfile, ${{ github.repository_owner }}/worker) (push) Has been skipped
Deploy Docs to GitHub Pages / build (push) Failing after 5s
Mirror to Codeberg / Mirror (push) Failing after 0s
Deploy Docs to GitHub Pages / Deploy (push) Has been skipped
Nix Build / check (push) Failing after 5s
This commit is contained in:
parent
65e2e19ff1
commit
c674a1309c
12
app.ts
12
app.ts
|
|
@ -3,10 +3,10 @@ import { handleZodError } from "@/api";
|
|||
import { applyToHono } from "@/bull-board.ts";
|
||||
import { configureLoggers } from "@/loggers";
|
||||
import { sentry } from "@/sentry";
|
||||
import { swaggerUI } from "@hono/swagger-ui";
|
||||
import { OpenAPIHono } from "@hono/zod-openapi";
|
||||
/* import { prometheus } from "@hono/prometheus"; */
|
||||
import { getLogger } from "@logtape/logtape";
|
||||
import { apiReference } from "@scalar/hono-api-reference";
|
||||
import { inspect } from "bun";
|
||||
import chalk from "chalk";
|
||||
import { cors } from "hono/cors";
|
||||
|
|
@ -148,7 +148,15 @@ export const appFactory = async (): Promise<OpenAPIHono<HonoEnv>> => {
|
|||
contact: pkg.author,
|
||||
},
|
||||
});
|
||||
app.get("/docs", swaggerUI({ url: "/openapi.json" }));
|
||||
app.get(
|
||||
"/docs",
|
||||
apiReference({
|
||||
theme: "deepSpace",
|
||||
hideClientButton: true,
|
||||
pageTitle: "Versia Server API",
|
||||
url: "/openapi.json",
|
||||
}),
|
||||
);
|
||||
applyToHono(app);
|
||||
|
||||
app.options("*", (context) => {
|
||||
|
|
|
|||
16
bun.lock
16
bun.lock
|
|
@ -13,12 +13,12 @@
|
|||
"@clerc/plugin-version": "^0.44.0",
|
||||
"@hackmd/markdown-it-task-lists": "^2.1.4",
|
||||
"@hono/prometheus": "^1.0.1",
|
||||
"@hono/swagger-ui": "^0.5.1",
|
||||
"@hono/zod-openapi": "0.19.2",
|
||||
"@hono/zod-validator": "^0.4.3",
|
||||
"@inquirer/confirm": "^5.1.8",
|
||||
"@logtape/file": "^0.9.0",
|
||||
"@logtape/logtape": "^0.9.0",
|
||||
"@scalar/hono-api-reference": "^0.7.2",
|
||||
"@sentry/bun": "^9.8.0",
|
||||
"@versia/client": "workspace:*",
|
||||
"@versia/federation": "^0.2.1",
|
||||
|
|
@ -271,8 +271,6 @@
|
|||
|
||||
"@hono/prometheus": ["@hono/prometheus@1.0.1", "", { "peerDependencies": { "hono": ">=3.*", "prom-client": "^15.0.0" } }, "sha512-PjMbjAppCgbvRP2aLxqJc1XJLxfmg4dLsS5R5ITt7qCf9Ab/xSRul/LHNVvYK2/ECi3BOPprSnlSizksBJmXBQ=="],
|
||||
|
||||
"@hono/swagger-ui": ["@hono/swagger-ui@0.5.1", "", { "peerDependencies": { "hono": "*" } }, "sha512-XpUCfszLJ9b1rtFdzqOSHfdg9pfBiC2J5piEjuSanYpDDTIwpMz0ciiv5N3WWUaQpz9fEgH8lttQqL41vIFuDA=="],
|
||||
|
||||
"@hono/zod-openapi": ["@hono/zod-openapi@0.19.2", "", { "dependencies": { "@asteasolutions/zod-to-openapi": "^7.1.0", "@hono/zod-validator": "^0.4.1" }, "peerDependencies": { "hono": ">=4.3.6", "zod": "3.*" } }, "sha512-lkFa6wdQVgY7d7/m++Ixr3hvKCF5Y+zjTIPM37fex5ylCfX53A/W28gZRDuFZx3aR+noKob7lHfwdk9dURLzxw=="],
|
||||
|
||||
"@hono/zod-validator": ["@hono/zod-validator@0.4.3", "", { "peerDependencies": { "hono": ">=3.9.0", "zod": "^3.19.1" } }, "sha512-xIgMYXDyJ4Hj6ekm9T9Y27s080Nl9NXHcJkOvkXPhubOLj8hZkOL8pDnnXfvCf5xEE8Q4oMFenQUZZREUY2gqQ=="],
|
||||
|
|
@ -465,6 +463,14 @@
|
|||
|
||||
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.36.0", "", { "os": "win32", "cpu": "x64" }, "sha512-aRXd7tRZkWLqGbChgcMMDEHjOKudo1kChb1Jt1IfR8cY/KIpgNviLeJy5FUb9IpSuQj8dU2fAYNMPW/hLKOSTw=="],
|
||||
|
||||
"@scalar/core": ["@scalar/core@0.2.2", "", { "dependencies": { "@scalar/types": "0.1.2" } }, "sha512-jT6vfz37yQnqVjj8kXYEmV2cZvODW1A0PXjxZ9DzKqjm9tIssNwP4vvcdD1FSuiMcj+rgxAxOjIYMI+ybI/9RQ=="],
|
||||
|
||||
"@scalar/hono-api-reference": ["@scalar/hono-api-reference@0.7.2", "", { "dependencies": { "@scalar/core": "0.2.2" }, "peerDependencies": { "hono": "^4.0.0" } }, "sha512-CnxRjGfAWPGkV0D5TEwogvn7JSx/f9+ag6vQ6g25GigSDyj/UkxYbZqwe/QOV/+2EWruY3ypOvPuNMf7nEQhdQ=="],
|
||||
|
||||
"@scalar/openapi-types": ["@scalar/openapi-types@0.1.9", "", {}, "sha512-HQQudOSQBU7ewzfnBW9LhDmBE2XOJgSfwrh5PlUB7zJup/kaRkBGNgV2wMjNz9Af/uztiU/xNrO179FysmUT+g=="],
|
||||
|
||||
"@scalar/types": ["@scalar/types@0.1.2", "", { "dependencies": { "@scalar/openapi-types": "0.1.9", "@unhead/schema": "^1.11.11", "zod": "^3.23.8" } }, "sha512-5kCLQRwAYWt1ds110EaUb9yonc3KoQYNyo4YUCigJLOnoNugbqkEX0zRudGevItiuk+xg4uOYd30r3C+6xAasA=="],
|
||||
|
||||
"@selderee/plugin-htmlparser2": ["@selderee/plugin-htmlparser2@0.11.0", "", { "dependencies": { "domhandler": "^5.0.3", "selderee": "^0.11.0" } }, "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ=="],
|
||||
|
||||
"@sentry/bun": ["@sentry/bun@9.8.0", "", { "dependencies": { "@sentry/core": "9.8.0", "@sentry/node": "9.8.0", "@sentry/opentelemetry": "9.8.0" } }, "sha512-3JSaxyEomfZYLp1mwvwugj308QeZ4fYRzjAOQcWZqHFKbr6pMFKTvZKfEKIoAEXsNfka33+VpPdltlMgGe9auw=="],
|
||||
|
|
@ -543,6 +549,8 @@
|
|||
|
||||
"@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="],
|
||||
|
||||
"@unhead/schema": ["@unhead/schema@1.11.20", "", { "dependencies": { "hookable": "^5.5.3", "zhead": "^2.2.4" } }, "sha512-0zWykKAaJdm+/Y7yi/Yds20PrUK7XabLe9c3IRcjnwYmSWY6z0Cr19VIs3ozCj8P+GhR+/TI2mwtGlueCEYouA=="],
|
||||
|
||||
"@versia/client": ["@versia/client@workspace:packages/client"],
|
||||
|
||||
"@versia/federation": ["@versia/federation@0.2.1", "", { "dependencies": { "magic-regexp": "^0.8.0", "mime-types": "^2.1.35", "zod": "^3.24.1", "zod-validation-error": "^3.4.0" } }, "sha512-FTo3VGNJBGmCi0ZEQMzqFZBbcfbX81kmg0UgY4cKamr1dJWgEf72IAZnEDgrBffFjYtreLGdEjFkkcq3JfS8oQ=="],
|
||||
|
|
@ -1339,6 +1347,8 @@
|
|||
|
||||
"yoctocolors-cjs": ["yoctocolors-cjs@2.1.2", "", {}, "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA=="],
|
||||
|
||||
"zhead": ["zhead@2.2.4", "", {}, "sha512-8F0OI5dpWIA5IGG5NHUg9staDwz/ZPxZtvGVf01j7vHqSyZ0raHY+78atOVxRqb73AotX22uV1pXt3gYSstGag=="],
|
||||
|
||||
"zod": ["zod@3.24.2", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="],
|
||||
|
||||
"zod-to-json-schema": ["zod-to-json-schema@3.24.5", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g=="],
|
||||
|
|
|
|||
|
|
@ -85,12 +85,12 @@
|
|||
"@clerc/plugin-version": "^0.44.0",
|
||||
"@hackmd/markdown-it-task-lists": "^2.1.4",
|
||||
"@hono/prometheus": "^1.0.1",
|
||||
"@hono/swagger-ui": "^0.5.1",
|
||||
"@hono/zod-openapi": "0.19.2",
|
||||
"@hono/zod-validator": "^0.4.3",
|
||||
"@inquirer/confirm": "^5.1.8",
|
||||
"@logtape/file": "^0.9.0",
|
||||
"@logtape/logtape": "^0.9.0",
|
||||
"@scalar/hono-api-reference": "^0.7.2",
|
||||
"@sentry/bun": "^9.8.0",
|
||||
"@versia/client": "workspace:*",
|
||||
"@versia/federation": "^0.2.1",
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ export const AccountWarning = z
|
|||
example: "2025-01-04T14:11:00Z",
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("AccountWarning", {
|
||||
description: "Moderation warning against a particular account.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/AccountWarning",
|
||||
|
|
|
|||
|
|
@ -5,44 +5,46 @@ import { iso631, zBoolean } from "./common.ts";
|
|||
import { CustomEmoji } from "./emoji.ts";
|
||||
import { Role } from "./versia.ts";
|
||||
|
||||
export const Field = z.object({
|
||||
name: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1)
|
||||
.max(config.validation.accounts.max_field_name_characters)
|
||||
.openapi({
|
||||
description: "The key of a given field’s key-value pair.",
|
||||
example: "Freak level",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#name",
|
||||
},
|
||||
}),
|
||||
value: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1)
|
||||
.max(config.validation.accounts.max_field_value_characters)
|
||||
.openapi({
|
||||
description: "The value associated with the name key.",
|
||||
example: "<p>High</p>",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#value",
|
||||
},
|
||||
}),
|
||||
verified_at: z
|
||||
.string()
|
||||
.datetime()
|
||||
.nullable()
|
||||
.openapi({
|
||||
description:
|
||||
"Timestamp of when the server verified a URL value for a rel=“me” link.",
|
||||
example: null,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#verified_at",
|
||||
},
|
||||
}),
|
||||
});
|
||||
export const Field = z
|
||||
.object({
|
||||
name: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1)
|
||||
.max(config.validation.accounts.max_field_name_characters)
|
||||
.openapi({
|
||||
description: "The key of a given field’s key-value pair.",
|
||||
example: "Freak level",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#name",
|
||||
},
|
||||
}),
|
||||
value: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1)
|
||||
.max(config.validation.accounts.max_field_value_characters)
|
||||
.openapi({
|
||||
description: "The value associated with the name key.",
|
||||
example: "<p>High</p>",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#value",
|
||||
},
|
||||
}),
|
||||
verified_at: z
|
||||
.string()
|
||||
.datetime()
|
||||
.nullable()
|
||||
.openapi({
|
||||
description:
|
||||
"Timestamp of when the server verified a URL value for a rel=“me” link.",
|
||||
example: null,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#verified_at",
|
||||
},
|
||||
}),
|
||||
})
|
||||
.openapi("AccountField");
|
||||
|
||||
export const Source = z
|
||||
.object({
|
||||
|
|
@ -107,7 +109,7 @@ export const Source = z
|
|||
description: "Metadata about the account.",
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("AccountSource", {
|
||||
description:
|
||||
"An extra attribute that contains source values to be used with API methods that verify credentials and update credentials.",
|
||||
externalDocs: {
|
||||
|
|
@ -116,304 +118,310 @@ export const Source = z
|
|||
});
|
||||
|
||||
// Because Account has some recursive references, we need to define it like this
|
||||
const BaseAccount = z.object({
|
||||
id: z
|
||||
.string()
|
||||
.uuid()
|
||||
.openapi({
|
||||
description: "The account ID in the database.",
|
||||
example: "9e84842b-4db6-4a9b-969d-46ab408278da",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#id",
|
||||
},
|
||||
}),
|
||||
username: z
|
||||
.string()
|
||||
.min(3)
|
||||
.trim()
|
||||
.max(config.validation.accounts.max_username_characters)
|
||||
.regex(
|
||||
/^[a-z0-9_-]+$/,
|
||||
"Username can only contain letters, numbers, underscores and hyphens",
|
||||
)
|
||||
.refine(
|
||||
(s) =>
|
||||
!config.validation.filters.username.some((filter) =>
|
||||
filter.test(s),
|
||||
),
|
||||
"Username contains blocked words",
|
||||
)
|
||||
.refine(
|
||||
(s) =>
|
||||
!config.validation.accounts.disallowed_usernames.some((u) =>
|
||||
u.test(s),
|
||||
),
|
||||
"Username is disallowed",
|
||||
)
|
||||
.openapi({
|
||||
description: "The username of the account, not including domain.",
|
||||
example: "lexi",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#username",
|
||||
},
|
||||
}),
|
||||
acct: z
|
||||
.string()
|
||||
.min(1)
|
||||
.trim()
|
||||
.regex(userAddressValidator, "Invalid user address")
|
||||
.openapi({
|
||||
const BaseAccount = z
|
||||
.object({
|
||||
id: z
|
||||
.string()
|
||||
.uuid()
|
||||
.openapi({
|
||||
description: "The account ID in the database.",
|
||||
example: "9e84842b-4db6-4a9b-969d-46ab408278da",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#id",
|
||||
},
|
||||
}),
|
||||
username: z
|
||||
.string()
|
||||
.min(3)
|
||||
.trim()
|
||||
.max(config.validation.accounts.max_username_characters)
|
||||
.regex(
|
||||
/^[a-z0-9_-]+$/,
|
||||
"Username can only contain letters, numbers, underscores and hyphens",
|
||||
)
|
||||
.refine(
|
||||
(s) =>
|
||||
!config.validation.filters.username.some((filter) =>
|
||||
filter.test(s),
|
||||
),
|
||||
"Username contains blocked words",
|
||||
)
|
||||
.refine(
|
||||
(s) =>
|
||||
!config.validation.accounts.disallowed_usernames.some((u) =>
|
||||
u.test(s),
|
||||
),
|
||||
"Username is disallowed",
|
||||
)
|
||||
.openapi({
|
||||
description:
|
||||
"The username of the account, not including domain.",
|
||||
example: "lexi",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#username",
|
||||
},
|
||||
}),
|
||||
acct: z
|
||||
.string()
|
||||
.min(1)
|
||||
.trim()
|
||||
.regex(userAddressValidator, "Invalid user address")
|
||||
.openapi({
|
||||
description:
|
||||
"The Webfinger account URI. Equal to username for local users, or username@domain for remote users.",
|
||||
example: "lexi@beta.versia.social",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#acct",
|
||||
},
|
||||
}),
|
||||
url: z
|
||||
.string()
|
||||
.url()
|
||||
.openapi({
|
||||
description: "The location of the user’s profile page.",
|
||||
example: "https://beta.versia.social/@lexi",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#url",
|
||||
},
|
||||
}),
|
||||
display_name: z
|
||||
.string()
|
||||
.min(3)
|
||||
.trim()
|
||||
.max(config.validation.accounts.max_displayname_characters)
|
||||
.refine(
|
||||
(s) =>
|
||||
!config.validation.filters.displayname.some((filter) =>
|
||||
filter.test(s),
|
||||
),
|
||||
"Display name contains blocked words",
|
||||
)
|
||||
.openapi({
|
||||
description: "The profile’s display name.",
|
||||
example: "Lexi :flower:",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#display_name",
|
||||
},
|
||||
}),
|
||||
note: z
|
||||
.string()
|
||||
.min(0)
|
||||
.max(config.validation.accounts.max_bio_characters)
|
||||
.trim()
|
||||
.refine(
|
||||
(s) =>
|
||||
!config.validation.filters.bio.some((filter) =>
|
||||
filter.test(s),
|
||||
),
|
||||
"Bio contains blocked words",
|
||||
)
|
||||
.openapi({
|
||||
description: "The profile’s bio or description.",
|
||||
example: "<p>ermmm what the meow meow</p>",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#note",
|
||||
},
|
||||
}),
|
||||
avatar: z
|
||||
.string()
|
||||
.url()
|
||||
.openapi({
|
||||
description:
|
||||
"An image icon that is shown next to statuses and in the profile.",
|
||||
example:
|
||||
"https://cdn.versia.social/avatars/cff9aea0-0000-43fe-8b5e-e7c7ea69a488/lexi.webp",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#avatar",
|
||||
},
|
||||
}),
|
||||
avatar_static: z
|
||||
.string()
|
||||
.url()
|
||||
.openapi({
|
||||
description:
|
||||
"A static version of the avatar. Equal to avatar if its value is a static image; different if avatar is an animated GIF.",
|
||||
example:
|
||||
"https://cdn.versia.social/avatars/cff9aea0-0000-43fe-8b5e-e7c7ea69a488/lexi.webp",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#avatar_static",
|
||||
},
|
||||
}),
|
||||
header: z
|
||||
.string()
|
||||
.url()
|
||||
.openapi({
|
||||
description:
|
||||
"An image banner that is shown above the profile and in profile cards.",
|
||||
example:
|
||||
"https://cdn.versia.social/headers/a049f8e3-878c-4faa-ae4c-a6bcceddbd9d/femboy_2.webp",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#header",
|
||||
},
|
||||
}),
|
||||
header_static: z
|
||||
.string()
|
||||
.url()
|
||||
.openapi({
|
||||
description:
|
||||
"A static version of the header. Equal to header if its value is a static image; different if header is an animated GIF.",
|
||||
example:
|
||||
"https://cdn.versia.social/headers/a049f8e3-878c-4faa-ae4c-a6bcceddbd9d/femboy_2.webp",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#header_static",
|
||||
},
|
||||
}),
|
||||
locked: zBoolean.openapi({
|
||||
description:
|
||||
"The Webfinger account URI. Equal to username for local users, or username@domain for remote users.",
|
||||
example: "lexi@beta.versia.social",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#acct",
|
||||
},
|
||||
}),
|
||||
url: z
|
||||
.string()
|
||||
.url()
|
||||
.openapi({
|
||||
description: "The location of the user’s profile page.",
|
||||
example: "https://beta.versia.social/@lexi",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#url",
|
||||
},
|
||||
}),
|
||||
display_name: z
|
||||
.string()
|
||||
.min(3)
|
||||
.trim()
|
||||
.max(config.validation.accounts.max_displayname_characters)
|
||||
.refine(
|
||||
(s) =>
|
||||
!config.validation.filters.displayname.some((filter) =>
|
||||
filter.test(s),
|
||||
),
|
||||
"Display name contains blocked words",
|
||||
)
|
||||
.openapi({
|
||||
description: "The profile’s display name.",
|
||||
example: "Lexi :flower:",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#display_name",
|
||||
},
|
||||
}),
|
||||
note: z
|
||||
.string()
|
||||
.min(0)
|
||||
.max(config.validation.accounts.max_bio_characters)
|
||||
.trim()
|
||||
.refine(
|
||||
(s) =>
|
||||
!config.validation.filters.bio.some((filter) => filter.test(s)),
|
||||
"Bio contains blocked words",
|
||||
)
|
||||
.openapi({
|
||||
description: "The profile’s bio or description.",
|
||||
example: "<p>ermmm what the meow meow</p>",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#note",
|
||||
},
|
||||
}),
|
||||
avatar: z
|
||||
.string()
|
||||
.url()
|
||||
.openapi({
|
||||
description:
|
||||
"An image icon that is shown next to statuses and in the profile.",
|
||||
example:
|
||||
"https://cdn.versia.social/avatars/cff9aea0-0000-43fe-8b5e-e7c7ea69a488/lexi.webp",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#avatar",
|
||||
},
|
||||
}),
|
||||
avatar_static: z
|
||||
.string()
|
||||
.url()
|
||||
.openapi({
|
||||
description:
|
||||
"A static version of the avatar. Equal to avatar if its value is a static image; different if avatar is an animated GIF.",
|
||||
example:
|
||||
"https://cdn.versia.social/avatars/cff9aea0-0000-43fe-8b5e-e7c7ea69a488/lexi.webp",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#avatar_static",
|
||||
},
|
||||
}),
|
||||
header: z
|
||||
.string()
|
||||
.url()
|
||||
.openapi({
|
||||
description:
|
||||
"An image banner that is shown above the profile and in profile cards.",
|
||||
example:
|
||||
"https://cdn.versia.social/headers/a049f8e3-878c-4faa-ae4c-a6bcceddbd9d/femboy_2.webp",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#header",
|
||||
},
|
||||
}),
|
||||
header_static: z
|
||||
.string()
|
||||
.url()
|
||||
.openapi({
|
||||
description:
|
||||
"A static version of the header. Equal to header if its value is a static image; different if header is an animated GIF.",
|
||||
example:
|
||||
"https://cdn.versia.social/headers/a049f8e3-878c-4faa-ae4c-a6bcceddbd9d/femboy_2.webp",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#header_static",
|
||||
},
|
||||
}),
|
||||
locked: zBoolean.openapi({
|
||||
description: "Whether the account manually approves follow requests.",
|
||||
example: false,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#locked",
|
||||
},
|
||||
}),
|
||||
fields: z
|
||||
.array(Field)
|
||||
.max(config.validation.accounts.max_field_count)
|
||||
.openapi({
|
||||
description:
|
||||
"Additional metadata attached to a profile as name-value pairs.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#fields",
|
||||
},
|
||||
}),
|
||||
emojis: z.array(CustomEmoji).openapi({
|
||||
description:
|
||||
"Custom emoji entities to be used when rendering the profile.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#emojis",
|
||||
},
|
||||
}),
|
||||
bot: zBoolean.openapi({
|
||||
description:
|
||||
"Indicates that the account may perform automated actions, may not be monitored, or identifies as a robot.",
|
||||
example: false,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#bot",
|
||||
},
|
||||
}),
|
||||
group: z.literal(false).openapi({
|
||||
description: "Indicates that the account represents a Group actor.",
|
||||
example: false,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#group",
|
||||
},
|
||||
}),
|
||||
discoverable: zBoolean.nullable().openapi({
|
||||
description:
|
||||
"Whether the account has opted into discovery features such as the profile directory.",
|
||||
example: true,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#discoverable",
|
||||
},
|
||||
}),
|
||||
noindex: zBoolean
|
||||
.nullable()
|
||||
.optional()
|
||||
.openapi({
|
||||
description:
|
||||
"Whether the local user has opted out of being indexed by search engines.",
|
||||
"Whether the account manually approves follow requests.",
|
||||
example: false,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#noindex",
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#locked",
|
||||
},
|
||||
}),
|
||||
suspended: zBoolean.optional().openapi({
|
||||
description:
|
||||
"An extra attribute returned only when an account is suspended.",
|
||||
example: false,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#suspended",
|
||||
},
|
||||
}),
|
||||
limited: zBoolean.optional().openapi({
|
||||
description:
|
||||
"An extra attribute returned only when an account is silenced. If true, indicates that the account should be hidden behind a warning screen.",
|
||||
example: false,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#limited",
|
||||
},
|
||||
}),
|
||||
created_at: z
|
||||
.string()
|
||||
.datetime()
|
||||
.openapi({
|
||||
description: "When the account was created.",
|
||||
example: "2024-10-15T22:00:00.000Z",
|
||||
fields: z
|
||||
.array(Field)
|
||||
.max(config.validation.accounts.max_field_count)
|
||||
.openapi({
|
||||
description:
|
||||
"Additional metadata attached to a profile as name-value pairs.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#fields",
|
||||
},
|
||||
}),
|
||||
emojis: z.array(CustomEmoji).openapi({
|
||||
description:
|
||||
"Custom emoji entities to be used when rendering the profile.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#created_at",
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#emojis",
|
||||
},
|
||||
}),
|
||||
// TODO
|
||||
last_status_at: z
|
||||
.literal(null)
|
||||
.openapi({
|
||||
description: "When the most recent status was posted.",
|
||||
example: null,
|
||||
bot: zBoolean.openapi({
|
||||
description:
|
||||
"Indicates that the account may perform automated actions, may not be monitored, or identifies as a robot.",
|
||||
example: false,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#last_status_at",
|
||||
},
|
||||
})
|
||||
.nullable(),
|
||||
statuses_count: z
|
||||
.number()
|
||||
.int()
|
||||
.nonnegative()
|
||||
.openapi({
|
||||
description: "How many statuses are attached to this account.",
|
||||
example: 42,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#statuses_count",
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#bot",
|
||||
},
|
||||
}),
|
||||
followers_count: z
|
||||
.number()
|
||||
.int()
|
||||
.nonnegative()
|
||||
.openapi({
|
||||
description: "The reported followers of this profile.",
|
||||
example: 6,
|
||||
group: z.literal(false).openapi({
|
||||
description: "Indicates that the account represents a Group actor.",
|
||||
example: false,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#followers_count",
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#group",
|
||||
},
|
||||
}),
|
||||
following_count: z
|
||||
.number()
|
||||
.int()
|
||||
.nonnegative()
|
||||
.openapi({
|
||||
description: "The reported follows of this profile.",
|
||||
example: 23,
|
||||
discoverable: zBoolean.nullable().openapi({
|
||||
description:
|
||||
"Whether the account has opted into discovery features such as the profile directory.",
|
||||
example: true,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#following_count",
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#discoverable",
|
||||
},
|
||||
}),
|
||||
/* Versia Server API extension */
|
||||
uri: z.string().url().openapi({
|
||||
description:
|
||||
"The location of the user's Versia profile page, as opposed to the local representation.",
|
||||
example:
|
||||
"https://beta.versia.social/users/9e84842b-4db6-4a9b-969d-46ab408278da",
|
||||
}),
|
||||
source: Source.optional(),
|
||||
role: z
|
||||
.object({
|
||||
name: z.string(),
|
||||
})
|
||||
.optional(),
|
||||
/* Versia Server API extension */
|
||||
roles: z.array(Role).openapi({
|
||||
description: "Roles assigned to the account.",
|
||||
}),
|
||||
mute_expires_at: z.string().datetime().nullable().openapi({
|
||||
description: "When a timed mute will expire, if applicable.",
|
||||
example: "2025-03-01T14:00:00.000Z",
|
||||
}),
|
||||
});
|
||||
noindex: zBoolean
|
||||
.nullable()
|
||||
.optional()
|
||||
.openapi({
|
||||
description:
|
||||
"Whether the local user has opted out of being indexed by search engines.",
|
||||
example: false,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#noindex",
|
||||
},
|
||||
}),
|
||||
suspended: zBoolean.optional().openapi({
|
||||
description:
|
||||
"An extra attribute returned only when an account is suspended.",
|
||||
example: false,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#suspended",
|
||||
},
|
||||
}),
|
||||
limited: zBoolean.optional().openapi({
|
||||
description:
|
||||
"An extra attribute returned only when an account is silenced. If true, indicates that the account should be hidden behind a warning screen.",
|
||||
example: false,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#limited",
|
||||
},
|
||||
}),
|
||||
created_at: z
|
||||
.string()
|
||||
.datetime()
|
||||
.openapi({
|
||||
description: "When the account was created.",
|
||||
example: "2024-10-15T22:00:00.000Z",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#created_at",
|
||||
},
|
||||
}),
|
||||
// TODO
|
||||
last_status_at: z
|
||||
.literal(null)
|
||||
.openapi({
|
||||
description: "When the most recent status was posted.",
|
||||
example: null,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#last_status_at",
|
||||
},
|
||||
})
|
||||
.nullable(),
|
||||
statuses_count: z
|
||||
.number()
|
||||
.int()
|
||||
.nonnegative()
|
||||
.openapi({
|
||||
description: "How many statuses are attached to this account.",
|
||||
example: 42,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#statuses_count",
|
||||
},
|
||||
}),
|
||||
followers_count: z
|
||||
.number()
|
||||
.int()
|
||||
.nonnegative()
|
||||
.openapi({
|
||||
description: "The reported followers of this profile.",
|
||||
example: 6,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#followers_count",
|
||||
},
|
||||
}),
|
||||
following_count: z
|
||||
.number()
|
||||
.int()
|
||||
.nonnegative()
|
||||
.openapi({
|
||||
description: "The reported follows of this profile.",
|
||||
example: 23,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Account/#following_count",
|
||||
},
|
||||
}),
|
||||
/* Versia Server API extension */
|
||||
uri: z.string().url().openapi({
|
||||
description:
|
||||
"The location of the user's Versia profile page, as opposed to the local representation.",
|
||||
example:
|
||||
"https://beta.versia.social/users/9e84842b-4db6-4a9b-969d-46ab408278da",
|
||||
}),
|
||||
source: Source.optional(),
|
||||
role: z
|
||||
.object({
|
||||
name: z.string(),
|
||||
})
|
||||
.optional(),
|
||||
/* Versia Server API extension */
|
||||
roles: z.array(Role).openapi({
|
||||
description: "Roles assigned to the account.",
|
||||
}),
|
||||
mute_expires_at: z.string().datetime().nullable().openapi({
|
||||
description: "When a timed mute will expire, if applicable.",
|
||||
example: "2025-03-01T14:00:00.000Z",
|
||||
}),
|
||||
})
|
||||
.openapi("BaseAccount");
|
||||
|
||||
export const Account = BaseAccount.extend({
|
||||
moved: BaseAccount.nullable()
|
||||
|
|
@ -426,4 +434,4 @@ export const Account = BaseAccount.extend({
|
|||
url: "https://docs.joinmastodon.org/entities/Account/#moved",
|
||||
},
|
||||
}),
|
||||
});
|
||||
}).openapi("Account");
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ export const Appeal = z
|
|||
example: "pending",
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("Appeal", {
|
||||
description: "Appeal against a moderation action.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Appeal",
|
||||
|
|
|
|||
|
|
@ -1,65 +1,67 @@
|
|||
import { z } from "@hono/zod-openapi";
|
||||
|
||||
export const Application = z.object({
|
||||
name: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1)
|
||||
.max(200)
|
||||
.openapi({
|
||||
description: "The name of your application.",
|
||||
example: "Test Application",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Application/#name",
|
||||
},
|
||||
}),
|
||||
website: z
|
||||
.string()
|
||||
.nullable()
|
||||
.openapi({
|
||||
description: "The website associated with your application.",
|
||||
example: "https://app.example",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Application/#website",
|
||||
},
|
||||
}),
|
||||
scopes: z
|
||||
.array(z.string())
|
||||
.default(["read"])
|
||||
.openapi({
|
||||
export const Application = z
|
||||
.object({
|
||||
name: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1)
|
||||
.max(200)
|
||||
.openapi({
|
||||
description: "The name of your application.",
|
||||
example: "Test Application",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Application/#name",
|
||||
},
|
||||
}),
|
||||
website: z
|
||||
.string()
|
||||
.nullable()
|
||||
.openapi({
|
||||
description: "The website associated with your application.",
|
||||
example: "https://app.example",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Application/#website",
|
||||
},
|
||||
}),
|
||||
scopes: z
|
||||
.array(z.string())
|
||||
.default(["read"])
|
||||
.openapi({
|
||||
description:
|
||||
"The scopes for your application. This is the registered scopes string split on whitespace.",
|
||||
example: ["read", "write", "push"],
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Application/#scopes",
|
||||
},
|
||||
}),
|
||||
redirect_uris: z
|
||||
.array(
|
||||
z
|
||||
.string()
|
||||
.url()
|
||||
.or(z.literal("urn:ietf:wg:oauth:2.0:oob"))
|
||||
.openapi({
|
||||
description: "URL or 'urn:ietf:wg:oauth:2.0:oob'",
|
||||
}),
|
||||
)
|
||||
.openapi({
|
||||
description:
|
||||
"The registered redirection URI(s) for your application.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Application/#redirect_uris",
|
||||
},
|
||||
}),
|
||||
redirect_uri: z.string().openapi({
|
||||
deprecated: true,
|
||||
description:
|
||||
"The scopes for your application. This is the registered scopes string split on whitespace.",
|
||||
example: ["read", "write", "push"],
|
||||
"The registered redirection URI(s) for your application. May contain \\n characters when multiple redirect URIs are registered.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Application/#scopes",
|
||||
url: "https://docs.joinmastodon.org/entities/Application/#redirect_uri",
|
||||
},
|
||||
}),
|
||||
redirect_uris: z
|
||||
.array(
|
||||
z
|
||||
.string()
|
||||
.url()
|
||||
.or(z.literal("urn:ietf:wg:oauth:2.0:oob"))
|
||||
.openapi({
|
||||
description: "URL or 'urn:ietf:wg:oauth:2.0:oob'",
|
||||
}),
|
||||
)
|
||||
.openapi({
|
||||
description:
|
||||
"The registered redirection URI(s) for your application.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Application/#redirect_uris",
|
||||
},
|
||||
}),
|
||||
redirect_uri: z.string().openapi({
|
||||
deprecated: true,
|
||||
description:
|
||||
"The registered redirection URI(s) for your application. May contain \\n characters when multiple redirect URIs are registered.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Application/#redirect_uri",
|
||||
},
|
||||
}),
|
||||
});
|
||||
})
|
||||
.openapi("Application");
|
||||
|
||||
export const CredentialApplication = Application.extend({
|
||||
client_id: z.string().openapi({
|
||||
|
|
@ -81,4 +83,4 @@ export const CredentialApplication = Application.extend({
|
|||
url: "https://docs.joinmastodon.org/entities/CredentialApplication/#client_secret_expires_at",
|
||||
},
|
||||
}),
|
||||
});
|
||||
}).openapi("CredentialApplication");
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ export const Attachment = z
|
|||
example: "UFBWY:8_0Jxv4mx]t8t64.%M-:IUWGWAt6M}",
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("Attachment", {
|
||||
description:
|
||||
"Represents a file or media attachment that can be added to a status.",
|
||||
externalDocs: {
|
||||
|
|
|
|||
|
|
@ -1,31 +1,33 @@
|
|||
import { z } from "@hono/zod-openapi";
|
||||
import { Account } from "./account.ts";
|
||||
|
||||
export const PreviewCardAuthor = z.object({
|
||||
name: z.string().openapi({
|
||||
description: "The original resource author’s name.",
|
||||
example: "The Doubleclicks",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/PreviewCardAuthor/#name",
|
||||
},
|
||||
}),
|
||||
url: z
|
||||
.string()
|
||||
.url()
|
||||
.openapi({
|
||||
description: "A link to the author of the original resource.",
|
||||
example: "https://www.youtube.com/user/thedoubleclicks",
|
||||
export const PreviewCardAuthor = z
|
||||
.object({
|
||||
name: z.string().openapi({
|
||||
description: "The original resource author’s name.",
|
||||
example: "The Doubleclicks",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/PreviewCardAuthor/#url",
|
||||
url: "https://docs.joinmastodon.org/entities/PreviewCardAuthor/#name",
|
||||
},
|
||||
}),
|
||||
account: Account.nullable().openapi({
|
||||
description: "The fediverse account of the author.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/PreviewCardAuthor/#account",
|
||||
},
|
||||
}),
|
||||
});
|
||||
url: z
|
||||
.string()
|
||||
.url()
|
||||
.openapi({
|
||||
description: "A link to the author of the original resource.",
|
||||
example: "https://www.youtube.com/user/thedoubleclicks",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/PreviewCardAuthor/#url",
|
||||
},
|
||||
}),
|
||||
account: Account.nullable().openapi({
|
||||
description: "The fediverse account of the author.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/PreviewCardAuthor/#account",
|
||||
},
|
||||
}),
|
||||
})
|
||||
.openapi("PreviewCardAuthor");
|
||||
|
||||
export const PreviewCard = z
|
||||
.object({
|
||||
|
|
@ -150,7 +152,7 @@ export const PreviewCard = z
|
|||
},
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("PreviewCard", {
|
||||
description:
|
||||
"Represents a rich preview card that is generated using OpenGraph tags from a URL.",
|
||||
externalDocs: {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ import ISO6391 from "iso-639-1";
|
|||
|
||||
export const Id = z.string().uuid();
|
||||
|
||||
export const iso631 = z.enum(ISO6391.getAllCodes() as [string, ...string[]]);
|
||||
export const iso631 = z
|
||||
.enum(ISO6391.getAllCodes() as [string, ...string[]])
|
||||
.openapi("ISO631");
|
||||
|
||||
export const zBoolean = z
|
||||
.string()
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ export const Context = z
|
|||
},
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("Context", {
|
||||
description:
|
||||
"Represents the tree around a given status. Used for reconstructing threads of statuses.",
|
||||
externalDocs: {
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ export const CustomEmoji = z
|
|||
},
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("CustomEmoji", {
|
||||
description: "Represents a custom emoji.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/CustomEmoji",
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ export const ExtendedDescription = z
|
|||
},
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("ExtendedDescription", {
|
||||
description:
|
||||
"Represents an extended description for the instance, to be shown on its about page.",
|
||||
externalDocs: {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ export const FamiliarFollowers = z
|
|||
},
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("FamiliarFollowers", {
|
||||
description:
|
||||
"Represents a subset of your follows who also follow some other user.",
|
||||
externalDocs: {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export const FilterStatus = z
|
|||
},
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("FilterStatus", {
|
||||
description:
|
||||
"Represents a status ID that, if matched, should cause the filter action to be taken.",
|
||||
externalDocs: {
|
||||
|
|
@ -51,7 +51,7 @@ export const FilterKeyword = z
|
|||
},
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("FilterKeyword", {
|
||||
description:
|
||||
"Represents a keyword that, if matched, should cause the filter action to be taken.",
|
||||
externalDocs: {
|
||||
|
|
@ -133,7 +133,7 @@ export const Filter = z
|
|||
},
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("Filter", {
|
||||
description:
|
||||
"Represents a user-defined filter for determining which statuses should not be shown to the user.",
|
||||
externalDocs: {
|
||||
|
|
@ -171,7 +171,7 @@ export const FilterResult = z
|
|||
},
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("FilterResult", {
|
||||
description:
|
||||
"Represents a filter whose keywords matched a given status.",
|
||||
externalDocs: {
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ export const InstanceV1 = z
|
|||
/* Versia Server API extension */
|
||||
sso: SSOConfig,
|
||||
})
|
||||
.openapi({
|
||||
.openapi("InstanceV1", {
|
||||
description:
|
||||
"Represents the software instance of Versia Server running on this domain.",
|
||||
externalDocs: {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ const InstanceIcon = z
|
|||
example: "36x36",
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("InstanceIcon", {
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/InstanceIcon",
|
||||
},
|
||||
|
|
@ -375,7 +375,7 @@ export const Instance = z
|
|||
/* Versia Server API extension */
|
||||
sso: SSOConfig,
|
||||
})
|
||||
.openapi({
|
||||
.openapi("Instance", {
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Instance",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ export const Marker = z
|
|||
example: "2025-01-12T13:11:00Z",
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("Marker", {
|
||||
description:
|
||||
"Represents the last read position within a user's timelines.",
|
||||
externalDocs: {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ export const Notification = z
|
|||
"Moderation warning that caused the notification. Attached when type of the notification is moderation_warning.",
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("Notification", {
|
||||
description:
|
||||
"Represents a notification of an event relevant to the user.",
|
||||
externalDocs: {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ export const PollOption = z
|
|||
},
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("PollOption", {
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Poll/#Option",
|
||||
},
|
||||
|
|
@ -130,7 +130,7 @@ export const Poll = z
|
|||
},
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("Poll", {
|
||||
description: "Represents a poll attached to a status.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Poll",
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ export const Preferences = z
|
|||
},
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("Preferences", {
|
||||
description: "Represents a user's preferences.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Preferences",
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ export const PrivacyPolicy = z
|
|||
},
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("PrivacyPolicy", {
|
||||
description: "Represents the privacy policy of the instance.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/PrivacyPolicy",
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ export const WebPushSubscription = z
|
|||
description: "The streaming server’s VAPID key.",
|
||||
}),
|
||||
})
|
||||
.openapi({});
|
||||
.openapi("WebPushSubscription");
|
||||
|
||||
export const WebPushSubscriptionInput = z
|
||||
.object({
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ export const Relationship = z
|
|||
example: "they also like Kerbal Space Program",
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("Relationship", {
|
||||
description:
|
||||
"Represents the relationship between accounts, such as following / blocking / muting / etc.",
|
||||
externalDocs: {
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ export const Report = z
|
|||
description: "The account that was reported.",
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("Report", {
|
||||
description:
|
||||
"Reports filed against users and/or statuses, to be taken action on by moderators.",
|
||||
externalDocs: {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ export const Rule = z
|
|||
example: "Please, we beg you.",
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("Rule", {
|
||||
description: "Represents a rule that server users should follow.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Rule",
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ export const Search = z
|
|||
description: "Hashtags which match the given query",
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("Search", {
|
||||
description: "Represents the results of a search.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Search",
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ export const Mention = z
|
|||
},
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("Mention", {
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#Mention",
|
||||
},
|
||||
|
|
@ -75,282 +75,288 @@ export const StatusSource = z
|
|||
example: "",
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("StatusSource", {
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/StatusSource",
|
||||
},
|
||||
});
|
||||
|
||||
// Because Status has some recursive references, we need to define it like this
|
||||
const BaseStatus = z.object({
|
||||
id: Id.openapi({
|
||||
description: "ID of the status in the database.",
|
||||
example: "2de861d3-a3dd-42ee-ba38-2c7d3f4af588",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#id",
|
||||
},
|
||||
}),
|
||||
uri: z
|
||||
.string()
|
||||
.url()
|
||||
.openapi({
|
||||
description: "URI of the status used for federation.",
|
||||
example:
|
||||
"https://beta.versia.social/@lexi/2de861d3-a3dd-42ee-ba38-2c7d3f4af588",
|
||||
const BaseStatus = z
|
||||
.object({
|
||||
id: Id.openapi({
|
||||
description: "ID of the status in the database.",
|
||||
example: "2de861d3-a3dd-42ee-ba38-2c7d3f4af588",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#uri",
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#id",
|
||||
},
|
||||
}),
|
||||
url: z
|
||||
.string()
|
||||
.url()
|
||||
.nullable()
|
||||
.openapi({
|
||||
description: "A link to the status’s HTML representation.",
|
||||
example:
|
||||
"https://beta.versia.social/@lexi/2de861d3-a3dd-42ee-ba38-2c7d3f4af588",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#url",
|
||||
},
|
||||
}),
|
||||
account: Account.openapi({
|
||||
description: "The account that authored this status.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#account",
|
||||
},
|
||||
}),
|
||||
in_reply_to_id: Id.nullable().openapi({
|
||||
description: "ID of the status being replied to.",
|
||||
example: "c41c9fe9-919a-4d35-a921-d3e79a5c95f8",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#in_reply_to_id",
|
||||
},
|
||||
}),
|
||||
in_reply_to_account_id: Account.shape.id.nullable().openapi({
|
||||
description:
|
||||
"ID of the account that authored the status being replied to.",
|
||||
example: "7b9b3ec6-1013-4cc6-8902-94ad00cf2ccc",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#in_reply_to_account_id",
|
||||
},
|
||||
}),
|
||||
|
||||
content: z.string().openapi({
|
||||
description: "HTML-encoded status content.",
|
||||
example: "<p>hello world</p>",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#content",
|
||||
},
|
||||
}),
|
||||
created_at: z
|
||||
.string()
|
||||
.datetime()
|
||||
.openapi({
|
||||
description: "The date when this status was created.",
|
||||
example: "2025-01-07T14:11:00.000Z",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#created_at",
|
||||
},
|
||||
}),
|
||||
edited_at: z
|
||||
.string()
|
||||
.datetime()
|
||||
.nullable()
|
||||
.openapi({
|
||||
description: "Timestamp of when the status was last edited.",
|
||||
example: "2025-01-07T14:11:00.000Z",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#edited_at",
|
||||
},
|
||||
}),
|
||||
emojis: z.array(CustomEmoji).openapi({
|
||||
description: "Custom emoji to be used when rendering status content.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#emojis",
|
||||
},
|
||||
}),
|
||||
replies_count: z
|
||||
.number()
|
||||
.int()
|
||||
.nonnegative()
|
||||
.openapi({
|
||||
description: "How many replies this status has received.",
|
||||
example: 1,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#replies_count",
|
||||
},
|
||||
}),
|
||||
reblogs_count: z
|
||||
.number()
|
||||
.int()
|
||||
.nonnegative()
|
||||
.openapi({
|
||||
description: "How many boosts this status has received.",
|
||||
example: 6,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#reblogs_count",
|
||||
},
|
||||
}),
|
||||
favourites_count: z
|
||||
.number()
|
||||
.int()
|
||||
.nonnegative()
|
||||
.openapi({
|
||||
description: "How many favourites this status has received.",
|
||||
example: 11,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#favourites_count",
|
||||
},
|
||||
}),
|
||||
reblogged: zBoolean.optional().openapi({
|
||||
description:
|
||||
"If the current token has an authorized user: Have you boosted this status?",
|
||||
example: false,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#reblogged",
|
||||
},
|
||||
}),
|
||||
favourited: zBoolean.optional().openapi({
|
||||
description:
|
||||
"If the current token has an authorized user: Have you favourited this status?",
|
||||
example: true,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#favourited",
|
||||
},
|
||||
}),
|
||||
muted: zBoolean.optional().openapi({
|
||||
description:
|
||||
"If the current token has an authorized user: Have you muted notifications for this status’s conversation?",
|
||||
example: false,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#muted",
|
||||
},
|
||||
}),
|
||||
sensitive: zBoolean.openapi({
|
||||
description: "Is this status marked as sensitive content?",
|
||||
example: false,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#sensitive",
|
||||
},
|
||||
}),
|
||||
spoiler_text: z.string().openapi({
|
||||
description:
|
||||
"Subject or summary line, below which status content is collapsed until expanded.",
|
||||
example: "lewd text",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#spoiler_text",
|
||||
},
|
||||
}),
|
||||
visibility: z.enum(["public", "unlisted", "private", "direct"]).openapi({
|
||||
description: "Visibility of this status.",
|
||||
example: "public",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#visibility",
|
||||
},
|
||||
}),
|
||||
media_attachments: z.array(Attachment).openapi({
|
||||
description: "Media that is attached to this status.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#media_attachments",
|
||||
},
|
||||
}),
|
||||
mentions: z.array(Mention).openapi({
|
||||
description: "Mentions of users within the status content.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#mentions",
|
||||
},
|
||||
}),
|
||||
tags: z.array(Tag).openapi({
|
||||
description: "Hashtags used within the status content.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#tags",
|
||||
},
|
||||
}),
|
||||
card: PreviewCard.nullable().openapi({
|
||||
description: "Preview card for links included within status content.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#card",
|
||||
},
|
||||
}),
|
||||
poll: Poll.nullable().openapi({
|
||||
description: "The poll attached to the status.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#poll",
|
||||
},
|
||||
}),
|
||||
application: z
|
||||
.object({
|
||||
name: z.string().openapi({
|
||||
description:
|
||||
"The name of the application that posted this status.",
|
||||
uri: z
|
||||
.string()
|
||||
.url()
|
||||
.openapi({
|
||||
description: "URI of the status used for federation.",
|
||||
example:
|
||||
"https://beta.versia.social/@lexi/2de861d3-a3dd-42ee-ba38-2c7d3f4af588",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#application-name",
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#uri",
|
||||
},
|
||||
}),
|
||||
website: z
|
||||
.string()
|
||||
.url()
|
||||
.nullable()
|
||||
.openapi({
|
||||
url: z
|
||||
.string()
|
||||
.url()
|
||||
.nullable()
|
||||
.openapi({
|
||||
description: "A link to the status’s HTML representation.",
|
||||
example:
|
||||
"https://beta.versia.social/@lexi/2de861d3-a3dd-42ee-ba38-2c7d3f4af588",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#url",
|
||||
},
|
||||
}),
|
||||
account: Account.openapi({
|
||||
description: "The account that authored this status.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#account",
|
||||
},
|
||||
}),
|
||||
in_reply_to_id: Id.nullable().openapi({
|
||||
description: "ID of the status being replied to.",
|
||||
example: "c41c9fe9-919a-4d35-a921-d3e79a5c95f8",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#in_reply_to_id",
|
||||
},
|
||||
}),
|
||||
in_reply_to_account_id: Account.shape.id.nullable().openapi({
|
||||
description:
|
||||
"ID of the account that authored the status being replied to.",
|
||||
example: "7b9b3ec6-1013-4cc6-8902-94ad00cf2ccc",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#in_reply_to_account_id",
|
||||
},
|
||||
}),
|
||||
|
||||
content: z.string().openapi({
|
||||
description: "HTML-encoded status content.",
|
||||
example: "<p>hello world</p>",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#content",
|
||||
},
|
||||
}),
|
||||
created_at: z
|
||||
.string()
|
||||
.datetime()
|
||||
.openapi({
|
||||
description: "The date when this status was created.",
|
||||
example: "2025-01-07T14:11:00.000Z",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#created_at",
|
||||
},
|
||||
}),
|
||||
edited_at: z
|
||||
.string()
|
||||
.datetime()
|
||||
.nullable()
|
||||
.openapi({
|
||||
description: "Timestamp of when the status was last edited.",
|
||||
example: "2025-01-07T14:11:00.000Z",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#edited_at",
|
||||
},
|
||||
}),
|
||||
emojis: z.array(CustomEmoji).openapi({
|
||||
description:
|
||||
"Custom emoji to be used when rendering status content.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#emojis",
|
||||
},
|
||||
}),
|
||||
replies_count: z
|
||||
.number()
|
||||
.int()
|
||||
.nonnegative()
|
||||
.openapi({
|
||||
description: "How many replies this status has received.",
|
||||
example: 1,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#replies_count",
|
||||
},
|
||||
}),
|
||||
reblogs_count: z
|
||||
.number()
|
||||
.int()
|
||||
.nonnegative()
|
||||
.openapi({
|
||||
description: "How many boosts this status has received.",
|
||||
example: 6,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#reblogs_count",
|
||||
},
|
||||
}),
|
||||
favourites_count: z
|
||||
.number()
|
||||
.int()
|
||||
.nonnegative()
|
||||
.openapi({
|
||||
description: "How many favourites this status has received.",
|
||||
example: 11,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#favourites_count",
|
||||
},
|
||||
}),
|
||||
reblogged: zBoolean.optional().openapi({
|
||||
description:
|
||||
"If the current token has an authorized user: Have you boosted this status?",
|
||||
example: false,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#reblogged",
|
||||
},
|
||||
}),
|
||||
favourited: zBoolean.optional().openapi({
|
||||
description:
|
||||
"If the current token has an authorized user: Have you favourited this status?",
|
||||
example: true,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#favourited",
|
||||
},
|
||||
}),
|
||||
muted: zBoolean.optional().openapi({
|
||||
description:
|
||||
"If the current token has an authorized user: Have you muted notifications for this status’s conversation?",
|
||||
example: false,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#muted",
|
||||
},
|
||||
}),
|
||||
sensitive: zBoolean.openapi({
|
||||
description: "Is this status marked as sensitive content?",
|
||||
example: false,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#sensitive",
|
||||
},
|
||||
}),
|
||||
spoiler_text: z.string().openapi({
|
||||
description:
|
||||
"Subject or summary line, below which status content is collapsed until expanded.",
|
||||
example: "lewd text",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#spoiler_text",
|
||||
},
|
||||
}),
|
||||
visibility: z
|
||||
.enum(["public", "unlisted", "private", "direct"])
|
||||
.openapi({
|
||||
description: "Visibility of this status.",
|
||||
example: "public",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#visibility",
|
||||
},
|
||||
}),
|
||||
media_attachments: z.array(Attachment).openapi({
|
||||
description: "Media that is attached to this status.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#media_attachments",
|
||||
},
|
||||
}),
|
||||
mentions: z.array(Mention).openapi({
|
||||
description: "Mentions of users within the status content.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#mentions",
|
||||
},
|
||||
}),
|
||||
tags: z.array(Tag).openapi({
|
||||
description: "Hashtags used within the status content.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#tags",
|
||||
},
|
||||
}),
|
||||
card: PreviewCard.nullable().openapi({
|
||||
description:
|
||||
"Preview card for links included within status content.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#card",
|
||||
},
|
||||
}),
|
||||
poll: Poll.nullable().openapi({
|
||||
description: "The poll attached to the status.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#poll",
|
||||
},
|
||||
}),
|
||||
application: z
|
||||
.object({
|
||||
name: z.string().openapi({
|
||||
description:
|
||||
"The website associated with the application that posted this status.",
|
||||
"The name of the application that posted this status.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#application-website",
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#application-name",
|
||||
},
|
||||
}),
|
||||
})
|
||||
.optional()
|
||||
.openapi({
|
||||
description: "The application used to post this status.",
|
||||
website: z
|
||||
.string()
|
||||
.url()
|
||||
.nullable()
|
||||
.openapi({
|
||||
description:
|
||||
"The website associated with the application that posted this status.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#application-website",
|
||||
},
|
||||
}),
|
||||
})
|
||||
.optional()
|
||||
.openapi({
|
||||
description: "The application used to post this status.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#application",
|
||||
},
|
||||
}),
|
||||
language: iso631.nullable().openapi({
|
||||
description: "Primary language of this status.",
|
||||
example: "en",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#application",
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#language",
|
||||
},
|
||||
}),
|
||||
language: iso631.nullable().openapi({
|
||||
description: "Primary language of this status.",
|
||||
example: "en",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#language",
|
||||
},
|
||||
}),
|
||||
text: z
|
||||
.string()
|
||||
.nullable()
|
||||
.openapi({
|
||||
text: z
|
||||
.string()
|
||||
.nullable()
|
||||
.openapi({
|
||||
description:
|
||||
"Plain-text source of a status. Returned instead of content when status is deleted, so the user may redraft from the source text without the client having to reverse-engineer the original text from the HTML content.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#text",
|
||||
},
|
||||
}),
|
||||
pinned: zBoolean.optional().openapi({
|
||||
description:
|
||||
"Plain-text source of a status. Returned instead of content when status is deleted, so the user may redraft from the source text without the client having to reverse-engineer the original text from the HTML content.",
|
||||
"If the current token has an authorized user: Have you pinned this status? Only appears if the status is pinnable.",
|
||||
example: true,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#text",
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#pinned",
|
||||
},
|
||||
}),
|
||||
pinned: zBoolean.optional().openapi({
|
||||
description:
|
||||
"If the current token has an authorized user: Have you pinned this status? Only appears if the status is pinnable.",
|
||||
example: true,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#pinned",
|
||||
},
|
||||
}),
|
||||
reactions: z.array(NoteReaction).openapi({}),
|
||||
bookmarked: zBoolean.optional().openapi({
|
||||
description:
|
||||
"If the current token has an authorized user: Have you bookmarked this status?",
|
||||
example: false,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#bookmarked",
|
||||
},
|
||||
}),
|
||||
filtered: z
|
||||
.array(FilterResult)
|
||||
.optional()
|
||||
.openapi({
|
||||
reactions: z.array(NoteReaction).openapi({}),
|
||||
bookmarked: zBoolean.optional().openapi({
|
||||
description:
|
||||
"If the current token has an authorized user: The filter and keywords that matched this status.",
|
||||
"If the current token has an authorized user: Have you bookmarked this status?",
|
||||
example: false,
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#filtered",
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#bookmarked",
|
||||
},
|
||||
}),
|
||||
});
|
||||
filtered: z
|
||||
.array(FilterResult)
|
||||
.optional()
|
||||
.openapi({
|
||||
description:
|
||||
"If the current token has an authorized user: The filter and keywords that matched this status.",
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#filtered",
|
||||
},
|
||||
}),
|
||||
})
|
||||
.openapi("BaseStatus");
|
||||
|
||||
export const Status = BaseStatus.extend({
|
||||
reblog: BaseStatus.nullable().openapi({
|
||||
|
|
@ -360,50 +366,52 @@ export const Status = BaseStatus.extend({
|
|||
},
|
||||
}),
|
||||
quote: BaseStatus.nullable(),
|
||||
});
|
||||
}).openapi("Status");
|
||||
|
||||
export const ScheduledStatus = z.object({
|
||||
id: Id.openapi({
|
||||
description: "ID of the scheduled status in the database.",
|
||||
example: "2de861d3-a3dd-42ee-ba38-2c7d3f4af588",
|
||||
}),
|
||||
scheduled_at: z.string().datetime().openapi({
|
||||
description: "When the status will be scheduled.",
|
||||
example: "2025-01-07T14:11:00.000Z",
|
||||
}),
|
||||
media_attachments: Status.shape.media_attachments,
|
||||
params: z.object({
|
||||
text: z.string().openapi({
|
||||
description: "Text to be used as status content.",
|
||||
example: "Hello, world!",
|
||||
export const ScheduledStatus = z
|
||||
.object({
|
||||
id: Id.openapi({
|
||||
description: "ID of the scheduled status in the database.",
|
||||
example: "2de861d3-a3dd-42ee-ba38-2c7d3f4af588",
|
||||
}),
|
||||
poll: Status.shape.poll,
|
||||
media_ids: z
|
||||
.array(Id)
|
||||
.nullable()
|
||||
.openapi({
|
||||
description:
|
||||
"IDs of the MediaAttachments that will be attached to the status.",
|
||||
example: ["1234567890", "1234567891"],
|
||||
scheduled_at: z.string().datetime().openapi({
|
||||
description: "When the status will be scheduled.",
|
||||
example: "2025-01-07T14:11:00.000Z",
|
||||
}),
|
||||
media_attachments: Status.shape.media_attachments,
|
||||
params: z.object({
|
||||
text: z.string().openapi({
|
||||
description: "Text to be used as status content.",
|
||||
example: "Hello, world!",
|
||||
}),
|
||||
poll: Status.shape.poll,
|
||||
media_ids: z
|
||||
.array(Id)
|
||||
.nullable()
|
||||
.openapi({
|
||||
description:
|
||||
"IDs of the MediaAttachments that will be attached to the status.",
|
||||
example: ["1234567890", "1234567891"],
|
||||
}),
|
||||
sensitive: Status.shape.sensitive,
|
||||
spoiler_text: Status.shape.spoiler_text,
|
||||
visibility: Status.shape.visibility,
|
||||
in_reply_to_id: Status.shape.in_reply_to_id,
|
||||
/** Versia Server API Extension */
|
||||
quote_id: z.string().openapi({
|
||||
description: "ID of the status being quoted.",
|
||||
example: "c5d62a13-f340-4e7d-8942-7fd14be688dc",
|
||||
}),
|
||||
language: Status.shape.language,
|
||||
scheduled_at: z.null().openapi({
|
||||
description:
|
||||
"When the status will be scheduled. This will be null because the status is only scheduled once.",
|
||||
example: null,
|
||||
}),
|
||||
idempotency: z.string().nullable().openapi({
|
||||
description: "Idempotency key to prevent duplicate statuses.",
|
||||
example: "1234567890",
|
||||
}),
|
||||
sensitive: Status.shape.sensitive,
|
||||
spoiler_text: Status.shape.spoiler_text,
|
||||
visibility: Status.shape.visibility,
|
||||
in_reply_to_id: Status.shape.in_reply_to_id,
|
||||
/** Versia Server API Extension */
|
||||
quote_id: z.string().openapi({
|
||||
description: "ID of the status being quoted.",
|
||||
example: "c5d62a13-f340-4e7d-8942-7fd14be688dc",
|
||||
}),
|
||||
language: Status.shape.language,
|
||||
scheduled_at: z.null().openapi({
|
||||
description:
|
||||
"When the status will be scheduled. This will be null because the status is only scheduled once.",
|
||||
example: null,
|
||||
}),
|
||||
idempotency: z.string().nullable().openapi({
|
||||
description: "Idempotency key to prevent duplicate statuses.",
|
||||
example: "1234567890",
|
||||
}),
|
||||
}),
|
||||
});
|
||||
})
|
||||
.openapi("ScheduledStatus");
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ export const Tag = z
|
|||
},
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("Tag", {
|
||||
externalDocs: {
|
||||
url: "https://docs.joinmastodon.org/entities/Status/#Tag",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ export const Token = z
|
|||
example: 1573979017,
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("Token", {
|
||||
description:
|
||||
"Represents an OAuth token used for authenticating with the API and performing actions.",
|
||||
externalDocs: {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,6 @@ export const TermsOfService = z
|
|||
example: "<p><h1>ToS</h1><p>None, have fun.</p></p>",
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("TermsOfService", {
|
||||
description: "Represents the ToS of the instance.",
|
||||
});
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ export const Role = z
|
|||
example: "https://example.com/role-icon.png",
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("Role", {
|
||||
description:
|
||||
"Information about a role in the system, as well as its permissions.",
|
||||
});
|
||||
|
|
@ -72,7 +72,7 @@ export const NoteReaction = z
|
|||
example: true,
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("NoteReaction", {
|
||||
description: "Information about a reaction to a note.",
|
||||
});
|
||||
|
||||
|
|
@ -134,6 +134,6 @@ export const Challenge = z
|
|||
example: "1234567890",
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
.openapi("Challenge", {
|
||||
description: "A cryptographic challenge to solve. Used for Captchas.",
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue