UNPKG

@lucidcms/core

Version:

The core of the Lucid CMS. It's responsible for spinning up the API and serving the CMS.

1 lines 24.4 kB
{"version":3,"file":"app.mjs","names":["constants","packageJson.version"],"sources":["../../../src/libs/http/app.ts"],"sourcesContent":["import type { PublicErrorData } from \"@lucidcms/types\";\nimport { Scalar } from \"@scalar/hono-api-reference\";\nimport { Hono } from \"hono\";\nimport { contextStorage } from \"hono/context-storage\";\nimport { cors } from \"hono/cors\";\nimport { requestId } from \"hono/request-id\";\nimport { secureHeaders } from \"hono/secure-headers\";\nimport type { StatusCode } from \"hono/utils/http-status\";\nimport { openAPIRouteHandler } from \"hono-openapi\";\nimport packageJson from \"../../../package.json\" with { type: \"json\" };\nimport constants from \"../../constants/constants.js\";\nimport type { LucidHonoGeneric } from \"../../types/hono.js\";\nimport type { Config, EnvironmentVariables } from \"../../types.js\";\nimport { LucidAPIError, translateErrorData } from \"../../utils/errors/index.js\";\nimport { normalizeHost } from \"../../utils/helpers/index.js\";\nimport type { DatabaseConnection } from \"../db/types.js\";\nimport {\n\tdestroyEmailAdapter,\n\tgetInitializedEmailAdapter,\n} from \"../email/lifecycle.js\";\nimport type { EmailAdapterInstance } from \"../email/types.js\";\nimport { createTranslator, resolveInterfaceLocale } from \"../i18n/index.js\";\nimport type { TranslationStore } from \"../i18n/types.js\";\nimport {\n\tdestroyImageProcessor,\n\tgetInitializedImageProcessor,\n} from \"../image-processor/lifecycle.js\";\nimport type { ImageProcessorInstance } from \"../image-processor/types.js\";\nimport { destroyKVAdapter, getInitializedKVAdapter } from \"../kv/lifecycle.js\";\nimport type { KVAdapterInstance } from \"../kv/types.js\";\nimport logger, { destroyLogger } from \"../logger/index.js\";\nimport {\n\tdestroyMediaAdapter,\n\tgetInitializedMediaAdapter,\n} from \"../media/lifecycle.js\";\nimport type { MediaAdapterInstance } from \"../media/types.js\";\nimport {\n\tdestroyQueueAdapter,\n\tgetInitializedQueueAdapter,\n} from \"../queue/lifecycle.js\";\nimport type { QueueAdapterInstance } from \"../queue/types.js\";\nimport type { AdapterRuntimeContext } from \"../runtime/types.js\";\nimport logRoute from \"./middleware/log-route.js\";\nimport routes from \"./routes/index.js\";\nimport type { HttpExtension } from \"./types.js\";\nimport featureSupportChecks from \"./utils/feature-support-checks.js\";\nimport registerCustomRoutes from \"./utils/register-custom-routes.js\";\nimport runHttpExtensions from \"./utils/run-http-extensions.js\";\n\nconst invocationSymbol = Symbol(\"@lucidcms/core:http-invocation\");\n\ntype HttpInvocation = {\n\tdatabase: DatabaseConnection;\n\tenv?: EnvironmentVariables;\n};\n\ntype HttpInvocationBindings = EnvironmentVariables & {\n\t[invocationSymbol]: HttpInvocation;\n};\n\nconst createInvocationBindings = (\n\tinvocation: HttpInvocation,\n\trequestBindings?: object,\n): HttpInvocationBindings => {\n\tconst bindings = Object.create(\n\t\tinvocation.env ?? null,\n\t) as HttpInvocationBindings;\n\tif (requestBindings) {\n\t\t// Node bindings expose request state such as `socket` through descriptors,\n\t\t// so preserve them rather than flattening values with object spread.\n\t\tObject.defineProperties(\n\t\t\tbindings,\n\t\t\tObject.getOwnPropertyDescriptors(requestBindings),\n\t\t);\n\t}\n\tObject.defineProperty(bindings, invocationSymbol, {\n\t\tvalue: invocation,\n\t});\n\treturn bindings;\n};\n\n/**\n * The entry point for creating the Hono app.\n */\nconst createApp = async (props: {\n\tconfig: Config;\n\ttranslationStore: TranslationStore;\n\truntimeContext: AdapterRuntimeContext;\n\tenv?: EnvironmentVariables;\n\thttp?: {\n\t\textensions?: HttpExtension[];\n\t};\n}) => {\n\tconst app = new Hono<LucidHonoGeneric>();\n\tconst configuredHost = props.config.host?.trim()\n\t\t? normalizeHost(props.config.host)\n\t\t: undefined;\n\n\tapp\n\t\t.use(\n\t\t\trequestId({\n\t\t\t\theaderName: constants.headers.requestId,\n\t\t\t}),\n\t\t)\n\t\t.use(contextStorage());\n\n\tawait runHttpExtensions({\n\t\tapp,\n\t\tconfig: props.config,\n\t\tpriority: 0,\n\t\textensions: [\n\t\t\t...(props.http?.extensions ?? []),\n\t\t\t...props.config.http.extensions,\n\t\t],\n\t});\n\n\tlet kvInstance: KVAdapterInstance | undefined;\n\tlet queueInstance: QueueAdapterInstance | undefined;\n\tlet mediaInstance: MediaAdapterInstance | null | undefined;\n\tlet emailInstance: EmailAdapterInstance | undefined;\n\tlet imageProcessorInstance: ImageProcessorInstance | undefined;\n\tconst destroyAdapterInstances = () =>\n\t\tPromise.allSettled([\n\t\t\tdestroyQueueAdapter(queueInstance, {\n\t\t\t\tconfig: props.config,\n\t\t\t\tenv: props.env,\n\t\t\t\truntimeContext: props.runtimeContext,\n\t\t\t}),\n\t\t\tdestroyKVAdapter(kvInstance, {\n\t\t\t\tconfig: props.config,\n\t\t\t\tenv: props.env,\n\t\t\t\truntimeContext: props.runtimeContext,\n\t\t\t}),\n\t\t\tdestroyMediaAdapter(mediaInstance, {\n\t\t\t\tconfig: props.config,\n\t\t\t\tenv: props.env,\n\t\t\t\truntimeContext: props.runtimeContext,\n\t\t\t}),\n\t\t\tdestroyEmailAdapter(emailInstance, {\n\t\t\t\tconfig: props.config,\n\t\t\t\tenv: props.env,\n\t\t\t\truntimeContext: props.runtimeContext,\n\t\t\t}),\n\t\t\tdestroyImageProcessor(imageProcessorInstance, {\n\t\t\t\tconfig: props.config,\n\t\t\t\tenv: props.env,\n\t\t\t\truntimeContext: props.runtimeContext,\n\t\t\t}),\n\t\t]);\n\n\ttry {\n\t\tkvInstance = await getInitializedKVAdapter(props.config, {\n\t\t\tenv: props.env,\n\t\t\truntimeContext: props.runtimeContext,\n\t\t});\n\t\tqueueInstance = await getInitializedQueueAdapter(props.config, {\n\t\t\tenv: props.env,\n\t\t\truntimeContext: props.runtimeContext,\n\t\t});\n\t\tmediaInstance = await getInitializedMediaAdapter(props.config, {\n\t\t\tenv: props.env,\n\t\t\truntimeContext: props.runtimeContext,\n\t\t});\n\t\temailInstance = await getInitializedEmailAdapter(props.config, {\n\t\t\tenv: props.env,\n\t\t\truntimeContext: props.runtimeContext,\n\t\t});\n\t\timageProcessorInstance = await getInitializedImageProcessor(props.config, {\n\t\t\tenv: props.env,\n\t\t\truntimeContext: props.runtimeContext,\n\t\t});\n\t} catch (error) {\n\t\tawait destroyAdapterInstances();\n\t\tawait destroyLogger();\n\t\tthrow error;\n\t}\n\tif (\n\t\t!kvInstance ||\n\t\t!queueInstance ||\n\t\t!emailInstance ||\n\t\t!imageProcessorInstance\n\t) {\n\t\tthrow new Error(\"Lucid could not initialize its application adapters.\");\n\t}\n\n\tapp\n\t\t.use(logRoute)\n\t\t.use(\n\t\t\tcors({\n\t\t\t\torigin: [\n\t\t\t\t\t\"http://localhost:3000\",\n\t\t\t\t\t...(configuredHost ? [configuredHost] : []),\n\t\t\t\t\t...(props.config.http.security.cors?.origin || []),\n\t\t\t\t],\n\t\t\t\tallowMethods: [\"GET\", \"POST\", \"PUT\", \"DELETE\", \"PATCH\"],\n\t\t\t\tallowHeaders: [\n\t\t\t\t\t\"Content-Type\",\n\t\t\t\t\t\"Authorization\",\n\t\t\t\t\t\"Content-Length\",\n\t\t\t\t\t...Object.values(constants.headers),\n\t\t\t\t\t...(props.config.http.security.cors?.allowHeaders || []),\n\t\t\t\t],\n\t\t\t\texposeHeaders: [constants.headers.requestId],\n\t\t\t\tcredentials: true,\n\t\t\t}),\n\t\t)\n\t\t.use(\n\t\t\tsecureHeaders(\n\t\t\t\tprops.config.http.security.headers ?? {\n\t\t\t\t\tcrossOriginResourcePolicy: false,\n\t\t\t\t},\n\t\t\t),\n\t\t)\n\t\t.use(async (c, next) => {\n\t\t\tconst invocation = (c.env as HttpInvocationBindings | undefined)?.[\n\t\t\t\tinvocationSymbol\n\t\t\t];\n\t\t\tif (!invocation) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"Lucid HTTP requests must be handled with an active runtime invocation.\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tc.set(\"config\", props.config);\n\t\t\tc.set(\"database\", invocation.database);\n\t\t\tc.set(\"translationStore\", props.translationStore);\n\t\t\tc.set(\"runtimeContext\", props.runtimeContext);\n\t\t\tc.set(\"queue\", queueInstance);\n\t\t\tc.set(\"kv\", kvInstance);\n\t\t\tc.set(\"media\", mediaInstance);\n\t\t\tc.set(\"email\", emailInstance);\n\t\t\tc.set(\"env\", invocation.env ?? null);\n\t\t\tc.set(\"cf\", c.get(\"cf\") ?? null);\n\t\t\tc.set(\"caches\", c.get(\"caches\") ?? null);\n\t\t\tc.set(\"ctx\", c.get(\"ctx\") ?? null);\n\t\t\tawait next();\n\t\t})\n\t\t.route(\"/\", routes)\n\t\t.onError(async (err, c) => {\n\t\t\tconst locale = resolveInterfaceLocale({\n\t\t\t\tconfig: props.config,\n\t\t\t\tlocale: c.req.header(constants.headers.interfaceLocale),\n\t\t\t\tacceptLanguage: c.req.header(\"Accept-Language\"),\n\t\t\t});\n\t\t\tconst translate = createTranslator({\n\t\t\t\tstore: props.translationStore,\n\t\t\t\tlocale,\n\t\t\t});\n\n\t\t\tif (err instanceof LucidAPIError) {\n\t\t\t\tconst error = translateErrorData(err.error, translate);\n\n\t\t\t\tc.status(error.status as StatusCode);\n\t\t\t\treturn c.json({\n\t\t\t\t\tname: error.name,\n\t\t\t\t\tmessage: error.message,\n\t\t\t\t\tstatus: error.status,\n\t\t\t\t\terrors: error.errors,\n\t\t\t\t\tcode: error.code,\n\t\t\t\t\tkey: error.key,\n\t\t\t\t} satisfies PublicErrorData);\n\t\t\t}\n\n\t\t\tlogger.error({\n\t\t\t\terror: err,\n\t\t\t\tevent: \"http.unhandled.error\",\n\t\t\t\tmessage: err.message,\n\t\t\t\tscope: constants.logScopes.http,\n\t\t\t});\n\n\t\t\t// @ts-expect-error\n\t\t\tif (err?.statusCode === 429) {\n\t\t\t\tconst resetSeconds = c.res.headers.get(\"Retry-After\") ?? 0;\n\t\t\t\tc.status(429);\n\t\t\t\treturn c.json({\n\t\t\t\t\tcode: \"rate_limit\",\n\t\t\t\t\tname: translate(\"server:core.rate.limit.error.name\"),\n\t\t\t\t\tmessage: translate(\"server:core.rate.limit.exceeded.message\", {\n\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\tresetSeconds,\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t\tstatus: 429,\n\t\t\t\t} satisfies PublicErrorData);\n\t\t\t}\n\n\t\t\tc.status(500);\n\t\t\treturn c.json({\n\t\t\t\tname: translate(\"server:core.errors.default.name\"),\n\t\t\t\tmessage: err.message\n\t\t\t\t\t? err.message\n\t\t\t\t\t: translate(\"server:core.errors.default.message\"),\n\t\t\t\tstatus: constants.errors.status,\n\t\t\t\terrors: constants.errors.errors,\n\t\t\t\tcode: constants.errors.code,\n\t\t\t} satisfies PublicErrorData);\n\t\t})\n\t\t.notFound((c) => {\n\t\t\tconst locale = resolveInterfaceLocale({\n\t\t\t\tconfig: props.config,\n\t\t\t\tlocale: c.req.header(constants.headers.interfaceLocale),\n\t\t\t\tacceptLanguage: c.req.header(\"Accept-Language\"),\n\t\t\t});\n\t\t\tconst translate = createTranslator({\n\t\t\t\tstore: props.translationStore,\n\t\t\t\tlocale,\n\t\t\t});\n\n\t\t\tif (c.req.url.includes(`/${constants.directories.base}/api`)) {\n\t\t\t\treturn c.json({\n\t\t\t\t\tstatus: 404,\n\t\t\t\t\tcode: \"not_found\",\n\t\t\t\t\tname: translate(\"server:core.routes.not.found\"),\n\t\t\t\t\tmessage: translate(\"server:core.routes.not.found.message\"),\n\t\t\t\t} satisfies PublicErrorData);\n\t\t\t}\n\t\t\tc.status(404);\n\t\t\treturn c.text(translate(\"server:core.pages.not.found\"));\n\t\t});\n\n\t//* HTTP extensions\n\ttry {\n\t\tregisterCustomRoutes(app, props.config.http.routes);\n\n\t\tawait runHttpExtensions({\n\t\t\tapp,\n\t\t\tconfig: props.config,\n\t\t\tpriority: 1,\n\t\t\textensions: [\n\t\t\t\t...props.config.http.extensions,\n\t\t\t\t...(props.http?.extensions ?? []),\n\t\t\t],\n\t\t});\n\n\t\tif (props.config.http.openAPI?.enabled) {\n\t\t\tapp.get(\n\t\t\t\t`/${constants.directories.base}/openapi`,\n\t\t\t\topenAPIRouteHandler(app, {\n\t\t\t\t\tdocumentation: {\n\t\t\t\t\t\topenapi: \"3.0.0\",\n\t\t\t\t\t\tinfo: {\n\t\t\t\t\t\t\ttitle: \"Lucid CMS\",\n\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\"A modern headless CMS offering a delightful developer experience. Tailor Lucid CMS seamlessly to your client and frontend requirements with our expressive brick and collection builders and extensive configuration.\",\n\t\t\t\t\t\t\tversion: packageJson.version,\n\t\t\t\t\t\t},\n\t\t\t\t\t\ttags: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: \"auth\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"Authentication endpoints including login, token management, CSRF protection and logout functionality.\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: \"account\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"User account management endpoints for user details, password resets and updating personal settings.\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: \"collections\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"Collection endpoints for returning all of the collection configuration, such as their details, config and supported bricks and fields.\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: \"documents\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"Document endpoints for creating, deleting, updating and promoting/restoring versions.\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: \"media\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"Media endpoints for creating, updating, deleting, creating upload sessions and clearing processed images.\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: \"media-folders\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"Media folder endpoints for creating, updating, deleting and fetching media folders.\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: \"media-share-links\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"Media share link endpoints for creating, updating, deleting and fetching media share links.\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: \"emails\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"Email endpoints for fetching, deleting and resending emails.\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: \"users\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"User endpoints for inviting, deleting and updating.\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: \"roles\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"Role endpoints for fetching, creating, updating and deleting.\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: \"permissions\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"Permission endpoints for fetching all available permissions.\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: \"locales\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"Locale endpoints for fetching active locales. These are the locales available for your content to be written in.\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: \"jobs\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"Job endpoints for fetching existing jobs so you can monitor them and their status.\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: \"cdn\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"CDN endpoints for streaming media files. This handles media retrieval and optional on-request image processing.\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: \"share\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"Share endpoints for accessing shared media files.\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: \"settings\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"Setting endpoints to recieve current settings and meta data on Lucid.\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: \"license\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"License endpoints for managing the license key and verifying its validity.\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: \"ai\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"AI endpoints for generating CMS content with Lucid AI features.\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: \"client-integrations\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"Endpoints for managing client integration credentials used to authenticate external applications accessing CMS content via client endpoints.\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: \"client-documents\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"Client document endpoints for fetching single and multiple documents via the client integration authentication.\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: \"client-previews\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"Client preview endpoints for resolving preview metadata in browser applications.\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: \"client-locales\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"Client locale endpoints for fetching locale information.\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\tservers: configuredHost\n\t\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\turl: configuredHost.includes(\"[::1]\")\n\t\t\t\t\t\t\t\t\t\t\t? configuredHost.replace(\"[::1]\", \"localhost\")\n\t\t\t\t\t\t\t\t\t\t\t: configuredHost,\n\t\t\t\t\t\t\t\t\t\tdescription: \"Development server\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t: [],\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t);\n\t\t\tapp.get(\n\t\t\t\tconstants.openAPIDocsRoute,\n\t\t\t\tScalar({\n\t\t\t\t\turl: `/${constants.directories.base}/openapi`,\n\t\t\t\t\ttheme: \"saturn\",\n\t\t\t\t\tdefaultHttpClient: {\n\t\t\t\t\t\ttargetKey: \"node\",\n\t\t\t\t\t\tclientKey: \"fetch\",\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\tawait runHttpExtensions({\n\t\t\tapp,\n\t\t\tconfig: props.config,\n\t\t\tpriority: 2,\n\t\t\textensions: [\n\t\t\t\t...props.config.http.extensions,\n\t\t\t\t...(props.http?.extensions ?? []),\n\t\t\t],\n\t\t});\n\t} catch (error) {\n\t\tawait destroyAdapterInstances();\n\t\tawait destroyLogger();\n\t\tthrow error;\n\t}\n\n\tconst supportChecksRes = featureSupportChecks(\n\t\t{\n\t\t\tqueue: queueInstance.key,\n\t\t\tkv: kvInstance.key,\n\t\t\tmedia: mediaInstance?.key ?? null,\n\t\t\temail: emailInstance.key,\n\t\t\tdatabase: props.config.db.adapter,\n\t\t},\n\t\tprops.runtimeContext.support,\n\t);\n\n\tlet destroyPromise: Promise<void> | undefined;\n\n\treturn {\n\t\thandle: (options: {\n\t\t\trequest: Request;\n\t\t\tdatabase: DatabaseConnection;\n\t\t\tenv?: EnvironmentVariables;\n\t\t\texecutionContext?: unknown;\n\t\t\trequestBindings?: object;\n\t\t}) =>\n\t\t\tapp.fetch(\n\t\t\t\toptions.request,\n\t\t\t\tcreateInvocationBindings(\n\t\t\t\t\t{\n\t\t\t\t\t\tdatabase: options.database,\n\t\t\t\t\t\tenv: options.env,\n\t\t\t\t\t},\n\t\t\t\t\toptions.requestBindings,\n\t\t\t\t),\n\t\t\t\toptions.executionContext as Parameters<typeof app.fetch>[2],\n\t\t\t),\n\t\tqueue: queueInstance,\n\t\tkv: kvInstance,\n\t\tmedia: mediaInstance,\n\t\temail: emailInstance,\n\t\tissues: supportChecksRes.issues,\n\t\tdestroy: () => {\n\t\t\tdestroyPromise ??= (async () => {\n\t\t\t\tawait destroyAdapterInstances();\n\t\t\t\tawait destroyLogger();\n\t\t\t})();\n\n\t\t\treturn destroyPromise;\n\t\t},\n\t};\n};\n\nexport default createApp;\n"],"mappings":"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U,YAAY,KAAK,KAAK,EACnD,EAAE,KAAK,CACb,OAAQ,IACR,KAAM,YACN,KAAM,EAAU,8BAA8B,EAC9C,QAAS,EAAU,sCAAsC,CAC1D,CAA2B,GAE5B,EAAE,OAAO,GAAG,EACL,EAAE,KAAK,EAAU,6BAA6B,CAAC,EACvD,CAAC,EAGF,GAAI,CACH,EAAqB,EAAK,EAAM,OAAO,KAAK,MAAM,EAElD,MAAM,EAAkB,CACvB,MACA,OAAQ,EAAM,OACd,SAAU,EACV,WAAY,CACX,GAAG,EAAM,OAAO,KAAK,WACrB,GAAI,EAAM,MAAM,YAAc,CAAC,CAChC,CACD,CAAC,EAEG,EAAM,OAAO,KAAK,SAAS,UAC9B,EAAI,IACH,IAAIA,EAAU,YAAY,KAAK,UAC/B,EAAoB,EAAK,CACxB,cAAe,CACd,QAAS,QACT,KAAM,CACL,MAAO,YACP,YACC,wNACQC,SACV,EACA,KAAM,CACL,CACC,KAAM,OACN,YACC,uGACF,EACA,CACC,KAAM,UACN,YACC,qGACF,EACA,CACC,KAAM,cACN,YACC,wIACF,EACA,CACC,KAAM,YACN,YACC,uFACF,EACA,CACC,KAAM,QACN,YACC,2GACF,EACA,CACC,KAAM,gBACN,YACC,qFACF,EACA,CACC,KAAM,oBACN,YACC,6FACF,EACA,CACC,KAAM,SACN,YACC,8DACF,EACA,CACC,KAAM,QACN,YACC,qDACF,EACA,CACC,KAAM,QACN,YACC,+DACF,EACA,CACC,KAAM,cACN,YACC,8DACF,EACA,CACC,KAAM,UACN,YACC,kHACF,EACA,CACC,KAAM,OACN,YACC,oFACF,EACA,CACC,KAAM,MACN,YACC,iHACF,EACA,CACC,KAAM,QACN,YACC,mDACF,EACA,CACC,KAAM,WACN,YACC,uEACF,EACA,CACC,KAAM,UACN,YACC,4EACF,EACA,CACC,KAAM,KACN,YACC,iEACF,EACA,CACC,KAAM,sBACN,YACC,8IACF,EACA,CACC,KAAM,mBACN,YACC,iHACF,EACA,CACC,KAAM,kBACN,YACC,kFACF,EACA,CACC,KAAM,iBACN,YACC,0DACF,CACD,EACA,QAAS,EACN,CACA,CACC,IAAK,EAAe,SAAS,OAAO,EACjC,EAAe,QAAQ,QAAS,WAAW,EAC3C,EACH,YAAa,oBACd,CACD,EACC,CAAC,CACL,CACD,CAAC,CACF,EACA,EAAI,IACHD,EAAU,iBACV,EAAO,CACN,IAAK,IAAIA,EAAU,YAAY,KAAK,UACpC,MAAO,SACP,kBAAmB,CAClB,UAAW,OACX,UAAW,OACZ,CACD,CAAC,CACF,GAGD,MAAM,EAAkB,CACvB,MACA,OAAQ,EAAM,OACd,SAAU,EACV,WAAY,CACX,GAAG,EAAM,OAAO,KAAK,WACrB,GAAI,EAAM,MAAM,YAAc,CAAC,CAChC,CACD,CAAC,CACF,OAAS,EAAO,CAGf,MAFA,MAAM,EAAwB,EAC9B,MAAM,EAAc,EACd,CACP,CAEA,IAAM,EAAmB,EACxB,CACC,MAAO,EAAc,IACrB,GAAI,EAAW,IACf,MAAO,GAAe,KAAO,KAC7B,MAAO,EAAc,IACrB,SAAU,EAAM,OAAO,GAAG,OAC3B,EACA,EAAM,eAAe,OACtB,EAEI,EAEJ,MAAO,CACN,OAAS,GAOR,EAAI,MACH,EAAQ,QACR,EACC,CACC,SAAU,EAAQ,SAClB,IAAK,EAAQ,GACd,EACA,EAAQ,eACT,EACA,EAAQ,gBACT,EACD,MAAO,EACP,GAAI,EACJ,MAAO,EACP,MAAO,EACP,OAAQ,EAAiB,OACzB,aACC,KAAoB,SAAY,CAC/B,MAAM,EAAwB,EAC9B,MAAM,EAAc,CACrB,EAAA,CAAG,EAEI,EAET,CACD"}