{"version":3,"file":"create-lucid-host.mjs","names":[],"sources":["../../../src/libs/runtime/create-lucid-host.ts"],"sourcesContent":["import type z from \"zod\";\nimport type { Config } from \"../../types/config.js\";\nimport createServiceContext from \"../../utils/services/create-service-context.js\";\nimport type { ServiceContext } from \"../../utils/services/types.js\";\nimport { resolveConfigDefinition } from \"../config/resolve-config-definition.js\";\nimport type { DatabaseConnection } from \"../db/types.js\";\nimport createApp from \"../http/app.js\";\nimport type { HttpExtension } from \"../http/types.js\";\nimport prepareTranslations from \"../i18n/prepare-translations.js\";\nimport type { TranslationBundles, TranslationStore } from \"../i18n/types.js\";\nimport createToolkit from \"../toolkit/create-toolkit.js\";\nimport type {\n\tCreateToolkitServiceContextOptions,\n\tToolkit,\n} from \"../toolkit/types.js\";\nimport type {\n\tAdapterRuntimeContext,\n\tDatabaseConnectionScope,\n\tEnvironmentVariables,\n\tLucidConfigDefinition,\n\tLucidConfigDefinitionMeta,\n} from \"./types.js\";\n\ntype CreateLucidHostSharedOptions = {\n\truntimeContext: AdapterRuntimeContext;\n\thttp?: {\n\t\textensions?: HttpExtension[];\n\t};\n\t/** Determines who owns live database connections created by this host. */\n\tdatabaseScope: DatabaseConnectionScope;\n};\n\n/** Options used to create a Lucid instance within another framework or host. */\nexport type CreateLucidHostOptions = CreateLucidHostSharedOptions &\n\t(\n\t\t| {\n\t\t\t\tdefinition: LucidConfigDefinition;\n\t\t\t\tenvSchema?: z.ZodType;\n\t\t\t\tenv?: EnvironmentVariables;\n\t\t\t\ttranslationBundles?: TranslationBundles;\n\t\t\t\tmeta?: LucidConfigDefinitionMeta;\n\t\t  }\n\t\t| {\n\t\t\t\tconfig: Config;\n\t\t\t\ttranslationStore: TranslationStore;\n\t\t\t\tenv?: EnvironmentVariables;\n\t\t  }\n\t);\n\n/** One request, scheduled event or other runtime invocation of a Lucid host. */\nexport type LucidInvocation = {\n\t/** Returns the fully initialized service context for this invocation. */\n\tgetServiceContext(\n\t\trequest?: CreateToolkitServiceContextOptions[\"request\"],\n\t): Promise<ServiceContext>;\n\t/** Returns a public toolkit backed by this invocation. */\n\tgetToolkit(\n\t\trequest?: CreateToolkitServiceContextOptions[\"request\"],\n\t): Promise<Toolkit>;\n\t/** Handles an HTTP request using this invocation's database connection. */\n\thandle(options: {\n\t\trequest: Request;\n\t\texecutionContext?: unknown;\n\t\trequestBindings?: object;\n\t}): Promise<Response>;\n\t/** Releases resources owned by this invocation. */\n\tdestroy(): Promise<void>;\n};\n\n/** An initialized Lucid application host owned by an external runtime. */\nexport type LucidHost = {\n\tconfig: Config;\n\tenv?: EnvironmentVariables;\n\truntimeContext: AdapterRuntimeContext;\n\ttranslationStore: TranslationStore;\n\tissues: Awaited<ReturnType<typeof createApp>>[\"issues\"];\n\tcreateInvocation(options?: { env?: EnvironmentVariables }): LucidInvocation;\n\tdestroy(): Promise<void>;\n};\n\n/** Creates a fully initialized application host with explicit invocation lifecycles. */\nconst createLucidHost = async (\n\toptions: CreateLucidHostOptions,\n): Promise<LucidHost> => {\n\tconst resolved =\n\t\t\"config\" in options\n\t\t\t? {\n\t\t\t\t\tconfig: options.config,\n\t\t\t\t\tenv: options.env,\n\t\t\t\t}\n\t\t\t: await resolveConfigDefinition({\n\t\t\t\t\tdefinition: options.definition,\n\t\t\t\t\tenvSchema: options.envSchema,\n\t\t\t\t\tenv: options.env,\n\t\t\t\t\tmeta: options.meta,\n\t\t\t\t\tprocessConfigOptions: {\n\t\t\t\t\t\tskipValidation: true,\n\t\t\t\t\t},\n\t\t\t\t});\n\tconst translationStore =\n\t\t\"translationStore\" in options\n\t\t\t? options.translationStore\n\t\t\t: (\n\t\t\t\t\tawait prepareTranslations({\n\t\t\t\t\t\tconfig: resolved.config,\n\t\t\t\t\t\tbundles: options.translationBundles,\n\t\t\t\t\t})\n\t\t\t\t).translationStore;\n\tconst app = await createApp({\n\t\tconfig: resolved.config,\n\t\ttranslationStore,\n\t\tenv: resolved.env,\n\t\truntimeContext: options.runtimeContext,\n\t\thttp: options.http,\n\t});\n\tlet runtimeDatabasePromise: Promise<DatabaseConnection> | undefined;\n\tlet destroyed = false;\n\tlet destroyPromise: Promise<void> | undefined;\n\tconst activeInvocations = new Set<LucidInvocation>();\n\n\tconst createDatabase = (env?: EnvironmentVariables) =>\n\t\tresolved.config.db.connect(env ?? {});\n\n\tconst getRuntimeDatabase = () => {\n\t\tif (!runtimeDatabasePromise) {\n\t\t\truntimeDatabasePromise = Promise.resolve(\n\t\t\t\tcreateDatabase(resolved.env),\n\t\t\t).catch((error) => {\n\t\t\t\truntimeDatabasePromise = undefined;\n\t\t\t\tthrow error;\n\t\t\t});\n\t\t}\n\t\treturn runtimeDatabasePromise;\n\t};\n\n\tconst host: LucidHost = {\n\t\tconfig: resolved.config,\n\t\tenv: resolved.env,\n\t\truntimeContext: options.runtimeContext,\n\t\ttranslationStore,\n\t\tissues: app.issues,\n\t\tcreateInvocation: (invocationOptions?: {\n\t\t\tenv?: EnvironmentVariables;\n\t\t}): LucidInvocation => {\n\t\t\tif (destroyed) {\n\t\t\t\tthrow new Error(\"Cannot use a Lucid host after it has been destroyed.\");\n\t\t\t}\n\t\t\tconst env = invocationOptions?.env ?? resolved.env;\n\t\t\tlet invocationDatabasePromise: Promise<DatabaseConnection> | undefined;\n\t\t\tlet invocationDestroyed = false;\n\t\t\tlet invocationDestroyPromise: Promise<void> | undefined;\n\n\t\t\tconst getDatabase = () => {\n\t\t\t\tif (destroyed) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"Cannot use a Lucid host after it has been destroyed.\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (invocationDestroyed) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"Cannot use a Lucid invocation after it has been destroyed.\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (options.databaseScope === \"runtime\") {\n\t\t\t\t\treturn getRuntimeDatabase();\n\t\t\t\t}\n\t\t\t\tif (!invocationDatabasePromise) {\n\t\t\t\t\tinvocationDatabasePromise = Promise.resolve(\n\t\t\t\t\t\tcreateDatabase(env),\n\t\t\t\t\t).catch((error) => {\n\t\t\t\t\t\tinvocationDatabasePromise = undefined;\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn invocationDatabasePromise;\n\t\t\t};\n\n\t\t\tconst getServiceContext = async (\n\t\t\t\trequest?: CreateToolkitServiceContextOptions[\"request\"],\n\t\t\t): Promise<ServiceContext> => {\n\t\t\t\tconst database = await getDatabase();\n\t\t\t\treturn createServiceContext({\n\t\t\t\t\tconfig: resolved.config,\n\t\t\t\t\tdatabase,\n\t\t\t\t\ttranslationStore,\n\t\t\t\t\tenv,\n\t\t\t\t\truntimeContext: options.runtimeContext,\n\t\t\t\t\tqueue: app.queue,\n\t\t\t\t\tkv: app.kv,\n\t\t\t\t\tmedia: app.media,\n\t\t\t\t\temail: app.email,\n\t\t\t\t\trequest,\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tconst invocation: LucidInvocation = {\n\t\t\t\tgetServiceContext,\n\t\t\t\tgetToolkit: async (request) =>\n\t\t\t\t\tcreateToolkit(await getServiceContext(request)),\n\t\t\t\thandle: async (handleOptions): Promise<Response> => {\n\t\t\t\t\tconst database = await getDatabase();\n\t\t\t\t\treturn app.handle({\n\t\t\t\t\t\trequest: handleOptions.request,\n\t\t\t\t\t\tdatabase,\n\t\t\t\t\t\tenv,\n\t\t\t\t\t\texecutionContext: handleOptions.executionContext,\n\t\t\t\t\t\trequestBindings: handleOptions.requestBindings,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\tdestroy: async () => {\n\t\t\t\t\tinvocationDestroyPromise ??= (async () => {\n\t\t\t\t\t\tinvocationDestroyed = true;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\toptions.databaseScope === \"invocation\" &&\n\t\t\t\t\t\t\t\tinvocationDatabasePromise\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tconst result = await Promise.allSettled([\n\t\t\t\t\t\t\t\t\tinvocationDatabasePromise,\n\t\t\t\t\t\t\t\t]);\n\t\t\t\t\t\t\t\tconst connection = result[0];\n\t\t\t\t\t\t\t\tif (connection?.status === \"fulfilled\") {\n\t\t\t\t\t\t\t\t\tawait Promise.allSettled([connection.value.destroy()]);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} finally {\n\t\t\t\t\t\t\tactiveInvocations.delete(invocation);\n\t\t\t\t\t\t}\n\t\t\t\t\t})();\n\t\t\t\t\treturn invocationDestroyPromise;\n\t\t\t\t},\n\t\t\t};\n\t\t\tactiveInvocations.add(invocation);\n\t\t\treturn invocation;\n\t\t},\n\t\tdestroy: async () => {\n\t\t\tdestroyPromise ??= (async () => {\n\t\t\t\tdestroyed = true;\n\t\t\t\tawait Promise.allSettled(\n\t\t\t\t\tArray.from(activeInvocations, (invocation) => invocation.destroy()),\n\t\t\t\t);\n\t\t\t\tconst [databaseResult] = await Promise.allSettled([\n\t\t\t\t\truntimeDatabasePromise,\n\t\t\t\t]);\n\t\t\t\tconst database =\n\t\t\t\t\tdatabaseResult.status === \"fulfilled\"\n\t\t\t\t\t\t? databaseResult.value\n\t\t\t\t\t\t: undefined;\n\t\t\t\tawait Promise.allSettled([app.destroy(), database?.destroy()]);\n\t\t\t})();\n\t\t\treturn destroyPromise;\n\t\t},\n\t};\n\treturn host;\n};\n\nexport default createLucidHost;\n"],"mappings":"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"}