refactor(api): ♻️ Serve frontend from static files instead of proxying another process

This commit is contained in:
Jesse Wierzbinski 2025-03-27 18:51:22 +01:00
parent 5f8c57b3e1
commit 58b4d7454f
No known key found for this signature in database
8 changed files with 133 additions and 107 deletions

View file

@ -89,8 +89,11 @@ banned_user_agents = [
# Enable custom frontends (warning: not enabling this will make Versia Server only accessible via the Mastodon API) # Enable custom frontends (warning: not enabling this will make Versia Server only accessible via the Mastodon API)
# Frontends also control the OpenID flow, so if you disable this, you will need to use the Mastodon frontend # Frontends also control the OpenID flow, so if you disable this, you will need to use the Mastodon frontend
enabled = true enabled = true
# The URL to reach the frontend at (should be on a local network) # Path that frontend files are served from
url = "http://localhost:3000" # Edit this property to serve custom frontends
# If this is not set, Versia Server will also check
# the VERSIA_FRONTEND_PATH environment variable
# path = ""
[frontend.routes] [frontend.routes]
# Special routes for your frontend, below are the defaults for Versia-FE # Special routes for your frontend, below are the defaults for Versia-FE

54
app.ts
View file

@ -9,6 +9,7 @@ import { getLogger } from "@logtape/logtape";
import { apiReference } from "@scalar/hono-api-reference"; import { apiReference } from "@scalar/hono-api-reference";
import { inspect } from "bun"; import { inspect } from "bun";
import chalk from "chalk"; import chalk from "chalk";
import { serveStatic } from "hono/bun";
import { cors } from "hono/cors"; import { cors } from "hono/cors";
import { createMiddleware } from "hono/factory"; import { createMiddleware } from "hono/factory";
import { prettyJSON } from "hono/pretty-json"; import { prettyJSON } from "hono/pretty-json";
@ -163,49 +164,20 @@ export const appFactory = async (): Promise<OpenAPIHono<HonoEnv>> => {
return context.body(null, 204); return context.body(null, 204);
}); });
app.all("*", async (context) => { app.all(
const replacedUrl = new URL( "*",
new URL(context.req.url).pathname, serveStatic({
config.frontend.url, root: config.frontend.path,
).toString(); }),
serverLogger.debug`Proxying ${replacedUrl}`;
const proxy = await fetch(replacedUrl, {
headers: {
// Include for SSR
"X-Forwarded-Host": `${config.http.bind}:${config.http.bind_port}`,
"Accept-Encoding": "identity",
},
redirect: "manual",
}).catch((e) => {
serverLogger.error`${e}`;
sentry?.captureException(e);
serverLogger.error`The Frontend is not running or the route is not found: ${replacedUrl}`;
return null;
});
proxy?.headers.set("Cache-Control", "max-age=31536000");
if (!proxy || proxy.status === 404) {
throw new ApiError(
404,
"Route not found on proxy or API route. Are you using the correct HTTP method?",
); );
} // Fallback for SPAs, in case we've hit a route that is client-side
app.all(
// Disable CSP upgrade-insecure-requests if an .onion domain is used "*",
if (new URL(context.req.url).hostname.endsWith(".onion")) { serveStatic({
proxy.headers.set( root: config.frontend.path,
"Content-Security-Policy", path: "index.html",
proxy.headers }),
.get("Content-Security-Policy")
?.replace("upgrade-insecure-requests;", "") ?? "",
); );
}
return proxy;
});
app.onError((error, c) => { app.onError((error, c) => {
if (error instanceof ApiError) { if (error instanceof ApiError) {

View file

@ -1,5 +1,6 @@
import { cwd } from "node:process";
import { z } from "@hono/zod-openapi"; import { z } from "@hono/zod-openapi";
import { type BunFile, file } from "bun"; import { type BunFile, env, file } from "bun";
import ISO6391 from "iso-639-1"; import ISO6391 from "iso-639-1";
import { types as mimeTypes } from "mime-types"; import { types as mimeTypes } from "mime-types";
import { generateVAPIDKeys } from "web-push"; import { generateVAPIDKeys } from "web-push";
@ -400,7 +401,7 @@ export const ConfigSchema = z
}), }),
frontend: z.strictObject({ frontend: z.strictObject({
enabled: z.boolean().default(true), enabled: z.boolean().default(true),
url: url.default("http://localhost:3000"), path: z.string().default(env.VERSIA_FRONTEND_PATH || cwd()),
routes: z.strictObject({ routes: z.strictObject({
home: urlPath.default("/"), home: urlPath.default("/"),
login: urlPath.default("/oauth/authorize"), login: urlPath.default("/oauth/authorize"),

View file

@ -89,8 +89,11 @@ banned_user_agents = [
# Enable custom frontends (warning: not enabling this will make Versia Server only accessible via the Mastodon API) # Enable custom frontends (warning: not enabling this will make Versia Server only accessible via the Mastodon API)
# Frontends also control the OpenID flow, so if you disable this, you will need to use the Mastodon frontend # Frontends also control the OpenID flow, so if you disable this, you will need to use the Mastodon frontend
enabled = true enabled = true
# The URL to reach the frontend at (should be on a local network) # Path that frontend files are served from
url = "http://localhost:3000" # Edit this property to serve custom frontends
# If this is not set, Versia Server will also check
# the VERSIA_FRONTEND_PATH environment variable
# path = ""
[frontend.routes] [frontend.routes]
# Special routes for your frontend, below are the defaults for Versia-FE # Special routes for your frontend, below are the defaults for Versia-FE

View file

@ -273,9 +273,9 @@
"type": "boolean", "type": "boolean",
"default": true "default": true
}, },
"url": { "path": {
"$ref": "#/properties/http/properties/proxy_address", "type": "string",
"default": "http://localhost:3000" "default": "/home/jessew/Dev/versia-server"
}, },
"routes": { "routes": {
"type": "object", "type": "object",
@ -317,7 +317,7 @@
"default": {} "default": {}
} }
}, },
"required": ["enabled", "url", "routes", "settings"], "required": ["enabled", "path", "routes", "settings"],
"additionalProperties": false "additionalProperties": false
}, },
"email": { "email": {
@ -597,8 +597,12 @@
}, },
"default": [ "default": [
"application/vnd.lotus-1-2-3", "application/vnd.lotus-1-2-3",
"model/step",
"application/andrew-inset", "application/andrew-inset",
"application/appinstaller",
"application/applixware", "application/applixware",
"application/appx",
"application/appxbundle",
"application/atom+xml", "application/atom+xml",
"application/atomcat+xml", "application/atomcat+xml",
"application/atomdeleted+xml", "application/atomdeleted+xml",
@ -606,6 +610,8 @@
"application/atsc-dwd+xml", "application/atsc-dwd+xml",
"application/atsc-held+xml", "application/atsc-held+xml",
"application/atsc-rsat+xml", "application/atsc-rsat+xml",
"application/automationml-aml+xml",
"application/automationml-amlx+zip",
"application/bdoc", "application/bdoc",
"application/calendar+xml", "application/calendar+xml",
"application/ccxml+xml", "application/ccxml+xml",
@ -617,19 +623,21 @@
"application/cdmi-queue", "application/cdmi-queue",
"application/cpl+xml", "application/cpl+xml",
"application/cu-seeme", "application/cu-seeme",
"application/cwl",
"application/dash+xml", "application/dash+xml",
"application/dash-patch+xml", "application/dash-patch+xml",
"application/davmount+xml", "application/davmount+xml",
"application/dicom",
"application/docbook+xml", "application/docbook+xml",
"application/dssc+der", "application/dssc+der",
"application/dssc+xml", "application/dssc+xml",
"application/ecmascript", "application/ecmascript",
"application/ecmascript",
"application/emma+xml", "application/emma+xml",
"application/emotionml+xml", "application/emotionml+xml",
"application/epub+zip", "application/epub+zip",
"application/exi", "application/exi",
"application/express", "application/express",
"application/fdf",
"application/fdt+xml", "application/fdt+xml",
"application/font-tdpfr", "application/font-tdpfr",
"application/geo+json", "application/geo+json",
@ -648,8 +656,7 @@
"application/java-archive", "application/java-archive",
"application/java-serialized-object", "application/java-serialized-object",
"application/java-vm", "application/java-vm",
"application/javascript", "text/javascript",
"application/javascript",
"application/json", "application/json",
"application/json", "application/json",
"application/json5", "application/json5",
@ -680,6 +687,10 @@
"application/mp21", "application/mp21",
"application/mp4", "application/mp4",
"application/mp4", "application/mp4",
"application/mp4",
"application/mp4",
"application/msix",
"application/msixbundle",
"application/msword", "application/msword",
"application/msword", "application/msword",
"application/mxf", "application/mxf",
@ -716,6 +727,8 @@
"application/onenote", "application/onenote",
"application/onenote", "application/onenote",
"application/onenote", "application/onenote",
"application/onenote",
"application/onenote",
"application/oxps", "application/oxps",
"application/p2p-overlay+xml", "application/p2p-overlay+xml",
"application/patch-ops-error+xml", "application/patch-ops-error+xml",
@ -740,6 +753,7 @@
"application/postscript", "application/postscript",
"application/provenance+xml", "application/provenance+xml",
"application/prs.cww", "application/prs.cww",
"application/prs.xsf+xml",
"application/pskc+xml", "application/pskc+xml",
"application/raml+yaml", "application/raml+yaml",
"application/rdf+xml", "application/rdf+xml",
@ -775,6 +789,7 @@
"application/smil+xml", "application/smil+xml",
"application/sparql-query", "application/sparql-query",
"application/sparql-results+xml", "application/sparql-results+xml",
"application/sql",
"application/srgs", "application/srgs",
"application/srgs+xml", "application/srgs+xml",
"application/sru+xml", "application/sru+xml",
@ -807,7 +822,7 @@
"application/vnd.adobe.fxp", "application/vnd.adobe.fxp",
"application/vnd.adobe.fxp", "application/vnd.adobe.fxp",
"application/vnd.adobe.xdp+xml", "application/vnd.adobe.xdp+xml",
"application/vnd.adobe.xfdf", "application/xfdf",
"application/vnd.age", "application/vnd.age",
"application/vnd.ahead.space", "application/vnd.ahead.space",
"application/vnd.airzip.filesecure.azf", "application/vnd.airzip.filesecure.azf",
@ -828,6 +843,7 @@
"application/vnd.aristanetworks.swi", "application/vnd.aristanetworks.swi",
"application/vnd.astraea-software.iota", "application/vnd.astraea-software.iota",
"application/vnd.audiograph", "application/vnd.audiograph",
"application/vnd.autodesk.fbx",
"application/vnd.balsamiq.bmml+xml", "application/vnd.balsamiq.bmml+xml",
"application/vnd.blueice.multipass", "application/vnd.blueice.multipass",
"application/vnd.bmi", "application/vnd.bmi",
@ -861,6 +877,7 @@
"application/vnd.dart", "application/vnd.dart",
"application/vnd.data-vision.rdz", "application/vnd.data-vision.rdz",
"application/vnd.dbf", "application/vnd.dbf",
"application/vnd.dcmp+xml",
"application/vnd.dece.data", "application/vnd.dece.data",
"application/vnd.dece.data", "application/vnd.dece.data",
"application/vnd.dece.data", "application/vnd.dece.data",
@ -891,7 +908,6 @@
"application/vnd.eszigno3+xml", "application/vnd.eszigno3+xml",
"application/vnd.ezpix-album", "application/vnd.ezpix-album",
"application/vnd.ezpix-package", "application/vnd.ezpix-package",
"application/vnd.fdf",
"application/vnd.fdsn.mseed", "application/vnd.fdsn.mseed",
"application/vnd.fdsn.seed", "application/vnd.fdsn.seed",
"application/vnd.fdsn.seed", "application/vnd.fdsn.seed",
@ -915,6 +931,7 @@
"application/vnd.fuzzysheet", "application/vnd.fuzzysheet",
"application/vnd.genomatix.tuxedo", "application/vnd.genomatix.tuxedo",
"application/vnd.geogebra.file", "application/vnd.geogebra.file",
"application/vnd.geogebra.slides",
"application/vnd.geogebra.tool", "application/vnd.geogebra.tool",
"application/vnd.geometry-explorer", "application/vnd.geometry-explorer",
"application/vnd.geometry-explorer", "application/vnd.geometry-explorer",
@ -923,10 +940,17 @@
"application/vnd.geospace", "application/vnd.geospace",
"application/vnd.gmx", "application/vnd.gmx",
"application/vnd.google-apps.document", "application/vnd.google-apps.document",
"application/vnd.google-apps.drawing",
"application/vnd.google-apps.form",
"application/vnd.google-apps.jam",
"application/vnd.google-apps.map",
"application/vnd.google-apps.presentation", "application/vnd.google-apps.presentation",
"application/vnd.google-apps.script",
"application/vnd.google-apps.site",
"application/vnd.google-apps.spreadsheet", "application/vnd.google-apps.spreadsheet",
"application/vnd.google-earth.kml+xml", "application/vnd.google-earth.kml+xml",
"application/vnd.google-earth.kmz", "application/vnd.google-earth.kmz",
"application/vnd.gov.sk.xmldatacontainer+xml",
"application/vnd.grafeq", "application/vnd.grafeq",
"application/vnd.grafeq", "application/vnd.grafeq",
"application/vnd.groove-account", "application/vnd.groove-account",
@ -1051,6 +1075,7 @@
"application/vnd.ms-powerpoint.slideshow.macroenabled.12", "application/vnd.ms-powerpoint.slideshow.macroenabled.12",
"application/vnd.ms-powerpoint.template.macroenabled.12", "application/vnd.ms-powerpoint.template.macroenabled.12",
"application/vnd.ms-project", "application/vnd.ms-project",
"application/vnd.ms-visio.viewer",
"application/vnd.ms-word.document.macroenabled.12", "application/vnd.ms-word.document.macroenabled.12",
"application/vnd.ms-word.template.macroenabled.12", "application/vnd.ms-word.template.macroenabled.12",
"application/vnd.ms-works", "application/vnd.ms-works",
@ -1063,6 +1088,7 @@
"application/vnd.musician", "application/vnd.musician",
"application/vnd.muvee.style", "application/vnd.muvee.style",
"application/vnd.mynfc", "application/vnd.mynfc",
"application/vnd.nato.bindingdataobject+xml",
"application/vnd.neurolanguage.nlu", "application/vnd.neurolanguage.nlu",
"application/vnd.nitf", "application/vnd.nitf",
"application/vnd.nitf", "application/vnd.nitf",
@ -1120,9 +1146,13 @@
"application/vnd.pocketlearn", "application/vnd.pocketlearn",
"application/vnd.powerbuilder6", "application/vnd.powerbuilder6",
"application/vnd.previewsystems.box", "application/vnd.previewsystems.box",
"application/vnd.procrate.brushset",
"application/vnd.procreate.brush",
"application/vnd.procreate.dream",
"application/vnd.proteus.magazine", "application/vnd.proteus.magazine",
"application/vnd.publishare-delta-tree", "application/vnd.publishare-delta-tree",
"application/vnd.pvi.ptid1", "application/vnd.pvi.ptid1",
"application/vnd.pwg-xhtml-print+xml",
"application/vnd.quark.quarkxpress", "application/vnd.quark.quarkxpress",
"application/vnd.quark.quarkxpress", "application/vnd.quark.quarkxpress",
"application/vnd.quark.quarkxpress", "application/vnd.quark.quarkxpress",
@ -1199,11 +1229,14 @@
"application/vnd.umajin", "application/vnd.umajin",
"application/vnd.unity", "application/vnd.unity",
"application/vnd.uoml+xml", "application/vnd.uoml+xml",
"application/vnd.uoml+xml",
"application/vnd.vcx", "application/vnd.vcx",
"application/vnd.visio", "application/vnd.visio",
"application/vnd.visio", "application/vnd.visio",
"application/vnd.visio", "application/vnd.visio",
"application/vnd.visio", "application/vnd.visio",
"application/vnd.visio",
"application/vnd.visio",
"application/vnd.visionary", "application/vnd.visionary",
"application/vnd.vsf", "application/vnd.vsf",
"application/vnd.wap.wbxml", "application/vnd.wap.wbxml",
@ -1246,6 +1279,7 @@
"application/x-authorware-seg", "application/x-authorware-seg",
"application/x-bcpio", "application/x-bcpio",
"application/x-bittorrent", "application/x-bittorrent",
"application/x-blender",
"application/x-blorb", "application/x-blorb",
"application/x-blorb", "application/x-blorb",
"application/x-bzip", "application/x-bzip",
@ -1302,6 +1336,7 @@
"application/x-hdf", "application/x-hdf",
"application/x-httpd-php", "application/x-httpd-php",
"application/x-install-instructions", "application/x-install-instructions",
"application/x-ipynb+json",
"application/x-java-archive-diff", "application/x-java-archive-diff",
"application/x-java-jnlp-file", "application/x-java-jnlp-file",
"application/x-keepass2", "application/x-keepass2",
@ -1311,7 +1346,7 @@
"application/x-lzh-compressed", "application/x-lzh-compressed",
"application/x-makeself", "application/x-makeself",
"application/x-mie", "application/x-mie",
"application/x-mobipocket-ebook", "model/prc",
"application/x-mobipocket-ebook", "application/x-mobipocket-ebook",
"application/x-ms-application", "application/x-ms-application",
"application/x-ms-shortcut", "application/x-ms-shortcut",
@ -1353,7 +1388,6 @@
"application/x-shar", "application/x-shar",
"application/x-shockwave-flash", "application/x-shockwave-flash",
"application/x-silverlight-app", "application/x-silverlight-app",
"application/x-sql",
"application/x-stuffit", "application/x-stuffit",
"application/x-stuffitx", "application/x-stuffitx",
"application/x-subrip", "application/x-subrip",
@ -1387,6 +1421,7 @@
"application/xliff+xml", "application/xliff+xml",
"application/x-xpinstall", "application/x-xpinstall",
"application/x-xz", "application/x-xz",
"application/zip",
"application/x-zmachine", "application/x-zmachine",
"application/x-zmachine", "application/x-zmachine",
"application/x-zmachine", "application/x-zmachine",
@ -1419,8 +1454,10 @@
"application/xv+xml", "application/xv+xml",
"application/yang", "application/yang",
"application/yin+xml", "application/yin+xml",
"application/zip", "application/zip+dotlottie",
"video/3gpp", "video/3gpp",
"audio/aac",
"audio/aac",
"audio/adpcm", "audio/adpcm",
"audio/amr", "audio/amr",
"audio/basic", "audio/basic",
@ -1433,6 +1470,7 @@
"audio/mpeg", "audio/mpeg",
"audio/mp4", "audio/mp4",
"audio/mp4", "audio/mp4",
"audio/mp4",
"audio/mpeg", "audio/mpeg",
"audio/mpeg", "audio/mpeg",
"audio/mpeg", "audio/mpeg",
@ -1456,9 +1494,8 @@
"audio/vnd.nuera.ecelp7470", "audio/vnd.nuera.ecelp7470",
"audio/vnd.nuera.ecelp9600", "audio/vnd.nuera.ecelp9600",
"audio/vnd.rip", "audio/vnd.rip",
"audio/wave", "audio/wav",
"audio/webm", "audio/webm",
"audio/x-aac",
"audio/x-aiff", "audio/x-aiff",
"audio/x-aiff", "audio/x-aiff",
"audio/x-aiff", "audio/x-aiff",
@ -1489,8 +1526,10 @@
"image/avcs", "image/avcs",
"image/avif", "image/avif",
"image/bmp", "image/bmp",
"image/bmp",
"image/cgm", "image/cgm",
"image/dicom-rle", "image/dicom-rle",
"image/dpx",
"image/fits", "image/fits",
"image/g3fax", "image/g3fax",
"image/gif", "image/gif",
@ -1499,8 +1538,9 @@
"image/heif", "image/heif",
"image/heif-sequence", "image/heif-sequence",
"image/hej2k", "image/hej2k",
"image/hsj2",
"image/ief", "image/ief",
"image/jaii",
"image/jais",
"image/jls", "image/jls",
"image/jp2", "image/jp2",
"image/jp2", "image/jp2",
@ -1510,8 +1550,10 @@
"image/jph", "image/jph",
"image/jphc", "image/jphc",
"image/jpm", "image/jpm",
"image/jpm",
"image/jpx", "image/jpx",
"image/jpx", "image/jpx",
"image/jxl",
"image/jxr", "image/jxr",
"image/jxra", "image/jxra",
"image/jxrs", "image/jxrs",
@ -1521,8 +1563,10 @@
"image/jxss", "image/jxss",
"image/ktx", "image/ktx",
"image/ktx2", "image/ktx2",
"image/pjpeg",
"image/png", "image/png",
"image/prs.btif", "image/prs.btif",
"image/prs.btif",
"image/prs.pti", "image/prs.pti",
"image/sgi", "image/sgi",
"image/svg+xml", "image/svg+xml",
@ -1560,6 +1604,7 @@
"image/vnd.zbrush.pcx", "image/vnd.zbrush.pcx",
"image/webp", "image/webp",
"image/x-3ds", "image/x-3ds",
"image/x-adobe-dng",
"image/x-cmu-raster", "image/x-cmu-raster",
"image/x-cmx", "image/x-cmx",
"image/x-freehand", "image/x-freehand",
@ -1587,28 +1632,41 @@
"message/global-headers", "message/global-headers",
"message/rfc822", "message/rfc822",
"message/rfc822", "message/rfc822",
"message/rfc822",
"message/rfc822",
"message/vnd.wfa.wsc", "message/vnd.wfa.wsc",
"model/3mf", "model/3mf",
"model/gltf+json", "model/gltf+json",
"model/gltf-binary", "model/gltf-binary",
"model/iges", "model/iges",
"model/iges", "model/iges",
"model/jt",
"model/mesh", "model/mesh",
"model/mesh", "model/mesh",
"model/mesh", "model/mesh",
"model/mtl", "model/mtl",
"model/step",
"model/step",
"model/step",
"model/step",
"model/step+xml", "model/step+xml",
"model/step+zip", "model/step+zip",
"model/step-xml+zip", "model/step-xml+zip",
"model/u3d",
"model/vnd.bary",
"model/vnd.cld",
"model/vnd.collada+xml", "model/vnd.collada+xml",
"model/vnd.dwf", "model/vnd.dwf",
"model/vnd.gdl", "model/vnd.gdl",
"model/vnd.gtw", "model/vnd.gtw",
"model/vnd.mts", "video/mp2t",
"model/vnd.opengex", "model/vnd.opengex",
"model/vnd.parasolid.transmit.binary", "model/vnd.parasolid.transmit.binary",
"model/vnd.parasolid.transmit.text", "model/vnd.parasolid.transmit.text",
"model/vnd.pytha.pyox",
"model/vnd.pytha.pyox",
"model/vnd.sap.vds", "model/vnd.sap.vds",
"model/vnd.usda",
"model/vnd.usdz+zip", "model/vnd.usdz+zip",
"model/vnd.valve.source.compiled-map", "model/vnd.valve.source.compiled-map",
"model/vnd.vtu", "model/vnd.vtu",
@ -1632,6 +1690,7 @@
"text/html", "text/html",
"text/html", "text/html",
"text/jade", "text/jade",
"text/javascript",
"text/jsx", "text/jsx",
"text/less", "text/less",
"text/markdown", "text/markdown",
@ -1683,6 +1742,7 @@
"text/vnd.wap.wml", "text/vnd.wap.wml",
"text/vnd.wap.wmlscript", "text/vnd.wap.wmlscript",
"text/vtt", "text/vtt",
"text/wgsl",
"text/x-asm", "text/x-asm",
"text/x-asm", "text/x-asm",
"text/x-c", "text/x-c",
@ -1723,12 +1783,11 @@
"video/h264", "video/h264",
"video/iso.segment", "video/iso.segment",
"video/jpeg", "video/jpeg",
"video/jpm",
"video/mj2", "video/mj2",
"video/mj2", "video/mj2",
"video/mp2t", "video/mp2t",
"video/mp4", "video/mp2t",
"video/mp4", "video/mp2t",
"video/mp4", "video/mp4",
"video/mpeg", "video/mpeg",
"video/mpeg", "video/mpeg",

View file

@ -36,20 +36,6 @@ serverLogger.info`Versia Server started at ${config.http.bind}:${config.http.bin
serverLogger.info`Database is online, now serving ${postCount} posts`; serverLogger.info`Database is online, now serving ${postCount} posts`;
if (config.frontend.enabled) {
// Check if frontend is reachable
const response = await fetch(new URL("/", config.frontend.url))
.then((res) => res.ok)
.catch(() => false);
if (!response) {
serverLogger.error`Frontend is unreachable at ${config.frontend.url}`;
serverLogger.error`Please ensure the frontend is online and reachable`;
}
} else {
serverLogger.warn`Frontend is disabled, skipping check`;
}
// Check if Redis is reachable // Check if Redis is reachable
const connection = new IORedis({ const connection = new IORedis({
host: config.redis.queue.host, host: config.redis.queue.host,

View file

@ -176,7 +176,7 @@ cert = "/app/dist/config/${DOMAIN}.pem"
[frontend] [frontend]
enabled = true enabled = true
url = "http://fe:3000" path = "/app/dist/frontend"
[media] [media]
backend = "local" backend = "local"

View file

@ -57,6 +57,8 @@ export const generateClient = async (
token?.data.accessToken, token?.data.accessToken,
); );
// @ts-expect-error This doesn't include fetch.preconnect, which is a custom property
// added by Bun
// biome-ignore lint/complexity/useLiteralKeys: Overriding private properties // biome-ignore lint/complexity/useLiteralKeys: Overriding private properties
client["fetch"] = ( client["fetch"] = (
input: RequestInfo | string | URL | Request, input: RequestInfo | string | URL | Request,