@authup/server-auth-console 1.0.0-beta.64 → 1.0.0-beta.66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -0
- package/dist/{server-Brhsp_x-.mjs → application-h8KbQSdz.mjs} +188 -97
- package/dist/application-h8KbQSdz.mjs.map +1 -0
- package/dist/bin.mjs +11 -13
- package/dist/bin.mjs.map +1 -1
- package/dist/config.d.ts +5 -5
- package/dist/config.d.ts.map +1 -1
- package/dist/constants.d.ts +7 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/handler.d.ts.map +1 -1
- package/dist/index.d.mts +90 -42
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +10 -20
- package/dist/index.mjs.map +1 -1
- package/dist/payload.d.ts +42 -0
- package/dist/payload.d.ts.map +1 -1
- package/dist/render.d.ts +8 -1
- package/dist/render.d.ts.map +1 -1
- package/dist/resolve.d.ts +9 -15
- package/dist/resolve.d.ts.map +1 -1
- package/dist/types.d.ts +2 -2
- package/package.json +12 -9
- package/dist/server-Brhsp_x-.mjs.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"server-Brhsp_x-.mjs","names":["createHandler","createAssetsHandler","createHandler"],"sources":["../src/config.ts","../src/constants.ts","../src/redirect.ts","../src/payload.ts","../src/path.ts","../src/resolve.ts","../src/render.ts","../src/handler.ts","../src/server.ts"],"sourcesContent":["/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport {\n AUTH_CONSOLE_SCHEMA,\n CORE_SCHEMA,\n ROOT_SCHEMA,\n SECTION_KEY,\n THEME_SCHEMA,\n} from '@authup/server-config';\nimport {\n buildSchemaDefaults,\n defineSchema,\n mergeSchemaData,\n readSchemaFromEnv,\n resolveSchemaData,\n} from '@authup/server-config-kit';\nimport type { CoreConfig, EnvironmentVariable } from '@authup/server-config';\nimport type { Config, ConfigInput } from './types';\n\n/**\n * The keys this service reads, SELECTED out of the document schema by name.\n *\n * Nothing is declared here: every key of `authup.yml` is declared once in\n * `@authup/server-config`, so this service cannot spell a path, an\n * environment variable, a default or a reader differently from server-core,\n * which reads several of the same keys. Neither package depends on the other;\n * both depend on the declaration.\n *\n * Its own section is spread, so this service reads it in its own vocabulary\n * (`url`, `port`, `host`); every other section stays under the key the\n * document nests it at.\n */\nexport const CONFIG_SCHEMA = defineSchema<ConfigInput, 'publicUrl' | 'internalUrl' | 'db'>({\n ...AUTH_CONSOLE_SCHEMA,\n ...ROOT_SCHEMA,\n [SECTION_KEY.THEME]: THEME_SCHEMA,\n // Two keys of core, never the section. `publicUrl` derives from\n // the core listener address, which is what a console needs; selecting the\n // whole section also selects its INVARIANTS, and `resolveSchemaData` runs\n // every resolver in a registry -- so a console would refuse to start on a\n // short SECRETS_ENCRYPTION_KEY, or on mfaRequired without mfaEnabled, for\n // keys it has no database, key store or MFA to use.\n [SECTION_KEY.CORE]: defineSchema<Pick<CoreConfig, 'host' | 'port'>, never, EnvironmentVariable>({\n host: CORE_SCHEMA.host,\n port: CORE_SCHEMA.port,\n }),\n});\n\n/**\n * Turn the configuration namespace into the service's own shape: fill the\n * defaults, derive the one key that is derived rather than configured, and\n * rename. An empty `url` means the console sits on server-core's own origin\n * under the default segment, which is the single-origin deployment.\n *\n * The defaults are layered SECTION-AWARE ({@link mergeSchemaData}): a spread\n * would let an input carrying one key of a section replace the whole section\n * and take every other key's default with it.\n */\nexport function resolveConfig(\n input: Partial<ConfigInput>,\n) : Config {\n const values = resolveSchemaData<ConfigInput>(\n CONFIG_SCHEMA,\n mergeSchemaData<ConfigInput>(\n CONFIG_SCHEMA,\n buildSchemaDefaults<ConfigInput>(CONFIG_SCHEMA),\n input,\n ),\n ) as ConfigInput;\n\n return {\n url: values.url,\n apiUrl: values.publicUrl,\n // `internalUrl` falls back to `publicUrl`, so an operator who has one\n // address for both sides configures nothing. The composed `authup\n // start` overrides this with its own listen address unless the\n // document named one.\n apiInternalUrl: values.internalUrl,\n port: values.port,\n host: values.host,\n distPath: values.path,\n theme: values.theme,\n };\n}\n\n/**\n * The standalone entry's configuration, read from the environment alone.\n * `authup.yml` reaches this service through the CLI roles, which compose this\n * very registry into the one document loader.\n */\nexport function readConfigFromEnv() : Config {\n // The explicit type argument is load-bearing: inferred from the schema\n // object, a key declared without a default (the derived publicUrl) comes\n // back as unknown.\n const input : Partial<ConfigInput> = readSchemaFromEnv<ConfigInput>(CONFIG_SCHEMA);\n\n return resolveConfig(input);\n}\n","/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\n/**\n * The vite base the auth console bundle is built with. Asset hrefs in the\n * shell are emitted against it, so the service mounts its assets there and\n * rebases them only when the deployment carries a sub-path.\n */\nexport const VITE_BASE = '/console/auth/';\n\n/**\n * The path the service is served under by default, i.e. the path component\n * of `authConsole.url`. It is the same segment server-core mounted\n * the assets at before the split, so a built bundle needs no rebuild.\n */\nexport const BASE_PATH = '/console/auth';\n\n/**\n * The pages the service renders. Each is a route of the console bundle's\n * own router, and each is what a server-core page GET now redirects to.\n */\nexport const PAGES = [\n '/authorize',\n '/register',\n '/activate',\n '/password-forgot',\n '/password-reset',\n '/logout',\n] as const;\n\n/**\n * Where this service mounts the bundle's `assets/` directory. The public\n * asset URL is the service's own public path plus this route, which is what\n * the bundle's fixed vite base is rebased onto.\n */\nexport const ASSETS_PATH = '/assets';\n\nexport const HEALTH_PATH = '/healthy';\n","/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\n/**\n * Open-redirect guard for the `redirect` query parameter carried by the\n * auth workflow pages: only same-origin relative paths pass through, so the\n * value can be safely reflected into an anchor href / forwarded as a\n * post-login destination.\n *\n * Rejects: non-strings, control/whitespace chars (browsers strip some,\n * shifting where the URL authority begins), protocol-relative (`//host`),\n * backslash variants (browsers normalise `\\` → `/`), and any scheme\n * (`javascript:`, `http:`) — both on the raw and once-decoded form so a\n * percent-encoded separator (`%2f`, `%5c`) can't slip past.\n */\nexport function sanitizeRelativeRedirect(input: unknown): string | undefined {\n if (typeof input !== 'string' || input.length === 0) {\n return undefined;\n }\n\n // Raw input: reject control chars AND whitespace (space/tab/newline) — a\n // raw space can shift where the URL authority begins.\n // eslint-disable-next-line no-control-regex\n if (/[\\u0000-\\u0020\\u007f]/.test(input)) {\n return undefined;\n }\n\n let decoded: string;\n try {\n decoded = decodeURIComponent(input);\n } catch {\n return undefined;\n }\n\n // Decoded form: reject C0 controls + DEL (CR/LF/NUL — the header-injection\n // vectors a `%0a`/`%0d` would smuggle past the raw check) but NOT space\n // (0x20), so a legitimate `%20` in the path still passes.\n // eslint-disable-next-line no-control-regex\n if (/[\\u0000-\\u001f\\u007f]/.test(decoded)) {\n return undefined;\n }\n\n for (const candidate of [input, decoded]) {\n if (!candidate.startsWith('/')) {\n return undefined;\n }\n if (candidate.length > 1 && (candidate[1] === '/' || candidate[1] === '\\\\')) {\n return undefined;\n }\n if (candidate.includes('\\\\')) {\n return undefined;\n }\n }\n\n return input;\n}\n","/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { AuthorizeInfo, StatusResponse, StatusResponseFeatures } from '@authup/core-http-kit';\nimport { Client } from '@authup/core-http-kit';\nimport { useRequestQuery } from '@routup/basic/query';\nimport type { IAppEvent } from 'routup';\nimport { sanitizeRelativeRedirect } from './redirect';\nimport type { Config } from './types';\n\n/**\n * The service hydrates ANONYMOUSLY. It holds no credential of its own and\n * asks server-core only for what an unauthenticated visitor may see, which\n * is the whole of what these pages render.\n *\n * It dispatches against `apiInternalUrl`, never the browser-facing `apiUrl`:\n * this is a server-side call, so it must not depend on the public address\n * resolving from inside the deployment. Unlike server-core's own internal\n * client the swap is on `baseURL` rather than at the transport layer,\n * because nothing derived from it reaches a caller -- there is no\n * `redirect_uri` here to be compared byte for byte later.\n */\nexport function createAPIClient(config: Config) : Client {\n return new Client({ baseURL: config.apiInternalUrl });\n}\n\n/**\n * Report an outbound failure to the operator and raise one the visitor may\n * see, which is deliberately not the same error.\n *\n * hapic embeds the resolved request URL in its message, and this service has\n * no error middleware: routup answers with `event.error.message` verbatim, on\n * the public login page. That URL is `apiInternalUrl`, which on a split\n * deployment names a service on the operator's own network, so an API that is\n * merely down would publish its internal address to every anonymous visitor.\n * It was harmless while the value was `publicUrl`, an address the browser\n * already had.\n *\n * The rule and the remedy are server-core's own (`sanitizeError` /\n * `describeError`): the caller gets a message it can act on, the detail goes\n * to the log. `console.error` rather than a logger because a console handler\n * is built from a config alone and is given none -- and because this line is\n * the only trace such a failure leaves, which is how #3550 was diagnosed in\n * the first place.\n */\nfunction failWithoutAddress(error: unknown) : never {\n // eslint-disable-next-line no-console\n console.error('[authup] the auth console could not reach the API:', error);\n\n throw new Error('The identity provider could not be reached.');\n}\n\n/**\n * The feature flags every workflow page gates its form on. A page that\n * cannot reach them must not silently claim a workflow is disabled, so the\n * failure propagates rather than defaulting to false.\n *\n * Read ONCE and held for the reader's lifetime, the same shape render.ts\n * keeps for the dist template, manifest and render entry: `GET /` reports\n * the version and the boot-config feature flags, none of which changes\n * without a restart, so a TTL would be a number with nothing behind it.\n * Without it every workflow page render is an API call, and under the\n * composed `authup start` those all arrive over loopback on one shared\n * rate-limit key. Only a SUCCESS is held, so an API that was down at the\n * first render is retried rather than remembered as broken.\n *\n * The cache is instance-scoped rather than module-scoped (098 C4): the\n * answer depends on which API the client was built against, so two handlers\n * in one process must not share one, and a module slot would additionally\n * leak between test cases.\n */\nexport function createFeaturesReader(client: Client) : () => Promise<StatusResponseFeatures> {\n let cached : StatusResponseFeatures | undefined;\n let pending : Promise<StatusResponseFeatures> | undefined;\n\n return () => {\n if (cached) {\n return Promise.resolve(cached);\n }\n\n if (pending) {\n return pending;\n }\n\n pending = client.status.get()\n .then((status: StatusResponse) => {\n cached = status.features;\n\n return cached;\n })\n .catch((e) => failWithoutAddress(e));\n\n const clear = () => {\n pending = undefined;\n };\n pending.then(clear, clear);\n\n return pending;\n };\n}\n\n/**\n * The `/authorize` render input, resolved by server-core (plan 101 D2-1).\n * The browser's query is forwarded verbatim: the answer is derived from all\n * of it, the `provider` hint and the closed `error` marker set included.\n */\nexport async function readAuthorizeInfo(client: Client, event: IAppEvent) : Promise<AuthorizeInfo> {\n const { search } = new URL(event.request.url);\n\n try {\n return await client.authorize.getInfo(search);\n } catch (e) {\n return failWithoutAddress(e);\n }\n}\n\nexport type WorkflowPageOptions = {\n // Whether the page consumes the `realmId` (legacy `realm_id`) / `token`\n // query params (e.g. prefill from an email deep link). Off by default so\n // a page never reflects a param it doesn't use.\n realmAware?: boolean,\n tokenAware?: boolean,\n};\n\n/**\n * The payload the four workflow pages render from: the feature flags plus\n * the handful of query params each one declares. Unchanged from the\n * assembly server-core did before the split, including the open-redirect\n * guard on `redirect`.\n */\nexport function buildWorkflowPageData(\n event: IAppEvent,\n features: StatusResponseFeatures,\n options: WorkflowPageOptions = {},\n) : Record<string, any> {\n const query = useRequestQuery(event);\n\n const data: Record<string, any> = {\n features,\n redirect: sanitizeRelativeRedirect(query.redirect),\n };\n\n if (options.realmAware) {\n const realmId = typeof query.realmId === 'string' ? query.realmId : query.realm_id;\n data.realmId = typeof realmId === 'string' ? realmId : undefined;\n }\n\n if (options.tokenAware) {\n data.token = typeof query.token === 'string' ? query.token : undefined;\n }\n\n return data;\n}\n","/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nexport const CODE_PATH = path.dirname(fileURLToPath(import.meta.url));\nexport const PACKAGE_PATH = path.join(CODE_PATH, '..');\n","/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { locateUpSync } from 'locter';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { PACKAGE_PATH } from './path';\n\nlet cachedPackagePath: string | undefined;\nlet cachedDistPath: string | undefined;\nlet overridePackagePath: string | undefined;\n\n/**\n * Point the resolution at a substituted package (config `distPath`)\n * instead of the node_modules walk. Called once at boot.\n */\nexport function setPackagePath(value: string | undefined) : void {\n overridePackagePath = value || undefined;\n cachedPackagePath = undefined;\n cachedDistPath = undefined;\n}\n\n/**\n * Locate the auth console package. The SSR auth workflow UI ships as\n * `@authup/client-auth-console` (a dependency of THIS service), so the\n * node_modules ancestor walk from this package's own root (locter's\n * `locateUp`) finds it for the workspace (symlink onto\n * apps/client-auth-console) and for a published install alike. Only a\n * positive result is cached.\n *\n * The `cwd` anchor is behavioural, not incidental: it decides which\n * node_modules tree is walked, so it stays pinned to this package rather\n * than to the process cwd.\n */\nexport function resolvePackagePath() : string | undefined {\n if (cachedPackagePath) {\n return cachedPackagePath;\n }\n\n if (overridePackagePath) {\n cachedPackagePath = overridePackagePath;\n\n return cachedPackagePath;\n }\n\n const manifest = locateUpSync(\n 'node_modules/@authup/client-auth-console/package.json',\n { cwd: PACKAGE_PATH },\n );\n if (manifest) {\n cachedPackagePath = manifest.directory;\n }\n\n return cachedPackagePath;\n}\n\n/**\n * Locate the BUILT auth console bundle (`dist/client` template + assets,\n * `dist/server/server.js` render entry). Only a positive result is cached,\n * so a dev building the package after boot is picked up on the next\n * request.\n */\nexport function resolveDistPath() : string | undefined {\n if (cachedDistPath) {\n return cachedDistPath;\n }\n\n const packagePath = resolvePackagePath();\n if (packagePath) {\n const distPath = path.join(packagePath, 'dist');\n\n if (fs.existsSync(path.join(distPath, 'client', 'index.html'))) {\n cachedDistPath = distPath;\n }\n }\n\n return cachedDistPath;\n}\n","/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { HydrationPayload, RenderFunction } from '@authup/client-auth-console';\nimport { InternalError } from '@authup/errors';\nimport { getURLBasePath } from '@authup/kit';\nimport {\n applyTheme,\n applyUIPageHeaders,\n readUIClientPreferences,\n rebaseAssetURLs,\n replaceTemplateMarker,\n stampHtmlAttributes,\n} from '@authup/server-console-kit';\nimport { read } from 'locter';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { VITE_BASE } from './constants';\nimport { resolveDistPath } from './resolve';\nimport type { RenderPage } from './types';\n\n// Process-lifetime caches for the immutable production SSR assets. The dist\n// template, manifest and server bundle don't change after boot, so read them\n// once instead of per request (the auth/login routes are hot paths).\nlet cachedHtml: string | undefined;\nlet cachedManifest: Record<string, any> | undefined;\nlet cachedRender: RenderFunction | undefined;\n\nexport const renderPage : RenderPage = async (event, config, ctx) => {\n const distPath = resolveDistPath();\n if (!distPath) {\n throw new InternalError(\n 'The auth console bundle (@authup/client-auth-console) is not built or installed.',\n );\n }\n\n const html = (cachedHtml ??= await fs.promises.readFile(\n path.join(distPath, 'client', 'index.html'),\n 'utf-8',\n ));\n const manifest = (cachedManifest ??= JSON.parse(await fs.promises.readFile(\n path.join(distPath, 'client', '.vite', 'ssr-manifest.json'),\n 'utf-8',\n )));\n const render = (cachedRender ??= (await read(\n path.join(distPath, 'server', 'server.js'),\n )).render as RenderFunction);\n\n // The client app hydrates locale + color-mode from the payload, so it\n // adopts the same values the HTML shell is stamped with below.\n const preferences = readUIClientPreferences(event);\n\n // `baseURL` is server-core's public URL: the console derives its HTTP\n // client and its cookie path from it. `basePath` is where THIS service\n // is served, which is what the router and every inter-page href need.\n // Before the split the two were the same value; they are not any more,\n // so the console reads them separately.\n const basePath = getURLBasePath(config.url);\n\n const payload : HydrationPayload = {\n config: {\n baseURL: config.apiUrl,\n basePath,\n colorMode: preferences.colorMode,\n locale: preferences.locale,\n },\n data: ctx.data,\n };\n\n const [appHtml, preloadLinks] = await render({\n url: ctx.url,\n manifest,\n payload,\n });\n\n let body = replaceTemplateMarker(html, '<!--preload-links-->', preloadLinks);\n body = replaceTemplateMarker(body, '<!--app-html-->', appHtml);\n\n body = stampHtmlAttributes(body, preferences);\n\n // This service mounts the bundle's assets at its own /assets, so the\n // fixed vite base in every href is replaced by this service's public\n // path. The vite base was decided when the bundle was built and says\n // nothing about where the service is published.\n body = rebaseAssetURLs(body, VITE_BASE, `${basePath}/`);\n\n // The theme's own asset urls are built from the same base, and the\n // service mounts them under it, so a themed deployment needs no rule of\n // its own at the reverse proxy beyond the one that reaches this service.\n body = await applyTheme(body, ctx.theme, basePath);\n\n applyUIPageHeaders(event);\n\n return body;\n};\n","/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { IThemeProvider } from '@authup/server-console-kit';\nimport {\n THEME_ASSET_MOUNT_PATH,\n createThemeAssetsHandler,\n createThemeProvider,\n} from '@authup/server-console-kit';\nimport { createHandler as createAssetsHandler } from '@routup/assets';\nimport { basic } from '@routup/basic';\nimport path from 'node:path';\nimport type { IApp } from 'routup';\nimport { App, defineCoreHandler } from 'routup';\nimport { ASSETS_PATH, HEALTH_PATH } from './constants';\nimport {\n buildWorkflowPageData,\n createAPIClient,\n createFeaturesReader,\n readAuthorizeInfo,\n} from './payload';\nimport { renderPage } from './render';\nimport { resolveDistPath, setPackagePath } from './resolve';\nimport type { Config, RenderPage } from './types';\n\nconst WORKFLOW_PAGES : {\n url: string,\n realmAware?: boolean,\n tokenAware?: boolean\n}[] = [\n { url: '/register', realmAware: true },\n { url: '/activate', tokenAware: true },\n { url: '/password-forgot', realmAware: true },\n {\n url: '/password-reset',\n realmAware: true,\n tokenAware: true,\n },\n];\n\n/**\n * The service as a mountable routup handler, so the CLI can compose it onto\n * server-core's own listener for the single-container deployment while a\n * split deployment runs it behind its own server.\n *\n * The paths are prefix-free. authup assumes a prefix-stripping reverse\n * proxy, so a service published at `<origin>/console/auth` receives\n * `/authorize`, exactly as server-core received it before the split.\n */\nexport async function createHandler(\n config: Config,\n themeProvider?: IThemeProvider,\n render: RenderPage = renderPage,\n) : Promise<IApp> {\n setPackagePath(config.distPath);\n\n const app = new App();\n const client = createAPIClient(config);\n const readFeatures = createFeaturesReader(client);\n\n // The shell is stamped from the vc-locale / vc-color-mode cookies, and\n // without the plugin every cookie read answers undefined, which is a\n // silent flash of the wrong color mode on every full load. server-core\n // registers it globally, so a mounted handler inherits one; a standalone\n // service has nothing above it.\n app.use(basic({ cookie: true, query: true }));\n\n // A missing directory disables theming entirely: no provider is created\n // and the rendered pages are byte-identical to the un-themed ones, so the\n // default configuration pays nothing. An invalid manifest throws here and\n // fails the boot rather than surfacing per request.\n // Injected by the theme module when this runs inside the console\n // application; built here for a caller holding only a config.\n const theme = themeProvider ?? await createThemeProvider(config);\n\n app.use(defineCoreHandler({\n method: 'get',\n path: HEALTH_PATH,\n fn: () => ({ status: 'ok' }),\n }));\n\n if (theme) {\n app.use(THEME_ASSET_MOUNT_PATH, createThemeAssetsHandler(theme));\n }\n\n app.use(defineCoreHandler({\n method: 'get',\n path: '/authorize',\n fn: async (event) => render(event, config, {\n url: '/authorize',\n data: await readAuthorizeInfo(client, event),\n theme,\n }),\n }));\n\n for (const page of WORKFLOW_PAGES) {\n app.use(defineCoreHandler({\n method: 'get',\n path: page.url,\n fn: async (event) => {\n const features = await readFeatures();\n\n return render(event, config, {\n url: page.url,\n data: buildWorkflowPageData(event, features, page),\n theme,\n });\n },\n }));\n }\n\n // The logout page needs nothing resolved up front: it drives the\n // end-session call itself and renders from the answer, so the render\n // stays a pure shell and no request reaches server-core here.\n app.use(defineCoreHandler({\n method: 'get',\n path: '/logout',\n fn: async (event) => render(event, config, {\n url: '/logout',\n data: {},\n theme,\n }),\n }));\n\n // Only the assets directory is mounted, never dist/client itself: the\n // template and the ssr manifest are inputs of the render, not files to\n // serve. A missing bundle only disables the mount; the page routes\n // report the actionable error.\n const distPath = resolveDistPath();\n if (distPath) {\n app.use(ASSETS_PATH, createAssetsHandler(\n path.posix.join(distPath, 'client', 'assets'),\n {\n fallthrough: false,\n scan: false,\n },\n ));\n }\n\n return app;\n}\n","/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { App } from 'routup';\nimport { createHandler } from './handler';\nimport type { Config } from './types';\n\n/**\n * The standalone service: the same handler the CLI mounts in process,\n * behind a listener of its own.\n */\nexport async function createServer(config: Config) : Promise<App> {\n const app = new App();\n\n app.use(await createHandler(config));\n\n return app;\n}\n"],"mappings":"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"}
|