mirror of
https://github.com/versia-pub/server.git
synced 2026-03-13 05:49:16 +01:00
refactor(config): ♻️ Redo config structure from scratch, simplify validation code, improve checks, add support for loading sensitive data from paths
This commit is contained in:
parent
d4afd84019
commit
54fd81f076
118 changed files with 3892 additions and 5291 deletions
|
|
@ -1,7 +1,7 @@
|
|||
import { afterAll, describe, expect, test } from "bun:test";
|
||||
import { randomString } from "@/math";
|
||||
import { Application } from "@versia/kit/db";
|
||||
import { config } from "~/packages/config-manager";
|
||||
import { config } from "~/config.ts";
|
||||
import { fakeRequest, getTestUsers } from "~/tests/utils";
|
||||
|
||||
const { users, deleteUsers, passwords } = await getTestUsers(1);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import type { Context } from "hono";
|
|||
import { setCookie } from "hono/cookie";
|
||||
import { SignJWT } from "jose";
|
||||
import { ApiError } from "~/classes/errors/api-error";
|
||||
import { config } from "~/packages/config-manager";
|
||||
import { config } from "~/config.ts";
|
||||
|
||||
const schemas = {
|
||||
form: z.object({
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { createRoute, z } from "@hono/zod-openapi";
|
|||
import { db } from "@versia/kit/db";
|
||||
import { Applications, Tokens } from "@versia/kit/tables";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import { config } from "~/packages/config-manager";
|
||||
import { config } from "~/config.ts";
|
||||
|
||||
const schemas = {
|
||||
query: z.object({
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { afterAll, describe, expect, test } from "bun:test";
|
||||
import { randomString } from "@/math";
|
||||
import { Application } from "@versia/kit/db";
|
||||
import { config } from "~/packages/config-manager";
|
||||
import { config } from "~/config.ts";
|
||||
import { fakeRequest, getTestUsers } from "~/tests/utils";
|
||||
|
||||
const { users, deleteUsers, passwords } = await getTestUsers(1);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { User } from "@versia/kit/db";
|
|||
import { Users } from "@versia/kit/tables";
|
||||
import { eq } from "drizzle-orm";
|
||||
import type { Context } from "hono";
|
||||
import { config } from "~/packages/config-manager";
|
||||
import { config } from "~/config.ts";
|
||||
|
||||
const schemas = {
|
||||
form: z.object({
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ import { Timeline } from "@versia/kit/db";
|
|||
import { Notes, RolePermissions } from "@versia/kit/tables";
|
||||
import { and, eq, gt, gte, inArray, isNull, lt, or, sql } from "drizzle-orm";
|
||||
import { Account as AccountSchema } from "~/classes/schemas/account";
|
||||
import { zBoolean } from "~/classes/schemas/common.ts";
|
||||
import { Status as StatusSchema } from "~/classes/schemas/status";
|
||||
import { zBoolean } from "~/packages/config-manager/config.type";
|
||||
|
||||
const route = createRoute({
|
||||
method: "get",
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import { Users } from "@versia/kit/tables";
|
|||
import { and, eq, isNull } from "drizzle-orm";
|
||||
import ISO6391 from "iso-639-1";
|
||||
import { ApiError } from "~/classes/errors/api-error";
|
||||
import { config } from "~/packages/config-manager";
|
||||
import { zBoolean } from "~/packages/config-manager/config.type";
|
||||
import { zBoolean } from "~/classes/schemas/common";
|
||||
import { config } from "~/config.ts";
|
||||
|
||||
const schema = z.object({
|
||||
username: z.string().openapi({
|
||||
|
|
@ -157,7 +157,7 @@ export default apiRoute((app) =>
|
|||
const { username, email, password, agreement, locale } =
|
||||
context.req.valid("json");
|
||||
|
||||
if (!config.signups.registration) {
|
||||
if (!config.registration.allow) {
|
||||
throw new ApiError(422, "Registration is disabled");
|
||||
}
|
||||
|
||||
|
|
@ -217,7 +217,11 @@ export default apiRoute((app) =>
|
|||
}
|
||||
|
||||
// Check if username doesnt match filters
|
||||
if (config.filters.username.some((filter) => username?.match(filter))) {
|
||||
if (
|
||||
config.validation.filters.username.some((filter) =>
|
||||
filter.test(username),
|
||||
)
|
||||
) {
|
||||
errors.details.username.push({
|
||||
error: "ERR_INVALID",
|
||||
description: "contains blocked words",
|
||||
|
|
@ -225,10 +229,13 @@ export default apiRoute((app) =>
|
|||
}
|
||||
|
||||
// Check if username is too long
|
||||
if ((username?.length ?? 0) > config.validation.max_username_size) {
|
||||
if (
|
||||
(username?.length ?? 0) >
|
||||
config.validation.accounts.max_username_characters
|
||||
) {
|
||||
errors.details.username.push({
|
||||
error: "ERR_TOO_LONG",
|
||||
description: `is too long (maximum is ${config.validation.max_username_size} characters)`,
|
||||
description: `is too long (maximum is ${config.validation.accounts.max_username_characters} characters)`,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -241,7 +248,11 @@ export default apiRoute((app) =>
|
|||
}
|
||||
|
||||
// Check if username is reserved
|
||||
if (config.validation.username_blacklist.includes(username ?? "")) {
|
||||
if (
|
||||
config.validation.accounts.disallowed_usernames.some((filter) =>
|
||||
filter.test(username),
|
||||
)
|
||||
) {
|
||||
errors.details.username.push({
|
||||
error: "ERR_RESERVED",
|
||||
description: "is reserved",
|
||||
|
|
@ -274,9 +285,11 @@ export default apiRoute((app) =>
|
|||
|
||||
// Check if email is blocked
|
||||
if (
|
||||
config.validation.email_blacklist.includes(email) ||
|
||||
(config.validation.blacklist_tempmail &&
|
||||
tempmailDomains.domains.includes((email ?? "").split("@")[1]))
|
||||
config.validation.emails.disallowed_domains.some((f) =>
|
||||
f.test(email.split("@")[1]),
|
||||
) ||
|
||||
(config.validation.emails.disallow_tempmail &&
|
||||
tempmailDomains.domains.includes(email.split("@")[1]))
|
||||
) {
|
||||
errors.details.email.push({
|
||||
error: "ERR_BLOCKED",
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import { and, eq, isNull } from "drizzle-orm";
|
|||
import { ApiError } from "~/classes/errors/api-error";
|
||||
import { Account } from "~/classes/schemas/account";
|
||||
import { Account as AccountSchema } from "~/classes/schemas/account";
|
||||
import { config } from "~/packages/config-manager";
|
||||
import { config } from "~/config.ts";
|
||||
|
||||
const route = createRoute({
|
||||
method: "get",
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ import { createRoute, z } from "@hono/zod-openapi";
|
|||
import { Relationship } from "@versia/kit/db";
|
||||
import { RolePermissions } from "@versia/kit/tables";
|
||||
import { Account as AccountSchema } from "~/classes/schemas/account";
|
||||
import { zBoolean } from "~/classes/schemas/common.ts";
|
||||
import { Relationship as RelationshipSchema } from "~/classes/schemas/relationship";
|
||||
import { zBoolean } from "~/packages/config-manager/config.type";
|
||||
|
||||
const route = createRoute({
|
||||
method: "get",
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { eq, ilike, not, or, sql } from "drizzle-orm";
|
|||
import stringComparison from "string-comparison";
|
||||
import { ApiError } from "~/classes/errors/api-error";
|
||||
import { Account as AccountSchema } from "~/classes/schemas/account";
|
||||
import { zBoolean } from "~/packages/config-manager/config.type";
|
||||
import { zBoolean } from "~/classes/schemas/common.ts";
|
||||
|
||||
export const route = createRoute({
|
||||
method: "get",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { afterAll, describe, expect, test } from "bun:test";
|
||||
import type { Account as APIAccount } from "@versia/client/types";
|
||||
import { config } from "~/packages/config-manager/index.ts";
|
||||
import { config } from "~/config.ts";
|
||||
import { fakeRequest, getTestUsers } from "~/tests/utils";
|
||||
|
||||
const { tokens, deleteUsers } = await getTestUsers(1);
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import { and, eq, isNull } from "drizzle-orm";
|
|||
import { ApiError } from "~/classes/errors/api-error";
|
||||
import { contentToHtml } from "~/classes/functions/status";
|
||||
import { Account as AccountSchema } from "~/classes/schemas/account";
|
||||
import { zBoolean } from "~/packages/config-manager/config.type";
|
||||
import { config } from "~/packages/config-manager/index.ts";
|
||||
import { zBoolean } from "~/classes/schemas/common.ts";
|
||||
import { config } from "~/config.ts";
|
||||
|
||||
const route = createRoute({
|
||||
method: "patch",
|
||||
|
|
@ -62,9 +62,9 @@ const route = createRoute({
|
|||
.refine(
|
||||
(v) =>
|
||||
v.size <=
|
||||
config.validation
|
||||
.max_avatar_size,
|
||||
`Avatar must be less than ${config.validation.max_avatar_size} bytes`,
|
||||
config.validation.accounts
|
||||
.max_avatar_bytes,
|
||||
`Avatar must be less than ${config.validation.accounts.max_avatar_bytes} bytes`,
|
||||
)
|
||||
.openapi({
|
||||
description:
|
||||
|
|
@ -84,9 +84,9 @@ const route = createRoute({
|
|||
.refine(
|
||||
(v) =>
|
||||
v.size <=
|
||||
config.validation
|
||||
.max_header_size,
|
||||
`Header must be less than ${config.validation.max_header_size} bytes`,
|
||||
config.validation.accounts
|
||||
.max_header_bytes,
|
||||
`Header must be less than ${config.validation.accounts.max_header_bytes} bytes`,
|
||||
)
|
||||
.openapi({
|
||||
description:
|
||||
|
|
@ -144,7 +144,9 @@ const route = createRoute({
|
|||
.element.shape.value,
|
||||
}),
|
||||
)
|
||||
.max(config.validation.max_field_count),
|
||||
.max(
|
||||
config.validation.accounts.max_field_count,
|
||||
),
|
||||
})
|
||||
.partial(),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { apiRoute, auth } from "@/api";
|
|||
import { generateChallenge } from "@/challenges";
|
||||
import { createRoute, z } from "@hono/zod-openapi";
|
||||
import { ApiError } from "~/classes/errors/api-error";
|
||||
import { config } from "~/packages/config-manager";
|
||||
import { config } from "~/config.ts";
|
||||
import { ErrorSchema } from "~/types/api";
|
||||
|
||||
const route = createRoute({
|
||||
|
|
@ -45,7 +45,7 @@ const route = createRoute({
|
|||
|
||||
export default apiRoute((app) =>
|
||||
app.openapi(route, async (context) => {
|
||||
if (!config.validation.challenges.enabled) {
|
||||
if (!config.validation.challenges) {
|
||||
throw new ApiError(400, "Challenges are disabled in config");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { createRoute, z } from "@hono/zod-openapi";
|
|||
import { RolePermissions } from "@versia/kit/tables";
|
||||
import { ApiError } from "~/classes/errors/api-error";
|
||||
import { CustomEmoji as CustomEmojiSchema } from "~/classes/schemas/emoji";
|
||||
import { config } from "~/packages/config-manager";
|
||||
import { config } from "~/config.ts";
|
||||
import { ErrorSchema } from "~/types/api";
|
||||
|
||||
const schema = z
|
||||
|
|
@ -31,8 +31,8 @@ const schema = z
|
|||
"Emoji image encoded using multipart/form-data",
|
||||
})
|
||||
.refine(
|
||||
(v) => v.size <= config.validation.max_emoji_size,
|
||||
`Emoji must be less than ${config.validation.max_emoji_size} bytes`,
|
||||
(v) => v.size <= config.validation.emojis.max_bytes,
|
||||
`Emoji must be less than ${config.validation.emojis.max_bytes} bytes`,
|
||||
),
|
||||
),
|
||||
category: CustomEmojiSchema.shape.category.optional(),
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { Emojis, RolePermissions } from "@versia/kit/tables";
|
|||
import { and, eq, isNull, or } from "drizzle-orm";
|
||||
import { ApiError } from "~/classes/errors/api-error";
|
||||
import { CustomEmoji as CustomEmojiSchema } from "~/classes/schemas/emoji";
|
||||
import { config } from "~/packages/config-manager";
|
||||
import { config } from "~/config.ts";
|
||||
|
||||
const schema = z.object({
|
||||
shortcode: CustomEmojiSchema.shape.shortcode,
|
||||
|
|
@ -25,8 +25,8 @@ const schema = z.object({
|
|||
"Emoji image encoded using multipart/form-data",
|
||||
})
|
||||
.refine(
|
||||
(v) => v.size <= config.validation.max_emoji_size,
|
||||
`Emoji must be less than ${config.validation.max_emoji_size} bytes`,
|
||||
(v) => v.size <= config.validation.emojis.max_bytes,
|
||||
`Emoji must be less than ${config.validation.emojis.max_bytes} bytes`,
|
||||
),
|
||||
),
|
||||
category: CustomEmojiSchema.shape.category.optional(),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { apiRoute } from "@/api";
|
||||
import { createRoute, z } from "@hono/zod-openapi";
|
||||
import { config } from "~/packages/config-manager";
|
||||
import { config } from "~/config.ts";
|
||||
|
||||
const route = createRoute({
|
||||
method: "get",
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ describe("/api/v1/instance/extended_description", () => {
|
|||
|
||||
const json = await response.json();
|
||||
expect(json).toEqual({
|
||||
updated_at: new Date(1970, 0, 0).toISOString(),
|
||||
updated_at: new Date(0).toISOString(),
|
||||
content:
|
||||
'<p>This is a <a href="https://versia.pub">Versia</a> server with the default extended description.</p>\n',
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { apiRoute } from "@/api";
|
||||
import { renderMarkdownInPath } from "@/markdown";
|
||||
import { createRoute } from "@hono/zod-openapi";
|
||||
import { markdownParse } from "~/classes/functions/status";
|
||||
import { ExtendedDescription as ExtendedDescriptionSchema } from "~/classes/schemas/extended-description";
|
||||
import { config } from "~/packages/config-manager";
|
||||
import { config } from "~/config.ts";
|
||||
|
||||
const route = createRoute({
|
||||
method: "get",
|
||||
|
|
@ -27,14 +27,17 @@ const route = createRoute({
|
|||
|
||||
export default apiRoute((app) =>
|
||||
app.openapi(route, async (context) => {
|
||||
const { content, lastModified } = await renderMarkdownInPath(
|
||||
config.instance.extended_description_path ?? "",
|
||||
"This is a [Versia](https://versia.pub) server with the default extended description.",
|
||||
const content = await markdownParse(
|
||||
config.instance.extended_description_path?.content ??
|
||||
"This is a [Versia](https://versia.pub) server with the default extended description.",
|
||||
);
|
||||
|
||||
return context.json(
|
||||
{
|
||||
updated_at: lastModified.toISOString(),
|
||||
updated_at: new Date(
|
||||
config.instance.extended_description_path?.file
|
||||
.lastModified ?? 0,
|
||||
).toISOString(),
|
||||
content,
|
||||
},
|
||||
200,
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import { apiRoute, auth } from "@/api";
|
||||
import { renderMarkdownInPath } from "@/markdown";
|
||||
import { proxyUrl } from "@/response";
|
||||
import { createRoute, type z } from "@hono/zod-openapi";
|
||||
import { Instance, Note, User } from "@versia/kit/db";
|
||||
import { Users } from "@versia/kit/tables";
|
||||
import { and, eq, isNull } from "drizzle-orm";
|
||||
import { markdownParse } from "~/classes/functions/status";
|
||||
import { InstanceV1 as InstanceV1Schema } from "~/classes/schemas/instance-v1";
|
||||
import { config } from "~/config.ts";
|
||||
import manifest from "~/package.json";
|
||||
import { config } from "~/packages/config-manager";
|
||||
|
||||
const route = createRoute({
|
||||
method: "get",
|
||||
|
|
@ -65,35 +65,38 @@ export default apiRoute((app) =>
|
|||
}
|
||||
| undefined;
|
||||
|
||||
const { content } = await renderMarkdownInPath(
|
||||
config.instance.extended_description_path ?? "",
|
||||
"This is a [Versia](https://versia.pub) server with the default extended description.",
|
||||
const content = await markdownParse(
|
||||
config.instance.extended_description_path?.content ??
|
||||
"This is a [Versia](https://versia.pub) server with the default extended description.",
|
||||
);
|
||||
|
||||
// TODO: fill in more values
|
||||
return context.json({
|
||||
approval_required: false,
|
||||
approval_required: config.registration.require_approval,
|
||||
configuration: {
|
||||
polls: {
|
||||
max_characters_per_option:
|
||||
config.validation.max_poll_option_size,
|
||||
max_expiration: config.validation.max_poll_duration,
|
||||
max_options: config.validation.max_poll_options,
|
||||
min_expiration: config.validation.min_poll_duration,
|
||||
config.validation.polls.max_option_characters,
|
||||
max_expiration:
|
||||
config.validation.polls.max_duration_seconds,
|
||||
max_options: config.validation.polls.max_options,
|
||||
min_expiration:
|
||||
config.validation.polls.min_duration_seconds,
|
||||
},
|
||||
statuses: {
|
||||
characters_reserved_per_url: 0,
|
||||
max_characters: config.validation.max_note_size,
|
||||
max_characters: config.validation.notes.max_characters,
|
||||
max_media_attachments:
|
||||
config.validation.max_media_attachments,
|
||||
config.validation.notes.max_attachments,
|
||||
},
|
||||
media_attachments: {
|
||||
supported_mime_types: config.validation.allowed_mime_types,
|
||||
image_size_limit: config.validation.max_media_size,
|
||||
image_matrix_limit: config.validation.max_media_size,
|
||||
video_size_limit: config.validation.max_media_size,
|
||||
video_frame_rate_limit: config.validation.max_media_size,
|
||||
video_matrix_limit: config.validation.max_media_size,
|
||||
supported_mime_types:
|
||||
config.validation.media.allowed_mime_types,
|
||||
image_size_limit: config.validation.media.max_bytes,
|
||||
// TODO: Implement
|
||||
image_matrix_limit: 1 ** 10,
|
||||
video_size_limit: 1 ** 10,
|
||||
video_frame_rate_limit: 60,
|
||||
video_matrix_limit: 1 ** 10,
|
||||
},
|
||||
accounts: {
|
||||
max_featured_tags: 100,
|
||||
|
|
@ -101,23 +104,22 @@ export default apiRoute((app) =>
|
|||
},
|
||||
short_description: config.instance.description,
|
||||
description: content,
|
||||
// TODO: Add contact email
|
||||
email: "",
|
||||
email: config.instance.contact.email,
|
||||
invites_enabled: false,
|
||||
registrations: config.signups.registration,
|
||||
// TODO: Implement
|
||||
languages: ["en"],
|
||||
rules: config.signups.rules.map((r, index) => ({
|
||||
registrations: config.registration.allow,
|
||||
languages: config.instance.languages,
|
||||
rules: config.instance.rules.map((r, index) => ({
|
||||
id: String(index),
|
||||
text: r,
|
||||
text: r.text,
|
||||
hint: r.hint,
|
||||
})),
|
||||
stats: {
|
||||
domain_count: knownDomainsCount,
|
||||
status_count: statusCount,
|
||||
user_count: userCount,
|
||||
},
|
||||
thumbnail: config.instance.logo
|
||||
? proxyUrl(config.instance.logo).toString()
|
||||
thumbnail: config.instance.branding.logo
|
||||
? proxyUrl(config.instance.branding.logo).toString()
|
||||
: null,
|
||||
title: config.instance.name,
|
||||
uri: config.http.base_url.host,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ describe("/api/v1/instance/privacy_policy", () => {
|
|||
|
||||
const json = await response.json();
|
||||
expect(json).toEqual({
|
||||
updated_at: new Date(1970, 0, 0).toISOString(),
|
||||
updated_at: new Date(0).toISOString(),
|
||||
// This instance has not provided any privacy policy.
|
||||
content:
|
||||
"<p>This instance has not provided any privacy policy.</p>\n",
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { apiRoute, auth } from "@/api";
|
||||
import { renderMarkdownInPath } from "@/markdown";
|
||||
import { createRoute } from "@hono/zod-openapi";
|
||||
import { markdownParse } from "~/classes/functions/status";
|
||||
import { PrivacyPolicy as PrivacyPolicySchema } from "~/classes/schemas/privacy-policy";
|
||||
import { config } from "~/packages/config-manager";
|
||||
import { config } from "~/config.ts";
|
||||
|
||||
const route = createRoute({
|
||||
method: "get",
|
||||
|
|
@ -32,13 +32,15 @@ const route = createRoute({
|
|||
|
||||
export default apiRoute((app) =>
|
||||
app.openapi(route, async (context) => {
|
||||
const { content, lastModified } = await renderMarkdownInPath(
|
||||
config.instance.privacy_policy_path ?? "",
|
||||
"This instance has not provided any privacy policy.",
|
||||
const content = await markdownParse(
|
||||
config.instance.privacy_policy_path?.content ??
|
||||
"This instance has not provided any privacy policy.",
|
||||
);
|
||||
|
||||
return context.json({
|
||||
updated_at: lastModified.toISOString(),
|
||||
updated_at: new Date(
|
||||
config.instance.privacy_policy_path?.file.lastModified ?? 0,
|
||||
).toISOString(),
|
||||
content,
|
||||
});
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { describe, expect, test } from "bun:test";
|
||||
import { config } from "~/packages/config-manager/index.ts";
|
||||
import { config } from "~/config.ts";
|
||||
import { fakeRequest } from "~/tests/utils";
|
||||
|
||||
// /api/v1/instance/rules
|
||||
|
|
@ -11,10 +11,10 @@ describe("/api/v1/instance/rules", () => {
|
|||
|
||||
const json = await response.json();
|
||||
expect(json).toEqual(
|
||||
config.signups.rules.map((rule, index) => ({
|
||||
config.instance.rules.map((r, index) => ({
|
||||
id: String(index),
|
||||
text: rule,
|
||||
hint: "",
|
||||
text: r.text,
|
||||
hint: r.hint,
|
||||
})),
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { apiRoute, auth } from "@/api";
|
||||
import { createRoute, z } from "@hono/zod-openapi";
|
||||
import { Rule as RuleSchema } from "~/classes/schemas/rule";
|
||||
import { config } from "~/packages/config-manager";
|
||||
import { config } from "~/config.ts";
|
||||
|
||||
const route = createRoute({
|
||||
method: "get",
|
||||
|
|
@ -32,10 +32,10 @@ const route = createRoute({
|
|||
export default apiRoute((app) =>
|
||||
app.openapi(route, (context) => {
|
||||
return context.json(
|
||||
config.signups.rules.map((rule, index) => ({
|
||||
config.instance.rules.map((r, index) => ({
|
||||
id: String(index),
|
||||
text: rule,
|
||||
hint: "",
|
||||
text: r.text,
|
||||
hint: r.hint,
|
||||
})),
|
||||
);
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ describe("/api/v1/instance/terms_of_service", () => {
|
|||
|
||||
const json = await response.json();
|
||||
expect(json).toEqual({
|
||||
updated_at: new Date(1970, 0, 0).toISOString(),
|
||||
updated_at: new Date(0).toISOString(),
|
||||
// This instance has not provided any terms of service.
|
||||
content:
|
||||
"<p>This instance has not provided any terms of service.</p>\n",
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { apiRoute, auth } from "@/api";
|
||||
import { renderMarkdownInPath } from "@/markdown";
|
||||
import { createRoute } from "@hono/zod-openapi";
|
||||
import { markdownParse } from "~/classes/functions/status";
|
||||
import { TermsOfService as TermsOfServiceSchema } from "~/classes/schemas/tos";
|
||||
import { config } from "~/packages/config-manager";
|
||||
import { config } from "~/config.ts";
|
||||
|
||||
const route = createRoute({
|
||||
method: "get",
|
||||
|
|
@ -33,13 +33,15 @@ const route = createRoute({
|
|||
|
||||
export default apiRoute((app) =>
|
||||
app.openapi(route, async (context) => {
|
||||
const { content, lastModified } = await renderMarkdownInPath(
|
||||
config.instance.tos_path ?? "",
|
||||
"This instance has not provided any terms of service.",
|
||||
const content = await markdownParse(
|
||||
config.instance.tos_path?.content ??
|
||||
"This instance has not provided any terms of service.",
|
||||
);
|
||||
|
||||
return context.json({
|
||||
updated_at: lastModified.toISOString(),
|
||||
updated_at: new Date(
|
||||
config.instance.tos_path?.file.lastModified ?? 0,
|
||||
).toISOString(),
|
||||
content,
|
||||
});
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import { Timeline } from "@versia/kit/db";
|
|||
import { Notifications, RolePermissions } from "@versia/kit/tables";
|
||||
import { and, eq, gt, gte, inArray, lt, not, sql } from "drizzle-orm";
|
||||
import { Account as AccountSchema } from "~/classes/schemas/account";
|
||||
import { zBoolean } from "~/classes/schemas/common.ts";
|
||||
import { Notification as NotificationSchema } from "~/classes/schemas/notification.ts";
|
||||
import { zBoolean } from "~/packages/config-manager/config.type";
|
||||
|
||||
const route = createRoute({
|
||||
method: "get",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
||||
import { Role } from "@versia/kit/db";
|
||||
import { RolePermissions } from "@versia/kit/tables";
|
||||
import { config } from "~/packages/config-manager/index.ts";
|
||||
import { config } from "~/config.ts";
|
||||
import { fakeRequest, getTestUsers } from "~/tests/utils";
|
||||
|
||||
const { users, deleteUsers, tokens } = await getTestUsers(1);
|
||||
|
|
|
|||
|
|
@ -11,13 +11,13 @@ import { Media } from "@versia/kit/db";
|
|||
import { RolePermissions } from "@versia/kit/tables";
|
||||
import { ApiError } from "~/classes/errors/api-error";
|
||||
import { Attachment as AttachmentSchema } from "~/classes/schemas/attachment";
|
||||
import { zBoolean } from "~/classes/schemas/common.ts";
|
||||
import { PollOption } from "~/classes/schemas/poll";
|
||||
import {
|
||||
Status as StatusSchema,
|
||||
StatusSource as StatusSourceSchema,
|
||||
} from "~/classes/schemas/status";
|
||||
import { zBoolean } from "~/packages/config-manager/config.type";
|
||||
import { config } from "~/packages/config-manager/index.ts";
|
||||
import { config } from "~/config.ts";
|
||||
|
||||
const schema = z
|
||||
.object({
|
||||
|
|
@ -35,7 +35,7 @@ const schema = z
|
|||
}),
|
||||
media_ids: z
|
||||
.array(AttachmentSchema.shape.id)
|
||||
.max(config.validation.max_media_attachments)
|
||||
.max(config.validation.notes.max_attachments)
|
||||
.default([])
|
||||
.openapi({
|
||||
description:
|
||||
|
|
@ -51,7 +51,7 @@ const schema = z
|
|||
language: StatusSchema.shape.language.optional(),
|
||||
"poll[options]": z
|
||||
.array(PollOption.shape.title)
|
||||
.max(config.validation.max_poll_options)
|
||||
.max(config.validation.polls.max_options)
|
||||
.optional()
|
||||
.openapi({
|
||||
description:
|
||||
|
|
@ -60,8 +60,8 @@ const schema = z
|
|||
"poll[expires_in]": z.coerce
|
||||
.number()
|
||||
.int()
|
||||
.min(config.validation.min_poll_duration)
|
||||
.max(config.validation.max_poll_duration)
|
||||
.min(config.validation.polls.min_duration_seconds)
|
||||
.max(config.validation.polls.max_duration_seconds)
|
||||
.optional()
|
||||
.openapi({
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import type { Status as ApiStatus } from "@versia/client/types";
|
|||
import { Media, db } from "@versia/kit/db";
|
||||
import { Emojis } from "@versia/kit/tables";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { config } from "~/packages/config-manager/index.ts";
|
||||
import { config } from "~/config.ts";
|
||||
import { fakeRequest, getTestUsers } from "~/tests/utils";
|
||||
|
||||
const { users, tokens, deleteUsers } = await getTestUsers(5);
|
||||
|
|
@ -61,7 +61,7 @@ describe("/api/v1/statuses", () => {
|
|||
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||
},
|
||||
body: new URLSearchParams({
|
||||
status: "a".repeat(config.validation.max_note_size + 1),
|
||||
status: "a".repeat(config.validation.notes.max_characters + 1),
|
||||
local_only: "true",
|
||||
}),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@ import { Media, Note } from "@versia/kit/db";
|
|||
import { RolePermissions } from "@versia/kit/tables";
|
||||
import { ApiError } from "~/classes/errors/api-error";
|
||||
import { Attachment as AttachmentSchema } from "~/classes/schemas/attachment";
|
||||
import { zBoolean } from "~/classes/schemas/common.ts";
|
||||
import { PollOption } from "~/classes/schemas/poll";
|
||||
import {
|
||||
Status as StatusSchema,
|
||||
StatusSource as StatusSourceSchema,
|
||||
} from "~/classes/schemas/status";
|
||||
import { zBoolean } from "~/packages/config-manager/config.type";
|
||||
import { config } from "~/packages/config-manager/index.ts";
|
||||
import { config } from "~/config.ts";
|
||||
|
||||
const schema = z
|
||||
.object({
|
||||
|
|
@ -28,7 +28,7 @@ const schema = z
|
|||
}),
|
||||
media_ids: z
|
||||
.array(AttachmentSchema.shape.id)
|
||||
.max(config.validation.max_media_attachments)
|
||||
.max(config.validation.notes.max_attachments)
|
||||
.default([])
|
||||
.openapi({
|
||||
description:
|
||||
|
|
@ -44,7 +44,7 @@ const schema = z
|
|||
language: StatusSchema.shape.language.optional(),
|
||||
"poll[options]": z
|
||||
.array(PollOption.shape.title)
|
||||
.max(config.validation.max_poll_options)
|
||||
.max(config.validation.polls.max_options)
|
||||
.optional()
|
||||
.openapi({
|
||||
description:
|
||||
|
|
@ -53,8 +53,8 @@ const schema = z
|
|||
"poll[expires_in]": z.coerce
|
||||
.number()
|
||||
.int()
|
||||
.min(config.validation.min_poll_duration)
|
||||
.max(config.validation.max_poll_duration)
|
||||
.min(config.validation.polls.min_duration_seconds)
|
||||
.max(config.validation.polls.max_duration_seconds)
|
||||
.optional()
|
||||
.openapi({
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { afterAll, describe, expect, test } from "bun:test";
|
||||
import type { Status as ApiStatus } from "@versia/client/types";
|
||||
import { config } from "~/packages/config-manager/index.ts";
|
||||
import { config } from "~/config.ts";
|
||||
import { fakeRequest, getTestStatuses, getTestUsers } from "~/tests/utils";
|
||||
|
||||
const { users, tokens, deleteUsers } = await getTestUsers(5);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { afterAll, describe, expect, test } from "bun:test";
|
||||
import type { Status as ApiStatus } from "@versia/client/types";
|
||||
import { config } from "~/packages/config-manager/index.ts";
|
||||
import { config } from "~/config.ts";
|
||||
import { fakeRequest, getTestStatuses, getTestUsers } from "~/tests/utils";
|
||||
|
||||
const { users, tokens, deleteUsers } = await getTestUsers(5);
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ import { createRoute, z } from "@hono/zod-openapi";
|
|||
import { Timeline } from "@versia/kit/db";
|
||||
import { Notes, RolePermissions } from "@versia/kit/tables";
|
||||
import { and, eq, gt, gte, inArray, lt, or, sql } from "drizzle-orm";
|
||||
import { zBoolean } from "~/classes/schemas/common.ts";
|
||||
import { Status as StatusSchema } from "~/classes/schemas/status";
|
||||
import { zBoolean } from "~/packages/config-manager/config.type";
|
||||
|
||||
const route = createRoute({
|
||||
method: "get",
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ import { db } from "@versia/kit/db";
|
|||
import { FilterKeywords, Filters, RolePermissions } from "@versia/kit/tables";
|
||||
import { type SQL, and, eq, inArray } from "drizzle-orm";
|
||||
import { ApiError } from "~/classes/errors/api-error";
|
||||
import { zBoolean } from "~/classes/schemas/common.ts";
|
||||
import {
|
||||
FilterKeyword as FilterKeywordSchema,
|
||||
Filter as FilterSchema,
|
||||
} from "~/classes/schemas/filters";
|
||||
import { zBoolean } from "~/packages/config-manager/config.type";
|
||||
import { ErrorSchema } from "~/types/api";
|
||||
|
||||
const routeGet = createRoute({
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ import { User } from "@versia/kit/db";
|
|||
import { Users } from "@versia/kit/tables";
|
||||
import { and, eq, isNull } from "drizzle-orm";
|
||||
import { Instance as InstanceSchema } from "~/classes/schemas/instance";
|
||||
import { config } from "~/config.ts";
|
||||
import pkg from "~/package.json";
|
||||
import { config } from "~/packages/config-manager";
|
||||
|
||||
const route = createRoute({
|
||||
method: "get",
|
||||
|
|
@ -69,92 +69,99 @@ export default apiRoute((app) =>
|
|||
mastodon: 1,
|
||||
},
|
||||
thumbnail: {
|
||||
url: config.instance.logo
|
||||
? proxyUrl(config.instance.logo).toString()
|
||||
url: config.instance.branding.logo
|
||||
? proxyUrl(config.instance.branding.logo).toString()
|
||||
: pkg.icon,
|
||||
},
|
||||
banner: {
|
||||
url: config.instance.banner
|
||||
? proxyUrl(config.instance.banner).toString()
|
||||
url: config.instance.branding.banner
|
||||
? proxyUrl(config.instance.branding.banner).toString()
|
||||
: null,
|
||||
},
|
||||
icon: [],
|
||||
languages: ["en"],
|
||||
languages: config.instance.languages,
|
||||
configuration: {
|
||||
urls: {
|
||||
// TODO: Implement Streaming API
|
||||
streaming: "",
|
||||
},
|
||||
vapid: {
|
||||
// TODO: Fill in vapid values
|
||||
public_key: "",
|
||||
public_key:
|
||||
config.notifications.push?.vapid_keys.public ?? "",
|
||||
},
|
||||
accounts: {
|
||||
max_featured_tags: 100,
|
||||
max_displayname_characters:
|
||||
config.validation.max_displayname_size,
|
||||
avatar_limit: config.validation.max_avatar_size,
|
||||
header_limit: config.validation.max_header_size,
|
||||
config.validation.accounts.max_displayname_characters,
|
||||
avatar_limit: config.validation.accounts.max_avatar_bytes,
|
||||
header_limit: config.validation.accounts.max_header_bytes,
|
||||
max_username_characters:
|
||||
config.validation.max_username_size,
|
||||
max_note_characters: config.validation.max_bio_size,
|
||||
max_pinned_statuses: 100,
|
||||
config.validation.accounts.max_username_characters,
|
||||
max_note_characters:
|
||||
config.validation.accounts.max_bio_characters,
|
||||
max_pinned_statuses:
|
||||
config.validation.accounts.max_pinned_notes,
|
||||
fields: {
|
||||
max_fields: config.validation.max_field_count,
|
||||
max_fields: config.validation.accounts.max_field_count,
|
||||
max_name_characters:
|
||||
config.validation.max_field_name_size,
|
||||
config.validation.accounts
|
||||
.max_field_name_characters,
|
||||
max_value_characters:
|
||||
config.validation.max_field_value_size,
|
||||
config.validation.accounts
|
||||
.max_field_value_characters,
|
||||
},
|
||||
},
|
||||
statuses: {
|
||||
max_characters: config.validation.max_note_size,
|
||||
max_characters: config.validation.notes.max_characters,
|
||||
max_media_attachments:
|
||||
config.validation.max_media_attachments,
|
||||
characters_reserved_per_url: 0,
|
||||
config.validation.notes.max_attachments,
|
||||
// TODO: Implement
|
||||
characters_reserved_per_url: 13,
|
||||
},
|
||||
media_attachments: {
|
||||
supported_mime_types: config.validation.allowed_mime_types,
|
||||
image_size_limit: config.validation.max_media_size,
|
||||
image_matrix_limit: config.validation.max_media_size,
|
||||
video_size_limit: config.validation.max_media_size,
|
||||
video_frame_rate_limit: config.validation.max_media_size,
|
||||
video_matrix_limit: config.validation.max_media_size,
|
||||
supported_mime_types:
|
||||
config.validation.media.allowed_mime_types,
|
||||
image_size_limit: config.validation.media.max_bytes,
|
||||
image_matrix_limit: 1 ** 10,
|
||||
video_size_limit: 1 ** 10,
|
||||
video_frame_rate_limit: 60,
|
||||
video_matrix_limit: 1 ** 10,
|
||||
description_limit:
|
||||
config.validation.max_media_description_size,
|
||||
config.validation.media.max_description_characters,
|
||||
},
|
||||
emojis: {
|
||||
emoji_size_limit: config.validation.max_emoji_size,
|
||||
emoji_size_limit: config.validation.emojis.max_bytes,
|
||||
max_shortcode_characters:
|
||||
config.validation.max_emoji_shortcode_size,
|
||||
config.validation.emojis.max_shortcode_characters,
|
||||
max_description_characters:
|
||||
config.validation.max_emoji_description_size,
|
||||
config.validation.emojis.max_description_characters,
|
||||
},
|
||||
polls: {
|
||||
max_characters_per_option:
|
||||
config.validation.max_poll_option_size,
|
||||
max_expiration: config.validation.max_poll_duration,
|
||||
max_options: config.validation.max_poll_options,
|
||||
min_expiration: config.validation.min_poll_duration,
|
||||
config.validation.polls.max_option_characters,
|
||||
max_expiration:
|
||||
config.validation.polls.max_duration_seconds,
|
||||
max_options: config.validation.polls.max_options,
|
||||
min_expiration:
|
||||
config.validation.polls.min_duration_seconds,
|
||||
},
|
||||
translation: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
registrations: {
|
||||
enabled: config.signups.registration,
|
||||
approval_required: false,
|
||||
message: null,
|
||||
enabled: config.registration.allow,
|
||||
approval_required: config.registration.require_approval,
|
||||
message: config.registration.message ?? null,
|
||||
},
|
||||
contact: {
|
||||
// TODO: Add contact email
|
||||
email: "",
|
||||
email: config.instance.contact.email,
|
||||
account: (contactAccount as User)?.toApi(),
|
||||
},
|
||||
rules: config.signups.rules.map((rule, index) => ({
|
||||
rules: config.instance.rules.map((r, index) => ({
|
||||
id: String(index),
|
||||
text: rule,
|
||||
hint: "",
|
||||
text: r.text,
|
||||
hint: r.hint,
|
||||
})),
|
||||
sso: {
|
||||
forced: oidcConfig?.forced ?? false,
|
||||
|
|
|
|||
|
|
@ -12,10 +12,10 @@ import { and, eq, inArray, isNull, sql } from "drizzle-orm";
|
|||
import { ApiError } from "~/classes/errors/api-error";
|
||||
import { Account as AccountSchema } from "~/classes/schemas/account";
|
||||
import { Id } from "~/classes/schemas/common";
|
||||
import { zBoolean } from "~/classes/schemas/common.ts";
|
||||
import { Search as SearchSchema } from "~/classes/schemas/search";
|
||||
import { searchManager } from "~/classes/search/search-manager";
|
||||
import { config } from "~/packages/config-manager";
|
||||
import { zBoolean } from "~/packages/config-manager/config.type";
|
||||
import { config } from "~/config.ts";
|
||||
import { ErrorSchema } from "~/types/api";
|
||||
|
||||
const route = createRoute({
|
||||
|
|
@ -133,7 +133,7 @@ export default apiRoute((app) =>
|
|||
);
|
||||
}
|
||||
|
||||
if (!config.sonic.enabled) {
|
||||
if (!config.search.enabled) {
|
||||
throw new ApiError(501, "Search is not enabled on this server");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { createRoute, z } from "@hono/zod-openapi";
|
|||
import { proxy } from "hono/proxy";
|
||||
import type { ContentfulStatusCode, StatusCode } from "hono/utils/http-status";
|
||||
import { ApiError } from "~/classes/errors/api-error";
|
||||
import { config } from "~/packages/config-manager";
|
||||
import { config } from "~/config.ts";
|
||||
import { ErrorSchema } from "~/types/api";
|
||||
|
||||
const schemas = {
|
||||
|
|
@ -56,7 +56,7 @@ export default apiRoute((app) =>
|
|||
|
||||
const media = await proxy(id, {
|
||||
// @ts-expect-error Proxy is a Bun-specific feature
|
||||
proxy: config.http.proxy.address,
|
||||
proxy: config.http.proxy_address,
|
||||
});
|
||||
|
||||
// Check if file extension ends in svg or svg
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { Like, Note, User } from "@versia/kit/db";
|
|||
import { Likes, Notes } from "@versia/kit/tables";
|
||||
import { and, eq, inArray, sql } from "drizzle-orm";
|
||||
import { ApiError } from "~/classes/errors/api-error";
|
||||
import { config } from "~/packages/config-manager";
|
||||
import { config } from "~/config.ts";
|
||||
import { ErrorSchema, type KnownEntity } from "~/types/api";
|
||||
|
||||
const route = createRoute({
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { Note, User, db } from "@versia/kit/db";
|
|||
import { Notes } from "@versia/kit/tables";
|
||||
import { and, eq, inArray } from "drizzle-orm";
|
||||
import { ApiError } from "~/classes/errors/api-error";
|
||||
import { config } from "~/packages/config-manager";
|
||||
import { config } from "~/config.ts";
|
||||
import { ErrorSchema } from "~/types/api";
|
||||
|
||||
const schemas = {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { apiRoute } from "@/api";
|
||||
import { createRoute, z } from "@hono/zod-openapi";
|
||||
import { config } from "~/packages/config-manager";
|
||||
import { config } from "~/config.ts";
|
||||
|
||||
const route = createRoute({
|
||||
method: "get",
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { apiRoute } from "@/api";
|
||||
import { createRoute, z } from "@hono/zod-openapi";
|
||||
import { Note, User } from "@versia/kit/db";
|
||||
import { config } from "~/config.ts";
|
||||
import manifest from "~/package.json";
|
||||
import { config } from "~/packages/config-manager";
|
||||
|
||||
const route = createRoute({
|
||||
method: "get",
|
||||
|
|
@ -65,7 +65,7 @@ export default apiRoute((app) =>
|
|||
},
|
||||
localPosts: noteCount,
|
||||
},
|
||||
openRegistrations: config.signups.registration,
|
||||
openRegistrations: config.registration.allow,
|
||||
metadata: {
|
||||
nodeName: config.instance.name,
|
||||
nodeDescription: config.instance.description,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { apiRoute } from "@/api";
|
||||
import { createRoute, z } from "@hono/zod-openapi";
|
||||
import { config } from "~/packages/config-manager";
|
||||
import { config } from "~/config.ts";
|
||||
|
||||
const route = createRoute({
|
||||
method: "get",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { apiRoute } from "@/api";
|
||||
import { createRoute, z } from "@hono/zod-openapi";
|
||||
import { config } from "~/packages/config-manager";
|
||||
import { config } from "~/config.ts";
|
||||
|
||||
const route = createRoute({
|
||||
method: "get",
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ import { InstanceMetadata as InstanceMetadataSchema } from "@versia/federation/s
|
|||
import { User } from "@versia/kit/db";
|
||||
import { Users } from "@versia/kit/tables";
|
||||
import { asc } from "drizzle-orm";
|
||||
import { config } from "~/config.ts";
|
||||
import pkg from "~/package.json";
|
||||
import { config } from "~/packages/config-manager";
|
||||
|
||||
const route = createRoute({
|
||||
method: "get",
|
||||
|
|
@ -29,6 +29,10 @@ export default apiRoute((app) =>
|
|||
// Get date of first user creation
|
||||
const firstUser = await User.fromSql(undefined, asc(Users.createdAt));
|
||||
|
||||
const publicKey = Buffer.from(
|
||||
await crypto.subtle.exportKey("spki", config.instance.keys.public),
|
||||
).toString("base64");
|
||||
|
||||
return context.json(
|
||||
{
|
||||
type: "InstanceMetadata" as const,
|
||||
|
|
@ -43,18 +47,18 @@ export default apiRoute((app) =>
|
|||
name: config.instance.name,
|
||||
description: config.instance.description,
|
||||
public_key: {
|
||||
key: config.instance.keys.public,
|
||||
key: publicKey,
|
||||
algorithm: "ed25519" as const,
|
||||
},
|
||||
software: {
|
||||
name: "Versia Server",
|
||||
version: pkg.version,
|
||||
},
|
||||
banner: config.instance.banner
|
||||
? urlToContentFormat(config.instance.banner)
|
||||
banner: config.instance.branding.banner
|
||||
? urlToContentFormat(config.instance.branding.banner)
|
||||
: undefined,
|
||||
logo: config.instance.logo
|
||||
? urlToContentFormat(config.instance.logo)
|
||||
logo: config.instance.branding.logo
|
||||
? urlToContentFormat(config.instance.branding.logo)
|
||||
: undefined,
|
||||
shared_inbox: new URL(
|
||||
"/inbox",
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import { User } from "@versia/kit/db";
|
|||
import { Users } from "@versia/kit/tables";
|
||||
import { and, eq, isNull } from "drizzle-orm";
|
||||
import { ApiError } from "~/classes/errors/api-error";
|
||||
import { config } from "~/packages/config-manager";
|
||||
import { config } from "~/config.ts";
|
||||
import { ErrorSchema } from "~/types/api";
|
||||
|
||||
const schemas = {
|
||||
|
|
@ -90,7 +90,7 @@ export default apiRoute((app) =>
|
|||
|
||||
let activityPubUrl = "";
|
||||
|
||||
if (config.federation.bridge.enabled) {
|
||||
if (config.federation.bridge) {
|
||||
const manager = await User.getFederationRequester();
|
||||
|
||||
try {
|
||||
|
|
@ -98,7 +98,7 @@ export default apiRoute((app) =>
|
|||
user.data.username,
|
||||
config.http.base_url.host,
|
||||
"application/activity+json",
|
||||
config.federation.bridge.url?.toString(),
|
||||
config.federation.bridge.url.origin,
|
||||
);
|
||||
} catch (e) {
|
||||
const error = e as ResponseError;
|
||||
|
|
@ -136,7 +136,7 @@ export default apiRoute((app) =>
|
|||
type:
|
||||
user.avatar?.getPreferredMimeType() ??
|
||||
"image/svg+xml",
|
||||
href: user.getAvatarUrl(config),
|
||||
href: user.getAvatarUrl(),
|
||||
},
|
||||
].filter(Boolean) as {
|
||||
rel: string;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue