stratal 0.0.20 → 0.0.21
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/dist/base-email.provider-CfQCA08m.mjs.map +1 -1
- package/dist/bin/cloudflare-workers-loader.mjs.map +1 -1
- package/dist/bin/quarry.mjs.map +1 -1
- package/dist/cache/index.d.mts +1 -1
- package/dist/cache/index.mjs +5 -3
- package/dist/cache/index.mjs.map +1 -1
- package/dist/command-BgSlsS4M.mjs.map +1 -1
- package/dist/{command-Bu-PjJrX.d.mts → command-Cmmf0oHX.d.mts} +2 -2
- package/dist/{command-Bu-PjJrX.d.mts.map → command-Cmmf0oHX.d.mts.map} +1 -1
- package/dist/config/index.d.mts +1 -1
- package/dist/config/index.mjs +5 -3
- package/dist/config/index.mjs.map +1 -1
- package/dist/{controller.decorator-DQzenvSN.mjs → controller.decorator-B9vwn0zK.mjs} +3 -3
- package/dist/{controller.decorator-DQzenvSN.mjs.map → controller.decorator-B9vwn0zK.mjs.map} +1 -1
- package/dist/cron/index.d.mts +2 -2
- package/dist/cron/index.mjs +1 -1
- package/dist/{cron-manager-BEsH1mjW.d.mts → cron-manager-CmTimEjf.d.mts} +2 -2
- package/dist/cron-manager-CmTimEjf.d.mts.map +1 -0
- package/dist/{cron-manager-7Symz_TE.mjs → cron-manager-DQSK8uoV.mjs} +10 -4
- package/dist/cron-manager-DQSK8uoV.mjs.map +1 -0
- package/dist/di/index.d.mts +1 -1
- package/dist/di/index.mjs +2 -2
- package/dist/email/index.d.mts +2 -2
- package/dist/email/index.mjs +12 -7
- package/dist/email/index.mjs.map +1 -1
- package/dist/errors/index.d.mts +1 -1
- package/dist/errors/index.mjs +1 -1
- package/dist/{errors-BdyV5PnY.mjs → errors-COW9-Mar.mjs} +16 -2
- package/dist/{errors-BdyV5PnY.mjs.map → errors-COW9-Mar.mjs.map} +1 -1
- package/dist/{errors-Da3Pz2X7.mjs → errors-ORxu1-Bb.mjs} +2 -2
- package/dist/{errors-Da3Pz2X7.mjs.map → errors-ORxu1-Bb.mjs.map} +1 -1
- package/dist/events/index.mjs +1 -1
- package/dist/{events-COKixqnG.mjs → events-CzCV8jI8.mjs} +4 -2
- package/dist/{events-COKixqnG.mjs.map → events-CzCV8jI8.mjs.map} +1 -1
- package/dist/{gateway-context-CdJjpUCW.mjs → gateway-context-CXmXtaUP.mjs} +4 -3
- package/dist/{gateway-context-CdJjpUCW.mjs.map → gateway-context-CXmXtaUP.mjs.map} +1 -1
- package/dist/guards/index.d.mts +1 -1
- package/dist/guards/index.mjs +1 -1
- package/dist/{guards-DUk_Kzst.mjs → guards-DU1_J9YA.mjs} +2 -1
- package/dist/{guards-DUk_Kzst.mjs.map → guards-DU1_J9YA.mjs.map} +1 -1
- package/dist/{http-method.decorator-DXwxAfb_.mjs → http-method.decorator-BrgHMdLQ.mjs} +2 -2
- package/dist/{http-method.decorator-DXwxAfb_.mjs.map → http-method.decorator-BrgHMdLQ.mjs.map} +1 -1
- package/dist/i18n/index.d.mts +1 -1
- package/dist/i18n/index.mjs +2 -2
- package/dist/{i18n.module-BBlNNlcG.mjs → i18n.module-CzXLW9Hy.mjs} +59 -19
- package/dist/i18n.module-CzXLW9Hy.mjs.map +1 -0
- package/dist/{index-D0US0X14.d.mts → index-ByOyTmqf.d.mts} +6 -3
- package/dist/{index-D0US0X14.d.mts.map → index-ByOyTmqf.d.mts.map} +1 -1
- package/dist/{index-CjaQ6_tZ.d.mts → index-DUzWs0z7.d.mts} +2 -2
- package/dist/{index-CjaQ6_tZ.d.mts.map → index-DUzWs0z7.d.mts.map} +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/is-command-C6a7WTPw.mjs.map +1 -1
- package/dist/is-seeder-CebjZCDn.mjs.map +1 -1
- package/dist/logger/index.mjs +1 -1
- package/dist/{logger-V6Ms3QnQ.mjs → logger-DlV7NtvD.mjs} +8 -4
- package/dist/{logger-V6Ms3QnQ.mjs.map → logger-DlV7NtvD.mjs.map} +1 -1
- package/dist/macroable-BmufBshB.mjs.map +1 -1
- package/dist/module/index.d.mts +1 -1
- package/dist/module/index.mjs +1 -1
- package/dist/{module-Dk2qTa77.mjs → module-BzLg57FK.mjs} +10 -4
- package/dist/{module-Dk2qTa77.mjs.map → module-BzLg57FK.mjs.map} +1 -1
- package/dist/openapi/index.d.mts +2 -2
- package/dist/openapi/index.mjs +1 -1
- package/dist/openapi-tools.service-Zs-Ewv7F.mjs.map +1 -1
- package/dist/{openapi.service-BLgvn3hJ.d.mts → openapi.service-Bt9bCIrd.d.mts} +2 -2
- package/dist/{openapi.service-BLgvn3hJ.d.mts.map → openapi.service-Bt9bCIrd.d.mts.map} +1 -1
- package/dist/quarry/index.d.mts +4 -4
- package/dist/quarry/index.mjs +1 -1
- package/dist/{quarry-registry-DNEej-Db.mjs → quarry-registry-BwY2hOxm.mjs} +15 -4
- package/dist/{quarry-registry-DNEej-Db.mjs.map → quarry-registry-BwY2hOxm.mjs.map} +1 -1
- package/dist/queue/index.d.mts +1 -1
- package/dist/queue/index.mjs +3 -2
- package/dist/queue/index.mjs.map +1 -1
- package/dist/{queue.module-BCdCiySt.mjs → queue.module-BhCjZp6H.mjs} +13 -4
- package/dist/{queue.module-BCdCiySt.mjs.map → queue.module-BhCjZp6H.mjs.map} +1 -1
- package/dist/{r2-storage.provider-Co6F0ZYV.mjs → r2-storage.provider-DuonKeYm.mjs} +5 -2
- package/dist/{r2-storage.provider-Co6F0ZYV.mjs.map → r2-storage.provider-DuonKeYm.mjs.map} +1 -1
- package/dist/{rate-limit.decorator--o6Q6p9w.mjs → rate-limit.decorator-6qzNcSOt.mjs} +2 -2
- package/dist/{rate-limit.decorator--o6Q6p9w.mjs.map → rate-limit.decorator-6qzNcSOt.mjs.map} +1 -1
- package/dist/rate-limiter/index.d.mts +1 -1
- package/dist/rate-limiter/index.mjs +13 -4
- package/dist/rate-limiter/index.mjs.map +1 -1
- package/dist/{resend.provider-M6qRLrcy.mjs → resend.provider-DB4IlFjG.mjs} +2 -1
- package/dist/{resend.provider-M6qRLrcy.mjs.map → resend.provider-DB4IlFjG.mjs.map} +1 -1
- package/dist/router/index.d.mts +1 -1
- package/dist/router/index.mjs +5 -5
- package/dist/seeder/index.d.mts +2 -2
- package/dist/seeder/index.mjs +1 -1
- package/dist/{seeder-CJAOHEIo.mjs → seeder-zoEfEw9i.mjs} +6 -3
- package/dist/{seeder-CJAOHEIo.mjs.map → seeder-zoEfEw9i.mjs.map} +1 -1
- package/dist/setup-CefZKV_e.mjs.map +1 -1
- package/dist/signed-url-BQPbv2In.mjs.map +1 -1
- package/dist/{smtp.provider-w0Ve52Xg.mjs → smtp.provider-B6D7zuWX.mjs} +2 -1
- package/dist/{smtp.provider-w0Ve52Xg.mjs.map → smtp.provider-B6D7zuWX.mjs.map} +1 -1
- package/dist/storage/index.d.mts +1 -1
- package/dist/storage/index.mjs +2 -2
- package/dist/storage/providers/index.mjs +1 -1
- package/dist/{storage-1zw-6Yiz.mjs → storage-D8CBP72Z.mjs} +13 -8
- package/dist/{storage-1zw-6Yiz.mjs.map → storage-D8CBP72Z.mjs.map} +1 -1
- package/dist/{stratal-DeEcGgdq.mjs → stratal-CNwpbSZl.mjs} +12 -10
- package/dist/{stratal-DeEcGgdq.mjs.map → stratal-CNwpbSZl.mjs.map} +1 -1
- package/dist/usage-generator-BUdlhnCK.mjs.map +1 -1
- package/dist/validation-DtJwAv7O.mjs.map +1 -1
- package/dist/websocket/index.d.mts +1 -1
- package/dist/websocket/index.mjs +1 -1
- package/dist/workers/index.d.mts +1 -1
- package/dist/workers/index.mjs +2 -2
- package/dist/workers/index.mjs.map +1 -1
- package/package.json +13 -13
- package/dist/cron-manager-7Symz_TE.mjs.map +0 -1
- package/dist/cron-manager-BEsH1mjW.d.mts.map +0 -1
- package/dist/i18n.module-BBlNNlcG.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-email.provider-CfQCA08m.mjs","names":[],"sources":["../src/email/providers/base-email.provider.ts"],"sourcesContent":["import type { ResolvedEmailMessage } from '../contracts'\nimport type { EmailBatchSendResult, EmailSendResult, IEmailProvider } from './email-provider.interface'\n\n/**\n * Base Email Provider\n *\n * Abstract base class for email providers.\n * Provides shared implementation of sendBatch() to reduce code duplication.\n */\nexport abstract class BaseEmailProvider implements IEmailProvider {\n /**\n * Send a single email - must be implemented by concrete providers\n */\n abstract send(message: ResolvedEmailMessage): Promise<EmailSendResult>\n\n /**\n * Send multiple emails in a batch\n *\n * Default implementation sends emails sequentially.\n * Concrete providers can override for optimized batch sending.\n */\n async sendBatch(messages: ResolvedEmailMessage[]): Promise<EmailBatchSendResult> {\n const results: EmailSendResult[] = []\n let successful = 0\n let failed = 0\n\n for (const message of messages) {\n try {\n const result = await this.send(message)\n results.push(result)\n successful++\n }\n catch (error) {\n results.push({\n messageId: '',\n accepted: false,\n metadata: {\n error: error instanceof Error ? error.message : 'Unknown error',\n },\n })\n failed++\n }\n }\n\n return {\n total: messages.length,\n successful,\n failed,\n results,\n }\n }\n}\n"],"mappings":";;;;;;;AASA,IAAsB,oBAAtB,MAAkE;;;;;;;CAYhE,MAAM,UAAU,UAAiE;EAC/E,MAAM,UAA6B,EAAE;EACrC,IAAI,aAAa;EACjB,IAAI,SAAS;
|
|
1
|
+
{"version":3,"file":"base-email.provider-CfQCA08m.mjs","names":[],"sources":["../src/email/providers/base-email.provider.ts"],"sourcesContent":["import type { ResolvedEmailMessage } from '../contracts'\nimport type { EmailBatchSendResult, EmailSendResult, IEmailProvider } from './email-provider.interface'\n\n/**\n * Base Email Provider\n *\n * Abstract base class for email providers.\n * Provides shared implementation of sendBatch() to reduce code duplication.\n */\nexport abstract class BaseEmailProvider implements IEmailProvider {\n /**\n * Send a single email - must be implemented by concrete providers\n */\n abstract send(message: ResolvedEmailMessage): Promise<EmailSendResult>\n\n /**\n * Send multiple emails in a batch\n *\n * Default implementation sends emails sequentially.\n * Concrete providers can override for optimized batch sending.\n */\n async sendBatch(messages: ResolvedEmailMessage[]): Promise<EmailBatchSendResult> {\n const results: EmailSendResult[] = []\n let successful = 0\n let failed = 0\n\n for (const message of messages) {\n try {\n const result = await this.send(message)\n results.push(result)\n successful++\n }\n catch (error) {\n results.push({\n messageId: '',\n accepted: false,\n metadata: {\n error: error instanceof Error ? error.message : 'Unknown error',\n },\n })\n failed++\n }\n }\n\n return {\n total: messages.length,\n successful,\n failed,\n results,\n }\n }\n}\n"],"mappings":";;;;;;;AASA,IAAsB,oBAAtB,MAAkE;;;;;;;CAYhE,MAAM,UAAU,UAAiE;EAC/E,MAAM,UAA6B,EAAE;EACrC,IAAI,aAAa;EACjB,IAAI,SAAS;EAEb,KAAK,MAAM,WAAW,UACpB,IAAI;GACF,MAAM,SAAS,MAAM,KAAK,KAAK,QAAQ;GACvC,QAAQ,KAAK,OAAO;GACpB;WAEK,OAAO;GACZ,QAAQ,KAAK;IACX,WAAW;IACX,UAAU;IACV,UAAU,EACR,OAAO,iBAAiB,QAAQ,MAAM,UAAU,iBACjD;IACF,CAAC;GACF;;EAIJ,OAAO;GACL,OAAO,SAAS;GAChB;GACA;GACA;GACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloudflare-workers-loader.mjs","names":[],"sources":["../../src/bin/cloudflare-workers-loader.ts"],"sourcesContent":["/**\n * ESM loader hook that provides a virtual `cloudflare:workers` module\n * and handles Vite-style `?raw` imports (returning file contents as a string).\n *\n * When registered via `node --import` or `register()`, this intercepts\n * `import('cloudflare:workers')` and returns a module that reads `env`\n * and `waitUntil` from `globalThis.__stratalPlatformProxy`.\n */\n\nimport { readFileSync } from 'node:fs'\nimport { fileURLToPath } from 'node:url'\n\nconst VIRTUAL_URL = 'cloudflare-workers:virtual'\nconst RAW_SUFFIX = '?raw'\n\ninterface ResolveContext {\n parentURL?: string\n conditions: string[]\n}\n\ninterface ResolveResult {\n url: string\n shortCircuit?: boolean\n}\n\ntype NextResolve = (specifier: string, context: ResolveContext) => Promise<ResolveResult>\n\nexport async function resolve(\n specifier: string,\n context: ResolveContext,\n nextResolve: NextResolve,\n): Promise<ResolveResult> {\n if (specifier === 'cloudflare:workers') {\n return { url: VIRTUAL_URL, shortCircuit: true }\n }\n if (specifier.endsWith(RAW_SUFFIX)) {\n const base = specifier.slice(0, -RAW_SUFFIX.length)\n const resolved = await nextResolve(base, context)\n return { url: resolved.url + RAW_SUFFIX, shortCircuit: true }\n }\n return nextResolve(specifier, context)\n}\n\ninterface LoadContext {\n format?: string\n conditions: string[]\n}\n\ninterface LoadResult {\n format: string\n source: string\n shortCircuit?: boolean\n}\n\ntype NextLoad = (url: string, context: LoadContext) => Promise<LoadResult>\n\nexport async function load(\n url: string,\n context: LoadContext,\n nextLoad: NextLoad,\n): Promise<LoadResult> {\n if (url.endsWith(RAW_SUFFIX)) {\n const fileUrl = url.slice(0, -RAW_SUFFIX.length)\n const filePath = fileURLToPath(fileUrl)\n const content = readFileSync(filePath, 'utf-8')\n return {\n format: 'module',\n shortCircuit: true,\n source: `export default ${JSON.stringify(content)}`,\n }\n }\n if (url === VIRTUAL_URL) {\n return {\n format: 'module',\n shortCircuit: true,\n source: `\nconst proxy = globalThis.__stratalPlatformProxy;\nif (!proxy) throw new Error('globalThis.__stratalPlatformProxy not set — Quarry CLI must initialize it before importing the app entry.');\nexport const env = proxy.env;\nexport const waitUntil = proxy.waitUntil;\nexport const exports = {}\nexport class DurableObject {\n constructor(ctx, env) { this.ctx = ctx; this.env = env; }\n}\nexport class WorkerEntrypoint {\n constructor(ctx, env) { this.ctx = ctx; this.env = env; }\n}\nexport class WorkflowEntrypoint {\n constructor(ctx, env) { this.ctx = ctx; this.env = env; }\n}\nexport class WorkflowStep {}\nexport class RpcTarget {}\nexport const RpcStub = function(value) { return value; };\nexport function withEnv(newEnv, fn) { return fn(); }\nexport function withExports(newExports, fn) { return fn(); }\nexport function withEnvAndExports(newEnv, newExports, fn) { return fn(); }\n`,\n }\n }\n return nextLoad(url, context)\n}\n"],"mappings":";;;;;;;;;;;;AAYA,MAAM,cAAc;AACpB,MAAM,aAAa;AAcnB,eAAsB,QACpB,WACA,SACA,aACwB;
|
|
1
|
+
{"version":3,"file":"cloudflare-workers-loader.mjs","names":[],"sources":["../../src/bin/cloudflare-workers-loader.ts"],"sourcesContent":["/**\n * ESM loader hook that provides a virtual `cloudflare:workers` module\n * and handles Vite-style `?raw` imports (returning file contents as a string).\n *\n * When registered via `node --import` or `register()`, this intercepts\n * `import('cloudflare:workers')` and returns a module that reads `env`\n * and `waitUntil` from `globalThis.__stratalPlatformProxy`.\n */\n\nimport { readFileSync } from 'node:fs'\nimport { fileURLToPath } from 'node:url'\n\nconst VIRTUAL_URL = 'cloudflare-workers:virtual'\nconst RAW_SUFFIX = '?raw'\n\ninterface ResolveContext {\n parentURL?: string\n conditions: string[]\n}\n\ninterface ResolveResult {\n url: string\n shortCircuit?: boolean\n}\n\ntype NextResolve = (specifier: string, context: ResolveContext) => Promise<ResolveResult>\n\nexport async function resolve(\n specifier: string,\n context: ResolveContext,\n nextResolve: NextResolve,\n): Promise<ResolveResult> {\n if (specifier === 'cloudflare:workers') {\n return { url: VIRTUAL_URL, shortCircuit: true }\n }\n if (specifier.endsWith(RAW_SUFFIX)) {\n const base = specifier.slice(0, -RAW_SUFFIX.length)\n const resolved = await nextResolve(base, context)\n return { url: resolved.url + RAW_SUFFIX, shortCircuit: true }\n }\n return nextResolve(specifier, context)\n}\n\ninterface LoadContext {\n format?: string\n conditions: string[]\n}\n\ninterface LoadResult {\n format: string\n source: string\n shortCircuit?: boolean\n}\n\ntype NextLoad = (url: string, context: LoadContext) => Promise<LoadResult>\n\nexport async function load(\n url: string,\n context: LoadContext,\n nextLoad: NextLoad,\n): Promise<LoadResult> {\n if (url.endsWith(RAW_SUFFIX)) {\n const fileUrl = url.slice(0, -RAW_SUFFIX.length)\n const filePath = fileURLToPath(fileUrl)\n const content = readFileSync(filePath, 'utf-8')\n return {\n format: 'module',\n shortCircuit: true,\n source: `export default ${JSON.stringify(content)}`,\n }\n }\n if (url === VIRTUAL_URL) {\n return {\n format: 'module',\n shortCircuit: true,\n source: `\nconst proxy = globalThis.__stratalPlatformProxy;\nif (!proxy) throw new Error('globalThis.__stratalPlatformProxy not set — Quarry CLI must initialize it before importing the app entry.');\nexport const env = proxy.env;\nexport const waitUntil = proxy.waitUntil;\nexport const exports = {}\nexport class DurableObject {\n constructor(ctx, env) { this.ctx = ctx; this.env = env; }\n}\nexport class WorkerEntrypoint {\n constructor(ctx, env) { this.ctx = ctx; this.env = env; }\n}\nexport class WorkflowEntrypoint {\n constructor(ctx, env) { this.ctx = ctx; this.env = env; }\n}\nexport class WorkflowStep {}\nexport class RpcTarget {}\nexport const RpcStub = function(value) { return value; };\nexport function withEnv(newEnv, fn) { return fn(); }\nexport function withExports(newExports, fn) { return fn(); }\nexport function withEnvAndExports(newEnv, newExports, fn) { return fn(); }\n`,\n }\n }\n return nextLoad(url, context)\n}\n"],"mappings":";;;;;;;;;;;;AAYA,MAAM,cAAc;AACpB,MAAM,aAAa;AAcnB,eAAsB,QACpB,WACA,SACA,aACwB;CACxB,IAAI,cAAc,sBAChB,OAAO;EAAE,KAAK;EAAa,cAAc;EAAM;CAEjD,IAAI,UAAU,SAAS,WAAW,EAGhC,OAAO;EAAE,MAAK,MADS,YADV,UAAU,MAAM,GAAG,GACO,EAAE,QAAQ,EAC1B,MAAM;EAAY,cAAc;EAAM;CAE/D,OAAO,YAAY,WAAW,QAAQ;;AAgBxC,eAAsB,KACpB,KACA,SACA,UACqB;CACrB,IAAI,IAAI,SAAS,WAAW,EAAE;EAG5B,MAAM,UAAU,aADC,cADD,IAAI,MAAM,GAAG,GACS,CACD,EAAE,QAAQ;EAC/C,OAAO;GACL,QAAQ;GACR,cAAc;GACd,QAAQ,kBAAkB,KAAK,UAAU,QAAQ;GAClD;;CAEH,IAAI,QAAQ,aACV,OAAO;EACL,QAAQ;EACR,cAAc;EACd,QAAQ;;;;;;;;;;;;;;;;;;;;;;EAsBT;CAEH,OAAO,SAAS,KAAK,QAAQ"}
|
package/dist/bin/quarry.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quarry.mjs","names":["errorMessages"],"sources":["../../src/i18n/messages/en/errors.ts","../../src/bin/commands/dynamic-command.ts","../../src/bin/quarry.ts"],"sourcesContent":["/**\n * System Error Messages - English\n *\n * Error messages used by packages/modules infrastructure.\n * These are automatically merged with application-specific messages.\n */\n\nexport const errors = {\n // Generic errors\n internalError: 'An internal error occurred',\n notFound: 'Resource not found',\n unauthorized: 'Unauthorized. Please sign in.',\n forbidden: 'Access denied',\n\n // Router errors\n honoAppAlreadyConfigured: 'HonoApp has already been configured and can only be configured once',\n routeNotFound: 'Route not found: {method} {path}',\n routeAccessDenied: 'Resource not found',\n controllerMethodNotFound: 'Method {methodName} not found on {controllerName}',\n controllerRegistration: 'Failed to register controller {controllerName}: {reason}',\n duplicateRouteName: 'Duplicate route name \"{name}\". Already registered by {existingHandler}, cannot register {newHandler}.',\n routeNameNotFound: 'Route \"{name}\" not found in registry.',\n missingRouteParam: 'Missing required parameter \"{param}\" for route \"{name}\" (path: {path}).',\n routerUseScopeViolation: 'router.use() can only be called on the root Router, not inside group() callbacks. Use router.middleware() for scoped middleware.',\n middlewareNextCalledMultipleTimes: 'next() was called multiple times in \"{middlewareName}\" middleware. Ensure each middleware calls next() at most once.',\n missingEnvironmentVariable: 'Environment variable \"{variable}\" is required but not set.',\n\n // WebSocket errors\n websocketBodyNotAvailable: 'body() is not available in WebSocket gateways. Use WebSocket messages instead.',\n websocketDuplicateEventHandler: '@{decorator}() is already applied to \\'{existingMethod}\\'. Only one method per gateway can handle this event.',\n\n // Context errors\n contextNotInitialized: 'Context has not been initialized',\n userNotAuthenticated: 'User is not authenticated',\n insufficientPermissions: 'Insufficient permissions to perform this action',\n requestContainerNotInitialized: 'Request container has not been initialized',\n requestScopeOperationNotAllowed: '{methodName}() cannot be called on this container scope. Check if you are calling it on the correct container (global vs request-scoped).',\n conditionalBindingFallback: 'Conditional binding predicate returned false for token \"{token}\" but no fallback was provided and no existing registration exists.',\n\n // Configuration errors\n configNotInitialized: 'Configuration service has not been initialized',\n configModuleNotInitialized: 'ConfigModule.forRoot() was not called before module initialization',\n stratalNotInitialized: 'Stratal has not been instantiated. Ensure you export a Stratal instance as the default export.',\n\n // Module errors\n moduleAlreadyRegistered: 'Module {moduleName} is already registered',\n moduleDependencyNotFound: 'Module dependency {dependency} not found for module {moduleName}',\n moduleCircularDependency: 'Circular dependency detected: {cycle}',\n invalidModuleProvider: 'Invalid module provider configuration: {provider}',\n\n // Database errors\n databaseGeneric: 'Database error occurred',\n databaseRecordNotFound: 'Record not found in database',\n databaseUniqueConstraint: 'Record already exists',\n databaseForeignKeyConstraint: 'Related record not found',\n databaseConnectionFailed: 'Failed to connect to database',\n databaseTimeout: 'Database query timeout',\n databaseNullConstraint: 'Required field is missing',\n databaseTooManyConnections: 'Too many database connections',\n databaseTransactionConflict: 'Transaction conflict or deadlock',\n databaseConstraintFailed: 'A database constraint was violated',\n databaseTableNotFound: 'The specified table does not exist in the database',\n databaseColumnNotFound: 'The specified column does not exist in the table',\n databaseInvalidQuery: 'The database query is invalid or malformed',\n invalidErrorCodeRange: 'Invalid error code range: {code}',\n\n // Queue errors\n queueBindingNotFound: 'Queue binding {queueName} not found in environment',\n queueProviderNotSupported: 'Queue provider \"{provider}\" is not supported. Valid providers: cloudflare, sync',\n\n // Cron errors\n cronExecutionFailed: '{count} cron job(s) failed for schedule \"{schedule}\": {jobs}',\n\n // i18n errors\n localeNotSupported: \"Locale '{locale}' is not supported. Supported locales: {supportedLocales}\",\n translationMissing: \"Translation missing for key '{key}' in locale '{locale}'\",\n\n // Container errors\n containerNotInitialized: 'Application container has not been initialized. Ensure Application.initialize() has been called.',\n\n // Domain routing errors\n domainMismatch: 'The requested domain does not match any configured route',\n\n // Signature errors\n invalidSignature: 'The URL signature is invalid or has expired',\n\n // Schema validation errors\n schemaValidation: 'Schema validation failed',\n responseValidation: 'Response validation failed',\n\n // OpenAPI errors\n openapiValidation: 'OpenAPI validation failed: {details}',\n openapiRouteRegistration: 'Failed to register OpenAPI route {path}: {reason}',\n\n // Email errors\n email: {\n resendApiKeyMissing: 'Resend API key not configured. Set RESEND_EMAIL_API_KEY environment variable.',\n smtpConfigurationMissing: 'SMTP configuration missing. Set SMTP_URL environment variable.',\n smtpHostMissing: 'SMTP host not configured. Check SMTP_URL format (smtp://user:pass@host:port).',\n smtpConnectionFailed: 'Failed to connect to SMTP server {smtpHost}:{smtpPort}',\n resendApiFailed: 'Resend API error',\n providerNotSupported: 'Unsupported email provider: {provider}. Supported providers: resend, smtp'\n },\n\n // Storage errors\n storage: {\n fileNotFound: 'File at path \"{path}\" was not found',\n invalidDisk: 'Storage disk \"{disk}\" is not configured',\n invalidFileType: 'File type \"{mimeType}\" is not allowed',\n fileTooLarge: 'File size {size} exceeds maximum allowed size of {maxSize}',\n presignedUrlInvalidExpiry: 'Expiry must be between {min} and {max} seconds',\n diskNotConfigured: 'Disk \"{disk}\" is not configured',\n responseBodyMissing: 'No body in storage response for path: {path}',\n r2BindingNotFound: 'R2 binding \"{binding}\" was not found in the environment',\n r2PresignedUrlSecretMissing: 'APP_SECRET environment variable is required for presigned URLs',\n },\n\n // Cache errors\n cache: {\n getFailed: \"Failed to retrieve value from cache for key '{key}'\",\n putFailed: \"Failed to store value in cache for key '{key}'\",\n deleteFailed: \"Failed to delete value from cache for key '{key}'\",\n listFailed: 'Failed to list cache keys'\n },\n\n // Rate limiter errors\n rateLimit: {\n tooManyRequests: 'Too Many Requests',\n notDefined: 'Rate limiter \"{name}\" is not defined. Register it via RateLimiterRegistry.for(\"{name}\", ...) inside a module\\'s onInitialize hook.',\n notConfigured: 'RateLimiterModule.forRoot() was not called. Pass { store: \"kv\" | \"memory\" | { useClass } } to enable rate limiting.',\n moduleNotImported: 'Rate limiter \"{name}\" was used (router.throttle / @RateLimit) but RateLimiterModule is not imported in your AppModule. Add RateLimiterModule.forRoot({ store: ... }) to imports.',\n },\n\n // Seeder errors\n seederNameCollision: 'Seeder name collision: \"{name}\" is already registered. Use distinct class names for each seeder.',\n seederNotRegistered: 'Seeder \"{name}\" is not registered',\n\n // Migration errors\n migration: {\n failed: 'Migration {migrationName} failed: {error}',\n checksumMismatch: 'Migration {migrationName} checksum mismatch (expected: {expected}, actual: {actual})',\n alreadyApplied: 'Migration {migrationName} has already been applied',\n notFound: 'Migration {migrationName} not found',\n },\n} as const\n","import { Command, type CommandClass, Option, type Usage } from 'clipanion'\n\nimport type { Application } from 'stratal'\nimport type { ParsedSignature, QuarryRegistry } from 'stratal/quarry'\n\n/** Create Clipanion command classes from Quarry-registered commands. */\nexport function createDynamicCommands(\n quarry: QuarryRegistry,\n parseSignature: (command: string) => ParsedSignature,\n app: Application,\n) {\n const commands: CommandClass[] = []\n\n for (const entry of quarry.list()) {\n const commandClass = quarry.get(entry.name)! as unknown as { command: string; description?: string; aliases?: string[] }\n const signature = parseSignature(commandClass.command)\n\n const paths: string[][] = [entry.name.split(' ')]\n if (commandClass.aliases) {\n for (const alias of commandClass.aliases) {\n paths.push(alias.split(' '))\n }\n }\n\n // Allow bare `npx quarry` (no arguments) to invoke the help command\n if (entry.name === 'help') {\n paths.push([])\n }\n\n class DynCmd extends Command {\n static override paths = paths\n static override usage: Usage | undefined = commandClass.description\n ? Command.Usage({ description: commandClass.description })\n : undefined\n\n async execute(): Promise<number> {\n const input: Record<string, unknown> = {}\n\n for (const arg of signature.arguments) {\n const value = (this as Record<string, unknown>)[arg.name]\n if (value !== undefined) input[arg.name] = value\n }\n\n for (const opt of signature.options) {\n const value = (this as Record<string, unknown>)[opt.name]\n if (value !== undefined) input[opt.name] = value\n }\n\n const result = await app.handleCommand(entry.name, input)\n\n for (const line of result.output) {\n this.context.stdout.write(line + '\\n')\n }\n\n for (const err of result.errors) {\n this.context.stderr.write(err + '\\n')\n }\n\n return result.exitCode\n }\n }\n\n // Define Clipanion options/arguments as class property defaults\n const proto = DynCmd.prototype as unknown as Record<string, unknown>\n for (const arg of signature.arguments) {\n if (arg.isArray) {\n proto[arg.name] = Option.Rest({ name: arg.name, required: arg.required ? 1 : 0 })\n } else {\n proto[arg.name] = Option.String({ name: arg.name, required: arg.required })\n }\n }\n\n for (const opt of signature.options) {\n const optName = opt.alias ? `-${opt.alias},--${opt.name}` : `--${opt.name}`\n const optDescParts: string[] = []\n if (opt.description) optDescParts.push(opt.description)\n if (opt.default !== undefined) optDescParts.push(`(default: ${opt.default})`)\n const optDesc = optDescParts.length > 0 ? optDescParts.join(' ') : undefined\n\n if (opt.isFlag) {\n proto[opt.name] = Option.Boolean(optName, { description: optDesc })\n } else if (opt.isArray) {\n if (opt.default !== undefined) {\n proto[opt.name] = Option.Array(optName, [opt.default], { description: optDesc })\n } else {\n proto[opt.name] = Option.Array(optName, { description: optDesc })\n }\n } else {\n if (opt.default !== undefined) {\n proto[opt.name] = Option.String(optName, opt.default, { description: optDesc })\n } else {\n proto[opt.name] = Option.String(optName, { description: optDesc })\n }\n }\n }\n\n commands.push(DynCmd)\n }\n\n return commands\n}\n","import 'reflect-metadata'\n\nimport { existsSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from 'node:fs'\nimport { createRequire, register } from 'node:module'\nimport { tmpdir } from 'node:os'\nimport { dirname, join, resolve } from 'node:path'\nimport { URL, pathToFileURL } from 'node:url'\nimport type { QuarryRegistry } from 'stratal/quarry'\nimport { type Application } from '../application'\nimport { errors as errorMessages } from '../i18n/messages/en/errors'\nimport { createDynamicCommands } from './commands/dynamic-command'\n\nconst require = createRequire(import.meta.url)\n\n// Register @swc-node/register for TypeScript + decorator support\nconst swcRegisterPath = join(dirname(require.resolve('@swc-node/register')), 'esm/esm.mjs')\nregister(pathToFileURL(swcRegisterPath), pathToFileURL('./'))\n\n// Register cloudflare:workers virtual module loader\nregister(new URL('./cloudflare-workers-loader.mjs', import.meta.url), pathToFileURL('./'))\n\nconst DEFAULT_ENTRY = './src/index.ts'\n\n// Determine entry file: if first arg looks like a file path, use it; otherwise use default\nconst firstArg = process.argv[2]\nlet entryFile = DEFAULT_ENTRY\n\nif (firstArg && (firstArg.includes('/') || firstArg.includes('\\\\') || /\\.(ts|js|mts|mjs)$/.test(firstArg))) {\n entryFile = firstArg\n // Remove the entry file from argv so Clipanion sees: [node, script, command, ...options]\n process.argv.splice(2, 1)\n}\n\n// Resolve and validate the entry file\nconst entryPath = resolve(process.cwd(), entryFile)\n\nif (!existsSync(entryPath)) {\n console.error(`Error: Entry file not found: ${entryFile}`)\n console.error('')\n console.error('Create src/index.ts with a default Stratal export, or specify a custom path:')\n console.error(' npx quarry ./path/to/entry.ts <command> [options]')\n process.exit(1)\n}\n\nfunction stripDurableObjects(config: Record<string, unknown>): void {\n delete config.durable_objects\n delete config.migrations\n if (config.env && typeof config.env === 'object') {\n for (const envConfig of Object.values(config.env as Record<string, Record<string, unknown>>)) {\n delete envConfig.durable_objects\n delete envConfig.migrations\n }\n }\n}\n\nasync function createStrippedConfig(cwdRequire: NodeRequire): Promise<string | undefined> {\n const candidates = ['wrangler.jsonc', 'wrangler.json', 'wrangler.toml']\n const configName = candidates.find(c => existsSync(resolve(process.cwd(), c)))\n if (!configName) return undefined\n\n const configPath = resolve(process.cwd(), configName)\n const raw = readFileSync(configPath, 'utf-8')\n\n let config: Record<string, unknown>\n if (configName.endsWith('.toml')) {\n const { parse } = await import(cwdRequire.resolve('smol-toml')) as { parse: (input: string) => Record<string, unknown> }\n config = parse(raw)\n } else {\n const { parse: parseJsonc } = await import(cwdRequire.resolve('jsonc-parser')) as { parse: (input: string) => Record<string, unknown> }\n config = parseJsonc(raw)\n }\n\n // Rename so quarry's ephemeral miniflare doesn't claim the running\n // `wrangler dev` session's dev-registry slot. getPlatformProxy registers\n // its worker with empty entrypointAddresses (no direct sockets), and that\n // overwrite makes peer workers route TenantsRpc/BrandingRpc/etc. calls to\n // their fallback service (\"couldn't find a local dev session for the X\n // entrypoint\"). A unique name keeps the running session's entry untouched.\n if (typeof config.name === 'string') {\n config.name = `quarry-${config.name}-${process.pid}`\n }\n if (config.env && typeof config.env === 'object') {\n for (const envConfig of Object.values(config.env as Record<string, Record<string, unknown>>)) {\n if (typeof envConfig.name === 'string') {\n envConfig.name = `quarry-${envConfig.name}-${process.pid}`\n }\n }\n }\n\n stripDurableObjects(config)\n\n const tmpPath = resolve(tmpdir(), `quarry-wrangler-${Date.now()}.json`)\n writeFileSync(tmpPath, JSON.stringify(config, null, 2))\n return tmpPath\n}\n\nfunction discoverEnvFiles(): string[] {\n const cwd = process.cwd()\n const files = readdirSync(cwd)\n return files\n .filter(file => (/^\\.dev\\.vars($|\\.)/.test(file) || /^\\.env($|\\.)/.test(file)) && !file.endsWith('.example') && !file.endsWith('.sample'))\n .sort((a, b) => {\n // Load .env files before .dev.vars so .dev.vars takes precedence\n const aIsDevVars = a.startsWith('.dev.vars')\n const bIsDevVars = b.startsWith('.dev.vars')\n if (aIsDevVars !== bIsDevVars) return aIsDevVars ? 1 : -1\n // Within each group, .local files load last (highest precedence)\n const aIsLocal = a.endsWith('.local')\n const bIsLocal = b.endsWith('.local')\n if (aIsLocal !== bIsLocal) return aIsLocal ? 1 : -1\n return a.localeCompare(b)\n })\n .map(file => join(cwd, file))\n}\n\nasync function main(): Promise<void> {\n const cwdRequire = createRequire(join(process.cwd(), 'package.json'))\n // eslint-disable-next-line @typescript-eslint/consistent-type-imports\n const { getPlatformProxy } = await import(cwdRequire.resolve('wrangler')) as typeof import('wrangler')\n\n const strippedConfigPath = await createStrippedConfig(cwdRequire)\n\n const envFiles = discoverEnvFiles()\n const { env, ctx, dispose } = await getPlatformProxy({\n envFiles, configPath: strippedConfigPath,\n })\n\n // Track waitUntil promises so we can drain them before shutdown.\n // In Workers runtime, waitUntil keeps the isolate alive. In Quarry (miniflare),\n // dispose() tears down without awaiting pending promises — so we track and drain them.\n const pendingPromises: Promise<unknown>[] = []\n const trackedWaitUntil = (promise: Promise<unknown>) => {\n pendingPromises.push(promise)\n ctx.waitUntil(promise)\n }\n\n let app: Application | undefined\n try {\n env.QUEUE_PROVIDER = 'sync';\n\n // Store platform proxy on globalThis so the cloudflare:workers virtual module can read it\n (globalThis as Record<string, unknown>).__stratalPlatformProxy = {\n env,\n waitUntil: trackedWaitUntil,\n }\n\n // Import user's entry file — triggers `new Stratal(...)` + full Application init\n await import(pathToFileURL(entryPath).href)\n\n // Parallel import of stratal modules\n const [\n { Stratal },\n { DI_TOKENS },\n { parseSignature },\n ] = await Promise.all([\n import('stratal'),\n import('stratal/di'),\n import('stratal/quarry'),\n ])\n\n app = await Stratal.resolveApplication()\n const quarry = app.container.resolve<QuarryRegistry>(DI_TOKENS.Quarry)\n\n // Build Clipanion CLI\n const { Cli } = await import('clipanion')\n const pkg = require('../../package.json') as { version: string }\n\n const cli = new Cli({\n binaryName: 'quarry',\n binaryLabel: 'Quarry CLI',\n binaryVersion: pkg.version,\n })\n\n for (const cmd of createDynamicCommands(quarry, parseSignature, app)) {\n cli.register(cmd)\n }\n\n await cli.runExit(process.argv.slice(2), { ...Cli.defaultContext })\n } finally {\n await Promise.allSettled(pendingPromises);\n\n await app?.shutdown()\n await dispose()\n\n if (strippedConfigPath) {\n try { unlinkSync(strippedConfigPath) } catch {\n //\n }\n }\n }\n}\n\nmain().catch(async (error: unknown) => {\n const { ConfigValidationError } = await import('stratal/config')\n const { StratalNotInitializedError } = await import('stratal/errors')\n\n const message = error instanceof StratalNotInitializedError\n ? errorMessages.stratalNotInitialized\n : error instanceof Error ? error.message : String(error)\n console.error('Fatal error:', message)\n if (error instanceof ConfigValidationError) {\n console.error(error.errors.message)\n }\n process.exit(1)\n})\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"quarry.mjs","names":["errorMessages"],"sources":["../../src/i18n/messages/en/errors.ts","../../src/bin/commands/dynamic-command.ts","../../src/bin/quarry.ts"],"sourcesContent":["/**\n * System Error Messages - English\n *\n * Error messages used by packages/modules infrastructure.\n * These are automatically merged with application-specific messages.\n */\n\nexport const errors = {\n // Generic errors\n internalError: 'An internal error occurred',\n notFound: 'Resource not found',\n unauthorized: 'Unauthorized. Please sign in.',\n forbidden: 'Access denied',\n\n // Router errors\n honoAppAlreadyConfigured: 'HonoApp has already been configured and can only be configured once',\n routeNotFound: 'Route not found: {method} {path}',\n routeAccessDenied: 'Resource not found',\n controllerMethodNotFound: 'Method {methodName} not found on {controllerName}',\n controllerRegistration: 'Failed to register controller {controllerName}: {reason}',\n duplicateRouteName: 'Duplicate route name \"{name}\". Already registered by {existingHandler}, cannot register {newHandler}.',\n routeNameNotFound: 'Route \"{name}\" not found in registry.',\n missingRouteParam: 'Missing required parameter \"{param}\" for route \"{name}\" (path: {path}).',\n routerUseScopeViolation: 'router.use() can only be called on the root Router, not inside group() callbacks. Use router.middleware() for scoped middleware.',\n middlewareNextCalledMultipleTimes: 'next() was called multiple times in \"{middlewareName}\" middleware. Ensure each middleware calls next() at most once.',\n missingEnvironmentVariable: 'Environment variable \"{variable}\" is required but not set.',\n\n // WebSocket errors\n websocketBodyNotAvailable: 'body() is not available in WebSocket gateways. Use WebSocket messages instead.',\n websocketDuplicateEventHandler: '@{decorator}() is already applied to \\'{existingMethod}\\'. Only one method per gateway can handle this event.',\n\n // Context errors\n contextNotInitialized: 'Context has not been initialized',\n userNotAuthenticated: 'User is not authenticated',\n insufficientPermissions: 'Insufficient permissions to perform this action',\n requestContainerNotInitialized: 'Request container has not been initialized',\n requestScopeOperationNotAllowed: '{methodName}() cannot be called on this container scope. Check if you are calling it on the correct container (global vs request-scoped).',\n conditionalBindingFallback: 'Conditional binding predicate returned false for token \"{token}\" but no fallback was provided and no existing registration exists.',\n\n // Configuration errors\n configNotInitialized: 'Configuration service has not been initialized',\n configModuleNotInitialized: 'ConfigModule.forRoot() was not called before module initialization',\n stratalNotInitialized: 'Stratal has not been instantiated. Ensure you export a Stratal instance as the default export.',\n\n // Module errors\n moduleAlreadyRegistered: 'Module {moduleName} is already registered',\n moduleDependencyNotFound: 'Module dependency {dependency} not found for module {moduleName}',\n moduleCircularDependency: 'Circular dependency detected: {cycle}',\n invalidModuleProvider: 'Invalid module provider configuration: {provider}',\n\n // Database errors\n databaseGeneric: 'Database error occurred',\n databaseRecordNotFound: 'Record not found in database',\n databaseUniqueConstraint: 'Record already exists',\n databaseForeignKeyConstraint: 'Related record not found',\n databaseConnectionFailed: 'Failed to connect to database',\n databaseTimeout: 'Database query timeout',\n databaseNullConstraint: 'Required field is missing',\n databaseTooManyConnections: 'Too many database connections',\n databaseTransactionConflict: 'Transaction conflict or deadlock',\n databaseConstraintFailed: 'A database constraint was violated',\n databaseTableNotFound: 'The specified table does not exist in the database',\n databaseColumnNotFound: 'The specified column does not exist in the table',\n databaseInvalidQuery: 'The database query is invalid or malformed',\n invalidErrorCodeRange: 'Invalid error code range: {code}',\n\n // Queue errors\n queueBindingNotFound: 'Queue binding {queueName} not found in environment',\n queueProviderNotSupported: 'Queue provider \"{provider}\" is not supported. Valid providers: cloudflare, sync',\n\n // Cron errors\n cronExecutionFailed: '{count} cron job(s) failed for schedule \"{schedule}\": {jobs}',\n\n // i18n errors\n localeNotSupported: \"Locale '{locale}' is not supported. Supported locales: {supportedLocales}\",\n translationMissing: \"Translation missing for key '{key}' in locale '{locale}'\",\n\n // Container errors\n containerNotInitialized: 'Application container has not been initialized. Ensure Application.initialize() has been called.',\n\n // Domain routing errors\n domainMismatch: 'The requested domain does not match any configured route',\n\n // Signature errors\n invalidSignature: 'The URL signature is invalid or has expired',\n\n // Schema validation errors\n schemaValidation: 'Schema validation failed',\n responseValidation: 'Response validation failed',\n\n // OpenAPI errors\n openapiValidation: 'OpenAPI validation failed: {details}',\n openapiRouteRegistration: 'Failed to register OpenAPI route {path}: {reason}',\n\n // Email errors\n email: {\n resendApiKeyMissing: 'Resend API key not configured. Set RESEND_EMAIL_API_KEY environment variable.',\n smtpConfigurationMissing: 'SMTP configuration missing. Set SMTP_URL environment variable.',\n smtpHostMissing: 'SMTP host not configured. Check SMTP_URL format (smtp://user:pass@host:port).',\n smtpConnectionFailed: 'Failed to connect to SMTP server {smtpHost}:{smtpPort}',\n resendApiFailed: 'Resend API error',\n providerNotSupported: 'Unsupported email provider: {provider}. Supported providers: resend, smtp'\n },\n\n // Storage errors\n storage: {\n fileNotFound: 'File at path \"{path}\" was not found',\n invalidDisk: 'Storage disk \"{disk}\" is not configured',\n invalidFileType: 'File type \"{mimeType}\" is not allowed',\n fileTooLarge: 'File size {size} exceeds maximum allowed size of {maxSize}',\n presignedUrlInvalidExpiry: 'Expiry must be between {min} and {max} seconds',\n diskNotConfigured: 'Disk \"{disk}\" is not configured',\n responseBodyMissing: 'No body in storage response for path: {path}',\n r2BindingNotFound: 'R2 binding \"{binding}\" was not found in the environment',\n r2PresignedUrlSecretMissing: 'APP_SECRET environment variable is required for presigned URLs',\n },\n\n // Cache errors\n cache: {\n getFailed: \"Failed to retrieve value from cache for key '{key}'\",\n putFailed: \"Failed to store value in cache for key '{key}'\",\n deleteFailed: \"Failed to delete value from cache for key '{key}'\",\n listFailed: 'Failed to list cache keys'\n },\n\n // Rate limiter errors\n rateLimit: {\n tooManyRequests: 'Too Many Requests',\n notDefined: 'Rate limiter \"{name}\" is not defined. Register it via RateLimiterRegistry.for(\"{name}\", ...) inside a module\\'s onInitialize hook.',\n notConfigured: 'RateLimiterModule.forRoot() was not called. Pass { store: \"kv\" | \"memory\" | { useClass } } to enable rate limiting.',\n moduleNotImported: 'Rate limiter \"{name}\" was used (router.throttle / @RateLimit) but RateLimiterModule is not imported in your AppModule. Add RateLimiterModule.forRoot({ store: ... }) to imports.',\n },\n\n // Seeder errors\n seederNameCollision: 'Seeder name collision: \"{name}\" is already registered. Use distinct class names for each seeder.',\n seederNotRegistered: 'Seeder \"{name}\" is not registered',\n\n // Migration errors\n migration: {\n failed: 'Migration {migrationName} failed: {error}',\n checksumMismatch: 'Migration {migrationName} checksum mismatch (expected: {expected}, actual: {actual})',\n alreadyApplied: 'Migration {migrationName} has already been applied',\n notFound: 'Migration {migrationName} not found',\n },\n} as const\n","import { Command, type CommandClass, Option, type Usage } from 'clipanion'\n\nimport type { Application } from 'stratal'\nimport type { ParsedSignature, QuarryRegistry } from 'stratal/quarry'\n\n/** Create Clipanion command classes from Quarry-registered commands. */\nexport function createDynamicCommands(\n quarry: QuarryRegistry,\n parseSignature: (command: string) => ParsedSignature,\n app: Application,\n) {\n const commands: CommandClass[] = []\n\n for (const entry of quarry.list()) {\n const commandClass = quarry.get(entry.name)! as unknown as { command: string; description?: string; aliases?: string[] }\n const signature = parseSignature(commandClass.command)\n\n const paths: string[][] = [entry.name.split(' ')]\n if (commandClass.aliases) {\n for (const alias of commandClass.aliases) {\n paths.push(alias.split(' '))\n }\n }\n\n // Allow bare `npx quarry` (no arguments) to invoke the help command\n if (entry.name === 'help') {\n paths.push([])\n }\n\n class DynCmd extends Command {\n static override paths = paths\n static override usage: Usage | undefined = commandClass.description\n ? Command.Usage({ description: commandClass.description })\n : undefined\n\n async execute(): Promise<number> {\n const input: Record<string, unknown> = {}\n\n for (const arg of signature.arguments) {\n const value = (this as Record<string, unknown>)[arg.name]\n if (value !== undefined) input[arg.name] = value\n }\n\n for (const opt of signature.options) {\n const value = (this as Record<string, unknown>)[opt.name]\n if (value !== undefined) input[opt.name] = value\n }\n\n const result = await app.handleCommand(entry.name, input)\n\n for (const line of result.output) {\n this.context.stdout.write(line + '\\n')\n }\n\n for (const err of result.errors) {\n this.context.stderr.write(err + '\\n')\n }\n\n return result.exitCode\n }\n }\n\n // Define Clipanion options/arguments as class property defaults\n const proto = DynCmd.prototype as unknown as Record<string, unknown>\n for (const arg of signature.arguments) {\n if (arg.isArray) {\n proto[arg.name] = Option.Rest({ name: arg.name, required: arg.required ? 1 : 0 })\n } else {\n proto[arg.name] = Option.String({ name: arg.name, required: arg.required })\n }\n }\n\n for (const opt of signature.options) {\n const optName = opt.alias ? `-${opt.alias},--${opt.name}` : `--${opt.name}`\n const optDescParts: string[] = []\n if (opt.description) optDescParts.push(opt.description)\n if (opt.default !== undefined) optDescParts.push(`(default: ${opt.default})`)\n const optDesc = optDescParts.length > 0 ? optDescParts.join(' ') : undefined\n\n if (opt.isFlag) {\n proto[opt.name] = Option.Boolean(optName, { description: optDesc })\n } else if (opt.isArray) {\n if (opt.default !== undefined) {\n proto[opt.name] = Option.Array(optName, [opt.default], { description: optDesc })\n } else {\n proto[opt.name] = Option.Array(optName, { description: optDesc })\n }\n } else {\n if (opt.default !== undefined) {\n proto[opt.name] = Option.String(optName, opt.default, { description: optDesc })\n } else {\n proto[opt.name] = Option.String(optName, { description: optDesc })\n }\n }\n }\n\n commands.push(DynCmd)\n }\n\n return commands\n}\n","import 'reflect-metadata'\n\nimport { existsSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from 'node:fs'\nimport { createRequire, register } from 'node:module'\nimport { tmpdir } from 'node:os'\nimport { dirname, join, resolve } from 'node:path'\nimport { URL, pathToFileURL } from 'node:url'\nimport type { QuarryRegistry } from 'stratal/quarry'\nimport { type Application } from '../application'\nimport { errors as errorMessages } from '../i18n/messages/en/errors'\nimport { createDynamicCommands } from './commands/dynamic-command'\n\nconst require = createRequire(import.meta.url)\n\n// Register @swc-node/register for TypeScript + decorator support\nconst swcRegisterPath = join(dirname(require.resolve('@swc-node/register')), 'esm/esm.mjs')\nregister(pathToFileURL(swcRegisterPath), pathToFileURL('./'))\n\n// Register cloudflare:workers virtual module loader\nregister(new URL('./cloudflare-workers-loader.mjs', import.meta.url), pathToFileURL('./'))\n\nconst DEFAULT_ENTRY = './src/index.ts'\n\n// Determine entry file: if first arg looks like a file path, use it; otherwise use default\nconst firstArg = process.argv[2]\nlet entryFile = DEFAULT_ENTRY\n\nif (firstArg && (firstArg.includes('/') || firstArg.includes('\\\\') || /\\.(ts|js|mts|mjs)$/.test(firstArg))) {\n entryFile = firstArg\n // Remove the entry file from argv so Clipanion sees: [node, script, command, ...options]\n process.argv.splice(2, 1)\n}\n\n// Resolve and validate the entry file\nconst entryPath = resolve(process.cwd(), entryFile)\n\nif (!existsSync(entryPath)) {\n console.error(`Error: Entry file not found: ${entryFile}`)\n console.error('')\n console.error('Create src/index.ts with a default Stratal export, or specify a custom path:')\n console.error(' npx quarry ./path/to/entry.ts <command> [options]')\n process.exit(1)\n}\n\nfunction stripDurableObjects(config: Record<string, unknown>): void {\n delete config.durable_objects\n delete config.migrations\n if (config.env && typeof config.env === 'object') {\n for (const envConfig of Object.values(config.env as Record<string, Record<string, unknown>>)) {\n delete envConfig.durable_objects\n delete envConfig.migrations\n }\n }\n}\n\nasync function createStrippedConfig(cwdRequire: NodeRequire): Promise<string | undefined> {\n const candidates = ['wrangler.jsonc', 'wrangler.json', 'wrangler.toml']\n const configName = candidates.find(c => existsSync(resolve(process.cwd(), c)))\n if (!configName) return undefined\n\n const configPath = resolve(process.cwd(), configName)\n const raw = readFileSync(configPath, 'utf-8')\n\n let config: Record<string, unknown>\n if (configName.endsWith('.toml')) {\n const { parse } = await import(cwdRequire.resolve('smol-toml')) as { parse: (input: string) => Record<string, unknown> }\n config = parse(raw)\n } else {\n const { parse: parseJsonc } = await import(cwdRequire.resolve('jsonc-parser')) as { parse: (input: string) => Record<string, unknown> }\n config = parseJsonc(raw)\n }\n\n // Rename so quarry's ephemeral miniflare doesn't claim the running\n // `wrangler dev` session's dev-registry slot. getPlatformProxy registers\n // its worker with empty entrypointAddresses (no direct sockets), and that\n // overwrite makes peer workers route TenantsRpc/BrandingRpc/etc. calls to\n // their fallback service (\"couldn't find a local dev session for the X\n // entrypoint\"). A unique name keeps the running session's entry untouched.\n if (typeof config.name === 'string') {\n config.name = `quarry-${config.name}-${process.pid}`\n }\n if (config.env && typeof config.env === 'object') {\n for (const envConfig of Object.values(config.env as Record<string, Record<string, unknown>>)) {\n if (typeof envConfig.name === 'string') {\n envConfig.name = `quarry-${envConfig.name}-${process.pid}`\n }\n }\n }\n\n stripDurableObjects(config)\n\n const tmpPath = resolve(tmpdir(), `quarry-wrangler-${Date.now()}.json`)\n writeFileSync(tmpPath, JSON.stringify(config, null, 2))\n return tmpPath\n}\n\nfunction discoverEnvFiles(): string[] {\n const cwd = process.cwd()\n const files = readdirSync(cwd)\n return files\n .filter(file => (/^\\.dev\\.vars($|\\.)/.test(file) || /^\\.env($|\\.)/.test(file)) && !file.endsWith('.example') && !file.endsWith('.sample'))\n .sort((a, b) => {\n // Load .env files before .dev.vars so .dev.vars takes precedence\n const aIsDevVars = a.startsWith('.dev.vars')\n const bIsDevVars = b.startsWith('.dev.vars')\n if (aIsDevVars !== bIsDevVars) return aIsDevVars ? 1 : -1\n // Within each group, .local files load last (highest precedence)\n const aIsLocal = a.endsWith('.local')\n const bIsLocal = b.endsWith('.local')\n if (aIsLocal !== bIsLocal) return aIsLocal ? 1 : -1\n return a.localeCompare(b)\n })\n .map(file => join(cwd, file))\n}\n\nasync function main(): Promise<void> {\n const cwdRequire = createRequire(join(process.cwd(), 'package.json'))\n // eslint-disable-next-line @typescript-eslint/consistent-type-imports\n const { getPlatformProxy } = await import(cwdRequire.resolve('wrangler')) as typeof import('wrangler')\n\n const strippedConfigPath = await createStrippedConfig(cwdRequire)\n\n const envFiles = discoverEnvFiles()\n const { env, ctx, dispose } = await getPlatformProxy({\n envFiles, configPath: strippedConfigPath,\n })\n\n // Track waitUntil promises so we can drain them before shutdown.\n // In Workers runtime, waitUntil keeps the isolate alive. In Quarry (miniflare),\n // dispose() tears down without awaiting pending promises — so we track and drain them.\n const pendingPromises: Promise<unknown>[] = []\n const trackedWaitUntil = (promise: Promise<unknown>) => {\n pendingPromises.push(promise)\n ctx.waitUntil(promise)\n }\n\n let app: Application | undefined\n try {\n env.QUEUE_PROVIDER = 'sync';\n\n // Store platform proxy on globalThis so the cloudflare:workers virtual module can read it\n (globalThis as Record<string, unknown>).__stratalPlatformProxy = {\n env,\n waitUntil: trackedWaitUntil,\n }\n\n // Import user's entry file — triggers `new Stratal(...)` + full Application init\n await import(pathToFileURL(entryPath).href)\n\n // Parallel import of stratal modules\n const [\n { Stratal },\n { DI_TOKENS },\n { parseSignature },\n ] = await Promise.all([\n import('stratal'),\n import('stratal/di'),\n import('stratal/quarry'),\n ])\n\n app = await Stratal.resolveApplication()\n const quarry = app.container.resolve<QuarryRegistry>(DI_TOKENS.Quarry)\n\n // Build Clipanion CLI\n const { Cli } = await import('clipanion')\n const pkg = require('../../package.json') as { version: string }\n\n const cli = new Cli({\n binaryName: 'quarry',\n binaryLabel: 'Quarry CLI',\n binaryVersion: pkg.version,\n })\n\n for (const cmd of createDynamicCommands(quarry, parseSignature, app)) {\n cli.register(cmd)\n }\n\n await cli.runExit(process.argv.slice(2), { ...Cli.defaultContext })\n } finally {\n await Promise.allSettled(pendingPromises);\n\n await app?.shutdown()\n await dispose()\n\n if (strippedConfigPath) {\n try { unlinkSync(strippedConfigPath) } catch {\n //\n }\n }\n }\n}\n\nmain().catch(async (error: unknown) => {\n const { ConfigValidationError } = await import('stratal/config')\n const { StratalNotInitializedError } = await import('stratal/errors')\n\n const message = error instanceof StratalNotInitializedError\n ? errorMessages.stratalNotInitialized\n : error instanceof Error ? error.message : String(error)\n console.error('Fatal error:', message)\n if (error instanceof ConfigValidationError) {\n console.error(error.errors.message)\n }\n process.exit(1)\n})\n"],"mappings":"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"}
|
package/dist/cache/index.d.mts
CHANGED
package/dist/cache/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { H as ApplicationError, k as ERROR_CODES } from "../errors-
|
|
2
|
-
import { a as __decorate, f as DI_TOKENS, o as __decorateParam, p as Transient, s as __decorateMetadata, u as LOGGER_TOKENS } from "../logger-
|
|
3
|
-
import { k as Module } from "../module-
|
|
1
|
+
import { H as ApplicationError, k as ERROR_CODES } from "../errors-COW9-Mar.mjs";
|
|
2
|
+
import { a as __decorate, f as DI_TOKENS, o as __decorateParam, p as Transient, s as __decorateMetadata, u as LOGGER_TOKENS } from "../logger-DlV7NtvD.mjs";
|
|
3
|
+
import { k as Module } from "../module-BzLg57FK.mjs";
|
|
4
4
|
import { t as CACHE_TOKENS } from "../cache.tokens-B7Rw1C9Q.mjs";
|
|
5
5
|
import { inject } from "tsyringe";
|
|
6
6
|
//#region src/cache/errors/cache-get.error.ts
|
|
@@ -57,6 +57,8 @@ var CacheListError = class extends ApplicationError {
|
|
|
57
57
|
//#region src/cache/services/cache.service.ts
|
|
58
58
|
var _CacheService;
|
|
59
59
|
let CacheService = _CacheService = class CacheService {
|
|
60
|
+
env;
|
|
61
|
+
logger;
|
|
60
62
|
kv;
|
|
61
63
|
constructor(env, logger) {
|
|
62
64
|
this.env = env;
|
package/dist/cache/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/cache/errors/cache-get.error.ts","../../src/cache/errors/cache-put.error.ts","../../src/cache/errors/cache-delete.error.ts","../../src/cache/errors/cache-list.error.ts","../../src/cache/services/cache.service.ts","../../src/cache/cache.module.ts"],"sourcesContent":["import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\n/**\n * Error thrown when a cache get operation fails\n *\n * Raw error details are logged via LoggerService for security.\n * Only the key is included in the user-facing error message.\n */\nexport class CacheGetError extends ApplicationError {\n constructor(key: string) {\n super('errors.cache.getFailed', ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR, { key })\n }\n}\n","import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\n/**\n * Error thrown when a cache put operation fails\n *\n * Raw error details are logged via LoggerService for security.\n * Only the key is included in the user-facing error message.\n */\nexport class CachePutError extends ApplicationError {\n constructor(key: string) {\n super('errors.cache.putFailed', ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR, { key })\n }\n}\n","import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\n/**\n * Error thrown when a cache delete operation fails\n *\n * Raw error details are logged via LoggerService for security.\n * Only the key is included in the user-facing error message.\n */\nexport class CacheDeleteError extends ApplicationError {\n constructor(key: string) {\n super('errors.cache.deleteFailed', ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR, { key })\n }\n}\n","import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\n/**\n * Error thrown when a cache list operation fails\n *\n * Raw error details are logged via LoggerService for security.\n */\nexport class CacheListError extends ApplicationError {\n constructor() {\n super('errors.cache.listFailed', ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR, {})\n }\n}\n","import { inject } from 'tsyringe'\nimport { Transient } from '../../di/decorators'\nimport { DI_TOKENS } from '../../di/tokens'\nimport { type StratalEnv } from '../../env'\nimport { LOGGER_TOKENS, type LoggerService } from '../../logger'\nimport { CACHE_TOKENS } from '../cache.tokens'\nimport {\n CacheDeleteError,\n CacheGetError,\n CacheListError,\n CachePutError,\n} from '../errors'\n\n/**\n * Cache Service\n *\n * Type-safe wrapper around Cloudflare KV namespaces for caching operations.\n *\n * **Features:**\n * - Mirrors all KVNamespace methods with full type safety\n * - Supports multiple KV bindings via `withBinding()`\n * - Automatic error handling with logging\n * - Security: Raw errors are logged, not exposed to users\n *\n * **Usage:**\n * ```typescript\n * class MyService {\n * private readonly uploadsCache: CacheService\n *\n * constructor(\n * @inject(CACHE_TOKENS.CacheService) private readonly cache: CacheService,\n * @inject(DI_TOKENS.CloudflareEnv) private readonly env: Env\n * ) {\n * // Initialize specialized caches in constructor\n * this.uploadsCache = this.cache.withBinding(this.env.UPLOADS_CACHE)\n * }\n *\n * async cacheData(key: string, value: string) {\n * await this.cache.put(key, value, { expirationTtl: 3600 })\n * await this.uploadsCache.put(`upload:${key}`, value)\n * }\n * }\n * ```\n *\n * @see https://developers.cloudflare.com/kv/api/\n */\n@Transient(CACHE_TOKENS.CacheService)\nexport class CacheService {\n private kv: KVNamespace\n\n constructor(\n @inject(DI_TOKENS.CloudflareEnv) private readonly env: StratalEnv,\n @inject(LOGGER_TOKENS.LoggerService) private readonly logger: LoggerService\n ) {\n this.kv = env.CACHE\n }\n\n /**\n * Set the KV namespace binding\n *\n * Used internally by `withBinding()` to configure different KV instances.\n *\n * @param kv - KV namespace to use\n */\n setKV(kv: KVNamespace): void {\n this.kv = kv\n }\n\n /**\n * Create a new CacheService instance with a different KV binding\n *\n * **Pattern:** Returns a new instance (immutable)\n *\n * **Best Practice:** Initialize specialized caches as class properties in constructor\n *\n * @example\n * ```typescript\n * class MyService {\n * private readonly uploadsCache: CacheService\n * private readonly systemCache: CacheService\n *\n * constructor(\n * @inject(CACHE_TOKENS.CacheService) private readonly cache: CacheService,\n * @inject(DI_TOKENS.CloudflareEnv) private readonly env: Env\n * ) {\n * this.uploadsCache = this.cache.withBinding(this.env.UPLOADS_CACHE)\n * this.systemCache = this.cache.withBinding(this.env.SYSTEM_CONFIG_KV)\n * }\n * }\n * ```\n *\n * @param kv - KV namespace to use\n * @returns New CacheService instance with the specified binding\n */\n withBinding(kv: KVNamespace): CacheService {\n const instance = new CacheService(this.env, this.logger)\n instance.setKV(kv)\n return instance\n }\n\n // ==================== GET METHODS ====================\n\n /**\n * Get a value from cache\n *\n * @param key - Cache key\n * @param typeOrOptions - Type string or options object (defaults to 'text')\n * @returns Value in specified type, or null if not found\n * @throws {CacheGetError} If operation fails\n */\n async get(key: string, typeOrOptions?: 'text' | KVNamespaceGetOptions<'text'>): Promise<string | null>\n async get<ExpectedValue = unknown>(key: string, typeOrOptions: 'json' | KVNamespaceGetOptions<'json'>): Promise<ExpectedValue | null>\n async get(key: string, typeOrOptions: 'arrayBuffer' | KVNamespaceGetOptions<'arrayBuffer'>): Promise<ArrayBuffer | null>\n async get(key: string, typeOrOptions: 'stream' | KVNamespaceGetOptions<'stream'>): Promise<ReadableStream | null>\n\n async get<ExpectedValue = unknown>(\n key: string,\n typeOrOptions?: string | KVNamespaceGetOptions<'text' | 'json' | 'arrayBuffer' | 'stream'>\n ): Promise<string | ExpectedValue | ArrayBuffer | ReadableStream | null> {\n try {\n if (typeof typeOrOptions === 'string') {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any -- bridging KV overloaded API\n return await this.kv.get(key, typeOrOptions as any)\n }\n\n if (typeOrOptions) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any -- bridging KV overloaded API\n return await this.kv.get(key, typeOrOptions as any)\n }\n\n return await this.kv.get(key)\n } catch (error) {\n this.logger.error('Cache get operation failed', { key, error })\n throw new CacheGetError(key)\n }\n }\n\n // ==================== GET WITH METADATA METHODS ====================\n\n /**\n * Get a value with metadata from cache\n *\n * @param key - Cache key\n * @param typeOrOptions - Type string or options object (defaults to 'text')\n * @returns Object with value, metadata, and cacheStatus\n * @throws {CacheGetError} If operation fails\n */\n async getWithMetadata<Metadata = unknown>(\n key: string,\n typeOrOptions?: 'text' | KVNamespaceGetOptions<'text'>\n ): Promise<KVNamespaceGetWithMetadataResult<string, Metadata>>\n async getWithMetadata<ExpectedValue = unknown, Metadata = unknown>(\n key: string,\n typeOrOptions: 'json' | KVNamespaceGetOptions<'json'>\n ): Promise<KVNamespaceGetWithMetadataResult<ExpectedValue, Metadata>>\n async getWithMetadata<Metadata = unknown>(\n key: string,\n typeOrOptions: 'arrayBuffer' | KVNamespaceGetOptions<'arrayBuffer'>\n ): Promise<KVNamespaceGetWithMetadataResult<ArrayBuffer, Metadata>>\n async getWithMetadata<Metadata = unknown>(\n key: string,\n typeOrOptions: 'stream' | KVNamespaceGetOptions<'stream'>\n ): Promise<KVNamespaceGetWithMetadataResult<ReadableStream, Metadata>>\n\n async getWithMetadata<ExpectedValue = unknown, Metadata = unknown>(\n key: string,\n typeOrOptions?: string | KVNamespaceGetOptions<'text' | 'json' | 'arrayBuffer' | 'stream'>\n ): Promise<\n KVNamespaceGetWithMetadataResult<\n string | ExpectedValue | ArrayBuffer | ReadableStream,\n Metadata\n >\n > {\n try {\n if (typeof typeOrOptions === 'string') {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any -- bridging KV overloaded API\n return await this.kv.getWithMetadata(key, typeOrOptions as any)\n }\n\n if (typeOrOptions) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any -- bridging KV overloaded API\n return await this.kv.getWithMetadata(key, typeOrOptions as any)\n }\n\n return await this.kv.getWithMetadata(key)\n } catch (error) {\n this.logger.error('Cache getWithMetadata operation failed', { key, error })\n throw new CacheGetError(key)\n }\n }\n\n // ==================== PUT METHOD ====================\n\n /**\n * Store a value in cache\n *\n * @param key - Cache key\n * @param value - Value to store (string, ArrayBuffer, ArrayBufferView, or ReadableStream)\n * @param options - Put options (expiration, expirationTtl, metadata)\n * @throws {CachePutError} If operation fails\n *\n * @example\n * ```typescript\n * // Simple put\n * await cache.put('key', 'value')\n *\n * // With TTL\n * await cache.put('key', 'value', { expirationTtl: 3600 })\n *\n * // With metadata\n * await cache.put('key', 'value', { metadata: { created: Date.now() } })\n * ```\n */\n async put(\n key: string,\n value: string | ArrayBuffer | ArrayBufferView | ReadableStream,\n options?: KVNamespacePutOptions\n ): Promise<void> {\n try {\n await this.kv.put(key, value as string, options)\n } catch (error) {\n this.logger.error('Cache put operation failed', { key, error })\n throw new CachePutError(key)\n }\n }\n\n // ==================== DELETE METHODS ====================\n\n /**\n * Delete a value from cache\n *\n * @param key - Cache key to delete\n * @throws {CacheDeleteError} If operation fails\n */\n async delete(key: string): Promise<void> {\n try {\n await this.kv.delete(key)\n } catch (error) {\n this.logger.error('Cache delete operation failed', { key, error })\n throw new CacheDeleteError(key)\n }\n }\n\n\n // ==================== LIST METHOD ====================\n\n /**\n * List keys in cache\n *\n * @param options - List options (limit, prefix, cursor)\n * @returns List result with keys and pagination info\n * @throws {CacheListError} If operation fails\n *\n * @example\n * ```typescript\n * // List all keys\n * const result = await cache.list()\n *\n * // List with prefix\n * const result = await cache.list({ prefix: 'user:' })\n *\n * // Paginated list\n * const result = await cache.list({ limit: 100 })\n * if (!result.list_complete) {\n * const nextPage = await cache.list({ cursor: result.cursor })\n * }\n * ```\n */\n async list<Metadata = unknown>(\n options?: KVNamespaceListOptions\n ): Promise<KVNamespaceListResult<Metadata>> {\n try {\n return await this.kv.list<Metadata>(options)\n } catch (error) {\n this.logger.error('Cache list operation failed', { options, error })\n throw new CacheListError()\n }\n }\n}\n","/**\n * Cache Module\n *\n * Provides key-value caching capabilities using Cloudflare KV namespaces.\n *\n * **Features:**\n * - Type-safe KV wrapper with full method coverage\n * - Multiple KV binding support via `withBinding()`\n * - Automatic error handling with security-focused logging\n * - Singleton service for optimal performance\n */\n\nimport { Module } from '../module'\nimport { CACHE_TOKENS } from './cache.tokens'\nimport { CacheService } from './services'\n\n@Module({\n providers: [\n // Singleton - CacheService has no request dependencies\n { provide: CACHE_TOKENS.CacheService, useClass: CacheService },\n ],\n})\nexport class CacheModule {}\n"],"mappings":";;;;;;;;;;;;AASA,IAAa,gBAAb,cAAmC,iBAAiB;CAClD,YAAY,KAAa;AACvB,QAAM,0BAA0B,YAAY,OAAO,sBAAsB,EAAE,KAAK,CAAC;;;;;;;;;;;ACFrF,IAAa,gBAAb,cAAmC,iBAAiB;CAClD,YAAY,KAAa;AACvB,QAAM,0BAA0B,YAAY,OAAO,sBAAsB,EAAE,KAAK,CAAC;;;;;;;;;;;ACFrF,IAAa,mBAAb,cAAsC,iBAAiB;CACrD,YAAY,KAAa;AACvB,QAAM,6BAA6B,YAAY,OAAO,sBAAsB,EAAE,KAAK,CAAC;;;;;;;;;;ACHxF,IAAa,iBAAb,cAAoC,iBAAiB;CACnD,cAAc;AACZ,QAAM,2BAA2B,YAAY,OAAO,sBAAsB,EAAE,CAAC;;;;;;ACqC1E,IAAA,eAAA,gBAAA,MAAM,aAAa;CACxB;CAEA,YACE,KACA,QACA;AAFkD,OAAA,MAAA;AACI,OAAA,SAAA;AAEtD,OAAK,KAAK,IAAI;;;;;;;;;CAUhB,MAAM,IAAuB;AAC3B,OAAK,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BZ,YAAY,IAA+B;EACzC,MAAM,WAAW,IAAA,cAAiB,KAAK,KAAK,KAAK,OAAO;AACxD,WAAS,MAAM,GAAG;AAClB,SAAO;;CAkBT,MAAM,IACJ,KACA,eACuE;AACvE,MAAI;AACF,OAAI,OAAO,kBAAkB,SAE3B,QAAO,MAAM,KAAK,GAAG,IAAI,KAAK,cAAqB;AAGrD,OAAI,cAEF,QAAO,MAAM,KAAK,GAAG,IAAI,KAAK,cAAqB;AAGrD,UAAO,MAAM,KAAK,GAAG,IAAI,IAAI;WACtB,OAAO;AACd,QAAK,OAAO,MAAM,8BAA8B;IAAE;IAAK;IAAO,CAAC;AAC/D,SAAM,IAAI,cAAc,IAAI;;;CA+BhC,MAAM,gBACJ,KACA,eAMA;AACA,MAAI;AACF,OAAI,OAAO,kBAAkB,SAE3B,QAAO,MAAM,KAAK,GAAG,gBAAgB,KAAK,cAAqB;AAGjE,OAAI,cAEF,QAAO,MAAM,KAAK,GAAG,gBAAgB,KAAK,cAAqB;AAGjE,UAAO,MAAM,KAAK,GAAG,gBAAgB,IAAI;WAClC,OAAO;AACd,QAAK,OAAO,MAAM,0CAA0C;IAAE;IAAK;IAAO,CAAC;AAC3E,SAAM,IAAI,cAAc,IAAI;;;;;;;;;;;;;;;;;;;;;;;CA0BhC,MAAM,IACJ,KACA,OACA,SACe;AACf,MAAI;AACF,SAAM,KAAK,GAAG,IAAI,KAAK,OAAiB,QAAQ;WACzC,OAAO;AACd,QAAK,OAAO,MAAM,8BAA8B;IAAE;IAAK;IAAO,CAAC;AAC/D,SAAM,IAAI,cAAc,IAAI;;;;;;;;;CAYhC,MAAM,OAAO,KAA4B;AACvC,MAAI;AACF,SAAM,KAAK,GAAG,OAAO,IAAI;WAClB,OAAO;AACd,QAAK,OAAO,MAAM,iCAAiC;IAAE;IAAK;IAAO,CAAC;AAClE,SAAM,IAAI,iBAAiB,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;CA6BnC,MAAM,KACJ,SAC0C;AAC1C,MAAI;AACF,UAAO,MAAM,KAAK,GAAG,KAAe,QAAQ;WACrC,OAAO;AACd,QAAK,OAAO,MAAM,+BAA+B;IAAE;IAAS;IAAO,CAAC;AACpE,SAAM,IAAI,gBAAgB;;;;;CArO/B,UAAU,aAAa,aAAa;oBAKhC,OAAO,UAAU,cAAc,CAAA;oBAC/B,OAAO,cAAc,cAAc,CAAA;;;;;;;;;;;;;;;;AC9BjC,IAAA,cAAA,MAAM,YAAY;0BANxB,OAAO,EACN,WAAW,CAET;CAAE,SAAS,aAAa;CAAc,UAAU;CAAc,CAC/D,EACF,CAAC,CAAA,EAAA,YAAA"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/cache/errors/cache-get.error.ts","../../src/cache/errors/cache-put.error.ts","../../src/cache/errors/cache-delete.error.ts","../../src/cache/errors/cache-list.error.ts","../../src/cache/services/cache.service.ts","../../src/cache/cache.module.ts"],"sourcesContent":["import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\n/**\n * Error thrown when a cache get operation fails\n *\n * Raw error details are logged via LoggerService for security.\n * Only the key is included in the user-facing error message.\n */\nexport class CacheGetError extends ApplicationError {\n constructor(key: string) {\n super('errors.cache.getFailed', ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR, { key })\n }\n}\n","import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\n/**\n * Error thrown when a cache put operation fails\n *\n * Raw error details are logged via LoggerService for security.\n * Only the key is included in the user-facing error message.\n */\nexport class CachePutError extends ApplicationError {\n constructor(key: string) {\n super('errors.cache.putFailed', ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR, { key })\n }\n}\n","import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\n/**\n * Error thrown when a cache delete operation fails\n *\n * Raw error details are logged via LoggerService for security.\n * Only the key is included in the user-facing error message.\n */\nexport class CacheDeleteError extends ApplicationError {\n constructor(key: string) {\n super('errors.cache.deleteFailed', ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR, { key })\n }\n}\n","import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\n/**\n * Error thrown when a cache list operation fails\n *\n * Raw error details are logged via LoggerService for security.\n */\nexport class CacheListError extends ApplicationError {\n constructor() {\n super('errors.cache.listFailed', ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR, {})\n }\n}\n","import { inject } from 'tsyringe'\nimport { Transient } from '../../di/decorators'\nimport { DI_TOKENS } from '../../di/tokens'\nimport { type StratalEnv } from '../../env'\nimport { LOGGER_TOKENS, type LoggerService } from '../../logger'\nimport { CACHE_TOKENS } from '../cache.tokens'\nimport {\n CacheDeleteError,\n CacheGetError,\n CacheListError,\n CachePutError,\n} from '../errors'\n\n/**\n * Cache Service\n *\n * Type-safe wrapper around Cloudflare KV namespaces for caching operations.\n *\n * **Features:**\n * - Mirrors all KVNamespace methods with full type safety\n * - Supports multiple KV bindings via `withBinding()`\n * - Automatic error handling with logging\n * - Security: Raw errors are logged, not exposed to users\n *\n * **Usage:**\n * ```typescript\n * class MyService {\n * private readonly uploadsCache: CacheService\n *\n * constructor(\n * @inject(CACHE_TOKENS.CacheService) private readonly cache: CacheService,\n * @inject(DI_TOKENS.CloudflareEnv) private readonly env: Env\n * ) {\n * // Initialize specialized caches in constructor\n * this.uploadsCache = this.cache.withBinding(this.env.UPLOADS_CACHE)\n * }\n *\n * async cacheData(key: string, value: string) {\n * await this.cache.put(key, value, { expirationTtl: 3600 })\n * await this.uploadsCache.put(`upload:${key}`, value)\n * }\n * }\n * ```\n *\n * @see https://developers.cloudflare.com/kv/api/\n */\n@Transient(CACHE_TOKENS.CacheService)\nexport class CacheService {\n private kv: KVNamespace\n\n constructor(\n @inject(DI_TOKENS.CloudflareEnv) private readonly env: StratalEnv,\n @inject(LOGGER_TOKENS.LoggerService) private readonly logger: LoggerService\n ) {\n this.kv = env.CACHE\n }\n\n /**\n * Set the KV namespace binding\n *\n * Used internally by `withBinding()` to configure different KV instances.\n *\n * @param kv - KV namespace to use\n */\n setKV(kv: KVNamespace): void {\n this.kv = kv\n }\n\n /**\n * Create a new CacheService instance with a different KV binding\n *\n * **Pattern:** Returns a new instance (immutable)\n *\n * **Best Practice:** Initialize specialized caches as class properties in constructor\n *\n * @example\n * ```typescript\n * class MyService {\n * private readonly uploadsCache: CacheService\n * private readonly systemCache: CacheService\n *\n * constructor(\n * @inject(CACHE_TOKENS.CacheService) private readonly cache: CacheService,\n * @inject(DI_TOKENS.CloudflareEnv) private readonly env: Env\n * ) {\n * this.uploadsCache = this.cache.withBinding(this.env.UPLOADS_CACHE)\n * this.systemCache = this.cache.withBinding(this.env.SYSTEM_CONFIG_KV)\n * }\n * }\n * ```\n *\n * @param kv - KV namespace to use\n * @returns New CacheService instance with the specified binding\n */\n withBinding(kv: KVNamespace): CacheService {\n const instance = new CacheService(this.env, this.logger)\n instance.setKV(kv)\n return instance\n }\n\n // ==================== GET METHODS ====================\n\n /**\n * Get a value from cache\n *\n * @param key - Cache key\n * @param typeOrOptions - Type string or options object (defaults to 'text')\n * @returns Value in specified type, or null if not found\n * @throws {CacheGetError} If operation fails\n */\n async get(key: string, typeOrOptions?: 'text' | KVNamespaceGetOptions<'text'>): Promise<string | null>\n async get<ExpectedValue = unknown>(key: string, typeOrOptions: 'json' | KVNamespaceGetOptions<'json'>): Promise<ExpectedValue | null>\n async get(key: string, typeOrOptions: 'arrayBuffer' | KVNamespaceGetOptions<'arrayBuffer'>): Promise<ArrayBuffer | null>\n async get(key: string, typeOrOptions: 'stream' | KVNamespaceGetOptions<'stream'>): Promise<ReadableStream | null>\n\n async get<ExpectedValue = unknown>(\n key: string,\n typeOrOptions?: string | KVNamespaceGetOptions<'text' | 'json' | 'arrayBuffer' | 'stream'>\n ): Promise<string | ExpectedValue | ArrayBuffer | ReadableStream | null> {\n try {\n if (typeof typeOrOptions === 'string') {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any -- bridging KV overloaded API\n return await this.kv.get(key, typeOrOptions as any)\n }\n\n if (typeOrOptions) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any -- bridging KV overloaded API\n return await this.kv.get(key, typeOrOptions as any)\n }\n\n return await this.kv.get(key)\n } catch (error) {\n this.logger.error('Cache get operation failed', { key, error })\n throw new CacheGetError(key)\n }\n }\n\n // ==================== GET WITH METADATA METHODS ====================\n\n /**\n * Get a value with metadata from cache\n *\n * @param key - Cache key\n * @param typeOrOptions - Type string or options object (defaults to 'text')\n * @returns Object with value, metadata, and cacheStatus\n * @throws {CacheGetError} If operation fails\n */\n async getWithMetadata<Metadata = unknown>(\n key: string,\n typeOrOptions?: 'text' | KVNamespaceGetOptions<'text'>\n ): Promise<KVNamespaceGetWithMetadataResult<string, Metadata>>\n async getWithMetadata<ExpectedValue = unknown, Metadata = unknown>(\n key: string,\n typeOrOptions: 'json' | KVNamespaceGetOptions<'json'>\n ): Promise<KVNamespaceGetWithMetadataResult<ExpectedValue, Metadata>>\n async getWithMetadata<Metadata = unknown>(\n key: string,\n typeOrOptions: 'arrayBuffer' | KVNamespaceGetOptions<'arrayBuffer'>\n ): Promise<KVNamespaceGetWithMetadataResult<ArrayBuffer, Metadata>>\n async getWithMetadata<Metadata = unknown>(\n key: string,\n typeOrOptions: 'stream' | KVNamespaceGetOptions<'stream'>\n ): Promise<KVNamespaceGetWithMetadataResult<ReadableStream, Metadata>>\n\n async getWithMetadata<ExpectedValue = unknown, Metadata = unknown>(\n key: string,\n typeOrOptions?: string | KVNamespaceGetOptions<'text' | 'json' | 'arrayBuffer' | 'stream'>\n ): Promise<\n KVNamespaceGetWithMetadataResult<\n string | ExpectedValue | ArrayBuffer | ReadableStream,\n Metadata\n >\n > {\n try {\n if (typeof typeOrOptions === 'string') {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any -- bridging KV overloaded API\n return await this.kv.getWithMetadata(key, typeOrOptions as any)\n }\n\n if (typeOrOptions) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any -- bridging KV overloaded API\n return await this.kv.getWithMetadata(key, typeOrOptions as any)\n }\n\n return await this.kv.getWithMetadata(key)\n } catch (error) {\n this.logger.error('Cache getWithMetadata operation failed', { key, error })\n throw new CacheGetError(key)\n }\n }\n\n // ==================== PUT METHOD ====================\n\n /**\n * Store a value in cache\n *\n * @param key - Cache key\n * @param value - Value to store (string, ArrayBuffer, ArrayBufferView, or ReadableStream)\n * @param options - Put options (expiration, expirationTtl, metadata)\n * @throws {CachePutError} If operation fails\n *\n * @example\n * ```typescript\n * // Simple put\n * await cache.put('key', 'value')\n *\n * // With TTL\n * await cache.put('key', 'value', { expirationTtl: 3600 })\n *\n * // With metadata\n * await cache.put('key', 'value', { metadata: { created: Date.now() } })\n * ```\n */\n async put(\n key: string,\n value: string | ArrayBuffer | ArrayBufferView | ReadableStream,\n options?: KVNamespacePutOptions\n ): Promise<void> {\n try {\n await this.kv.put(key, value as string, options)\n } catch (error) {\n this.logger.error('Cache put operation failed', { key, error })\n throw new CachePutError(key)\n }\n }\n\n // ==================== DELETE METHODS ====================\n\n /**\n * Delete a value from cache\n *\n * @param key - Cache key to delete\n * @throws {CacheDeleteError} If operation fails\n */\n async delete(key: string): Promise<void> {\n try {\n await this.kv.delete(key)\n } catch (error) {\n this.logger.error('Cache delete operation failed', { key, error })\n throw new CacheDeleteError(key)\n }\n }\n\n\n // ==================== LIST METHOD ====================\n\n /**\n * List keys in cache\n *\n * @param options - List options (limit, prefix, cursor)\n * @returns List result with keys and pagination info\n * @throws {CacheListError} If operation fails\n *\n * @example\n * ```typescript\n * // List all keys\n * const result = await cache.list()\n *\n * // List with prefix\n * const result = await cache.list({ prefix: 'user:' })\n *\n * // Paginated list\n * const result = await cache.list({ limit: 100 })\n * if (!result.list_complete) {\n * const nextPage = await cache.list({ cursor: result.cursor })\n * }\n * ```\n */\n async list<Metadata = unknown>(\n options?: KVNamespaceListOptions\n ): Promise<KVNamespaceListResult<Metadata>> {\n try {\n return await this.kv.list<Metadata>(options)\n } catch (error) {\n this.logger.error('Cache list operation failed', { options, error })\n throw new CacheListError()\n }\n }\n}\n","/**\n * Cache Module\n *\n * Provides key-value caching capabilities using Cloudflare KV namespaces.\n *\n * **Features:**\n * - Type-safe KV wrapper with full method coverage\n * - Multiple KV binding support via `withBinding()`\n * - Automatic error handling with security-focused logging\n * - Singleton service for optimal performance\n */\n\nimport { Module } from '../module'\nimport { CACHE_TOKENS } from './cache.tokens'\nimport { CacheService } from './services'\n\n@Module({\n providers: [\n // Singleton - CacheService has no request dependencies\n { provide: CACHE_TOKENS.CacheService, useClass: CacheService },\n ],\n})\nexport class CacheModule {}\n"],"mappings":";;;;;;;;;;;;AASA,IAAa,gBAAb,cAAmC,iBAAiB;CAClD,YAAY,KAAa;EACvB,MAAM,0BAA0B,YAAY,OAAO,sBAAsB,EAAE,KAAK,CAAC;;;;;;;;;;;ACFrF,IAAa,gBAAb,cAAmC,iBAAiB;CAClD,YAAY,KAAa;EACvB,MAAM,0BAA0B,YAAY,OAAO,sBAAsB,EAAE,KAAK,CAAC;;;;;;;;;;;ACFrF,IAAa,mBAAb,cAAsC,iBAAiB;CACrD,YAAY,KAAa;EACvB,MAAM,6BAA6B,YAAY,OAAO,sBAAsB,EAAE,KAAK,CAAC;;;;;;;;;;ACHxF,IAAa,iBAAb,cAAoC,iBAAiB;CACnD,cAAc;EACZ,MAAM,2BAA2B,YAAY,OAAO,sBAAsB,EAAE,CAAC;;;;;;ACqC1E,IAAA,eAAA,gBAAA,MAAM,aAAa;CAI4B;CACI;CAJxD;CAEA,YACE,KACA,QACA;EAFkD,KAAA,MAAA;EACI,KAAA,SAAA;EAEtD,KAAK,KAAK,IAAI;;;;;;;;;CAUhB,MAAM,IAAuB;EAC3B,KAAK,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BZ,YAAY,IAA+B;EACzC,MAAM,WAAW,IAAA,cAAiB,KAAK,KAAK,KAAK,OAAO;EACxD,SAAS,MAAM,GAAG;EAClB,OAAO;;CAkBT,MAAM,IACJ,KACA,eACuE;EACvE,IAAI;GACF,IAAI,OAAO,kBAAkB,UAE3B,OAAO,MAAM,KAAK,GAAG,IAAI,KAAK,cAAqB;GAGrD,IAAI,eAEF,OAAO,MAAM,KAAK,GAAG,IAAI,KAAK,cAAqB;GAGrD,OAAO,MAAM,KAAK,GAAG,IAAI,IAAI;WACtB,OAAO;GACd,KAAK,OAAO,MAAM,8BAA8B;IAAE;IAAK;IAAO,CAAC;GAC/D,MAAM,IAAI,cAAc,IAAI;;;CA+BhC,MAAM,gBACJ,KACA,eAMA;EACA,IAAI;GACF,IAAI,OAAO,kBAAkB,UAE3B,OAAO,MAAM,KAAK,GAAG,gBAAgB,KAAK,cAAqB;GAGjE,IAAI,eAEF,OAAO,MAAM,KAAK,GAAG,gBAAgB,KAAK,cAAqB;GAGjE,OAAO,MAAM,KAAK,GAAG,gBAAgB,IAAI;WAClC,OAAO;GACd,KAAK,OAAO,MAAM,0CAA0C;IAAE;IAAK;IAAO,CAAC;GAC3E,MAAM,IAAI,cAAc,IAAI;;;;;;;;;;;;;;;;;;;;;;;CA0BhC,MAAM,IACJ,KACA,OACA,SACe;EACf,IAAI;GACF,MAAM,KAAK,GAAG,IAAI,KAAK,OAAiB,QAAQ;WACzC,OAAO;GACd,KAAK,OAAO,MAAM,8BAA8B;IAAE;IAAK;IAAO,CAAC;GAC/D,MAAM,IAAI,cAAc,IAAI;;;;;;;;;CAYhC,MAAM,OAAO,KAA4B;EACvC,IAAI;GACF,MAAM,KAAK,GAAG,OAAO,IAAI;WAClB,OAAO;GACd,KAAK,OAAO,MAAM,iCAAiC;IAAE;IAAK;IAAO,CAAC;GAClE,MAAM,IAAI,iBAAiB,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;CA6BnC,MAAM,KACJ,SAC0C;EAC1C,IAAI;GACF,OAAO,MAAM,KAAK,GAAG,KAAe,QAAQ;WACrC,OAAO;GACd,KAAK,OAAO,MAAM,+BAA+B;IAAE;IAAS;IAAO,CAAC;GACpE,MAAM,IAAI,gBAAgB;;;;;CArO/B,UAAU,aAAa,aAAa;oBAKhC,OAAO,UAAU,cAAc,CAAA;oBAC/B,OAAO,cAAc,cAAc,CAAA;;;;;;;;;;;;;;;;AC9BjC,IAAA,cAAA,MAAM,YAAY;0BANxB,OAAO,EACN,WAAW,CAET;CAAE,SAAS,aAAa;CAAc,UAAU;CAAc,CAC/D,EACF,CAAC,CAAA,EAAA,YAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-BgSlsS4M.mjs","names":[],"sources":["../src/quarry/constants.ts","../src/quarry/errors/command.error.ts","../src/quarry/command.ts"],"sourcesContent":["/**\n * Symbol key for storing internal mutable state on Command instances.\n * Keeps internal state hidden from user-facing autocomplete.\n */\nexport const COMMAND_INTERNALS = Symbol.for('stratal:command:internals')\n","/**\n * User-facing command error with a plain English message.\n *\n * Quarry catches this in `call()` and puts the message into `CommandResult.errors`.\n * Does NOT extend `ApplicationError` (which requires i18n keys + error codes).\n * Not routed through ExceptionHandler.\n */\nexport class CommandError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'CommandError'\n }\n}\n","import 'reflect-metadata'\n\nimport { bold, cyan, dim, green, red, yellow } from './colors'\nimport { COMMAND_INTERNALS } from './constants'\nimport { CommandError } from './errors/command.error'\nimport type { CommandInput, CommandInternals, CommandResult } from './types'\n\n/**\n * Abstract base class for Quarry commands.\n *\n * Subclasses define a static `command` signature string and implement `handle()`.\n *\n * @example\n * ```typescript\n * export class GreetCommand extends Command {\n * static command = 'greet {name : The name to greet} {--loud}'\n * static description = 'Greet someone'\n *\n * async handle(): Promise<void> {\n * const name = this.string('name')\n * const loud = this.boolean('loud')\n * this.info(loud ? `HELLO, ${name.toUpperCase()}!` : `Hello, ${name}!`)\n * }\n * }\n * ```\n */\nexport abstract class Command {\n /**\n * Laravel-style command signature string.\n *\n * **Command names:**\n * - `'greet'` — flat command (`quarry greet`)\n * - `'task add'` — subcommand hierarchy via spaces (`quarry task add`)\n * - `'task:add'` — namespaced flat command via colons (`quarry task:add`)\n *\n * **Arguments:**\n * - `{name}` — required argument\n * - `{name?}` — optional argument\n * - `{name=default}` — argument with default value\n * - `{name*}` — array/variadic argument\n * - `{name : description}` — argument with description\n *\n * **Options:**\n * - `{--flag}` — boolean flag\n * - `{--name=}` — option that accepts a value\n * - `{--name=default}` — option with default value\n * - `{--name=*}` — array option (multiple values)\n * - `{--A|name}` — option with single-char alias\n * - `{--name= : description}` — option with description\n *\n * @example\n * ```typescript\n * // Namespaced flat command: `quarry users:create ...`\n * static command = 'users:create {email : The user email} {--A|admin} {--R|role= : Assign a role}'\n *\n * // Subcommand hierarchy: `quarry users create ...`\n * static command = 'users create {email : The user email} {--A|admin} {--R|role= : Assign a role}'\n * ```\n */\n static command: string\n /** Human-readable description */\n static description?: string\n /** Alternative command names */\n static aliases?: string[];\n\n [COMMAND_INTERNALS]: CommandInternals\n\n constructor() {\n this[COMMAND_INTERNALS] = {\n inputs: {},\n output: [],\n errors: [],\n exitCode: 0,\n quarry: null,\n }\n }\n\n /**\n * Implement this method with the command's logic.\n * Return a number to set the exit code, or void for exit code 0.\n */\n // eslint-disable-next-line @typescript-eslint/no-invalid-void-type\n abstract handle(): number | void | Promise<number | void>\n\n // ── Input Accessors ──────────────────────────────────────────────\n\n /**\n * Get an input value with generic type.\n */\n input<T>(name: string): T {\n return this[COMMAND_INTERNALS].inputs[name] as T\n }\n\n /**\n * Get a string input. Throws CommandError if present but not a string.\n */\n string(name: string): string {\n const value = this[COMMAND_INTERNALS].inputs[name]\n if (value === undefined || value === null) {\n return ''\n }\n if (typeof value !== 'string') {\n throw new CommandError(`Input \"${name}\" expected a string, got ${typeof value}`)\n }\n return value\n }\n\n /**\n * Get a boolean input. Throws CommandError if present but not a boolean.\n */\n boolean(name: string): boolean {\n const value = this[COMMAND_INTERNALS].inputs[name]\n if (value === undefined || value === null) {\n return false\n }\n if (typeof value !== 'boolean') {\n throw new CommandError(`Input \"${name}\" expected a boolean, got ${typeof value}`)\n }\n return value\n }\n\n /**\n * Get a number input. Coerces strings to numbers. Throws CommandError on NaN.\n */\n number(name: string): number {\n const value = this[COMMAND_INTERNALS].inputs[name]\n if (value === undefined || value === null) {\n return 0\n }\n const num = typeof value === 'string' ? Number(value) : value\n if (typeof num !== 'number' || Number.isNaN(num)) {\n throw new CommandError(`Input \"${name}\" expected a number, got ${typeof value}`)\n }\n return num\n }\n\n /**\n * Get an array input. Throws CommandError if present but not an array.\n */\n array(name: string): string[] {\n const value = this[COMMAND_INTERNALS].inputs[name]\n if (value === undefined || value === null) {\n return []\n }\n if (!Array.isArray(value)) {\n throw new CommandError(`Input \"${name}\" expected an array, got ${typeof value}`)\n }\n return value as string[]\n }\n\n // ── Output Helpers ───────────────────────────────────────────────\n\n /** Write an informational message to output */\n info(message: string): void {\n this[COMMAND_INTERNALS].output.push(cyan(message))\n }\n\n /** Write a success message to output */\n success(message: string): void {\n this[COMMAND_INTERNALS].output.push(`${green(bold('✔'))} ${green(message)}`)\n }\n\n /** Write a warning message to output */\n warn(message: string): void {\n this[COMMAND_INTERNALS].output.push(`${yellow(bold('⚠'))} ${yellow(message)}`)\n }\n\n /** Write an error message to errors */\n error(message: string): void {\n this[COMMAND_INTERNALS].errors.push(red(message))\n }\n\n /** Write a plain line to output */\n line(message?: string): void {\n this[COMMAND_INTERNALS].output.push(message ?? '')\n }\n\n /** Write an empty line to output */\n newLine(): void {\n this[COMMAND_INTERNALS].output.push('')\n }\n\n /** Write a comment-style line to output */\n comment(message: string): void {\n this[COMMAND_INTERNALS].output.push(dim(`// ${message}`))\n }\n\n /** Write a formatted table to output */\n table(headers: string[], rows: string[][]): void {\n const colWidths = headers.map((h, i) => {\n const maxRow = rows.reduce((max, row) => Math.max(max, (row[i] ?? '').length), 0)\n return Math.max(h.length, maxRow)\n })\n\n const formatRow = (cells: string[]) =>\n cells.map((cell, i) => cell.padEnd(colWidths[i])).join(' ')\n\n this[COMMAND_INTERNALS].output.push(bold(formatRow(headers)))\n this[COMMAND_INTERNALS].output.push(dim(colWidths.map((w) => '-'.repeat(w)).join(' ')))\n for (const row of rows) {\n this[COMMAND_INTERNALS].output.push(formatRow(row))\n }\n }\n\n /** Write an error message and set exit code */\n fail(message: string, exitCode = 1): void {\n this[COMMAND_INTERNALS].errors.push(`${red(bold('✖'))} ${red(message)}`)\n this[COMMAND_INTERNALS].exitCode = exitCode\n }\n\n // ── Command Calling ──────────────────────────────────────────────\n\n /**\n * Call another command from within this command.\n * Delegates to Quarry.call() via internal reference.\n */\n async call(name: string, input?: CommandInput): Promise<CommandResult> {\n const internals = this[COMMAND_INTERNALS]\n if (!internals.quarry) {\n throw new CommandError('Cannot call commands: Quarry reference not set')\n }\n const result = await internals.quarry.call(name, input)\n\n // Forward child output/errors into parent (like Clipanion context switches)\n internals.output.push(...result.output)\n internals.errors.push(...result.errors)\n\n return result\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"command-BgSlsS4M.mjs","names":[],"sources":["../src/quarry/constants.ts","../src/quarry/errors/command.error.ts","../src/quarry/command.ts"],"sourcesContent":["/**\n * Symbol key for storing internal mutable state on Command instances.\n * Keeps internal state hidden from user-facing autocomplete.\n */\nexport const COMMAND_INTERNALS = Symbol.for('stratal:command:internals')\n","/**\n * User-facing command error with a plain English message.\n *\n * Quarry catches this in `call()` and puts the message into `CommandResult.errors`.\n * Does NOT extend `ApplicationError` (which requires i18n keys + error codes).\n * Not routed through ExceptionHandler.\n */\nexport class CommandError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'CommandError'\n }\n}\n","import 'reflect-metadata'\n\nimport { bold, cyan, dim, green, red, yellow } from './colors'\nimport { COMMAND_INTERNALS } from './constants'\nimport { CommandError } from './errors/command.error'\nimport type { CommandInput, CommandInternals, CommandResult } from './types'\n\n/**\n * Abstract base class for Quarry commands.\n *\n * Subclasses define a static `command` signature string and implement `handle()`.\n *\n * @example\n * ```typescript\n * export class GreetCommand extends Command {\n * static command = 'greet {name : The name to greet} {--loud}'\n * static description = 'Greet someone'\n *\n * async handle(): Promise<void> {\n * const name = this.string('name')\n * const loud = this.boolean('loud')\n * this.info(loud ? `HELLO, ${name.toUpperCase()}!` : `Hello, ${name}!`)\n * }\n * }\n * ```\n */\nexport abstract class Command {\n /**\n * Laravel-style command signature string.\n *\n * **Command names:**\n * - `'greet'` — flat command (`quarry greet`)\n * - `'task add'` — subcommand hierarchy via spaces (`quarry task add`)\n * - `'task:add'` — namespaced flat command via colons (`quarry task:add`)\n *\n * **Arguments:**\n * - `{name}` — required argument\n * - `{name?}` — optional argument\n * - `{name=default}` — argument with default value\n * - `{name*}` — array/variadic argument\n * - `{name : description}` — argument with description\n *\n * **Options:**\n * - `{--flag}` — boolean flag\n * - `{--name=}` — option that accepts a value\n * - `{--name=default}` — option with default value\n * - `{--name=*}` — array option (multiple values)\n * - `{--A|name}` — option with single-char alias\n * - `{--name= : description}` — option with description\n *\n * @example\n * ```typescript\n * // Namespaced flat command: `quarry users:create ...`\n * static command = 'users:create {email : The user email} {--A|admin} {--R|role= : Assign a role}'\n *\n * // Subcommand hierarchy: `quarry users create ...`\n * static command = 'users create {email : The user email} {--A|admin} {--R|role= : Assign a role}'\n * ```\n */\n static command: string\n /** Human-readable description */\n static description?: string\n /** Alternative command names */\n static aliases?: string[];\n\n [COMMAND_INTERNALS]: CommandInternals\n\n constructor() {\n this[COMMAND_INTERNALS] = {\n inputs: {},\n output: [],\n errors: [],\n exitCode: 0,\n quarry: null,\n }\n }\n\n /**\n * Implement this method with the command's logic.\n * Return a number to set the exit code, or void for exit code 0.\n */\n // eslint-disable-next-line @typescript-eslint/no-invalid-void-type\n abstract handle(): number | void | Promise<number | void>\n\n // ── Input Accessors ──────────────────────────────────────────────\n\n /**\n * Get an input value with generic type.\n */\n input<T>(name: string): T {\n return this[COMMAND_INTERNALS].inputs[name] as T\n }\n\n /**\n * Get a string input. Throws CommandError if present but not a string.\n */\n string(name: string): string {\n const value = this[COMMAND_INTERNALS].inputs[name]\n if (value === undefined || value === null) {\n return ''\n }\n if (typeof value !== 'string') {\n throw new CommandError(`Input \"${name}\" expected a string, got ${typeof value}`)\n }\n return value\n }\n\n /**\n * Get a boolean input. Throws CommandError if present but not a boolean.\n */\n boolean(name: string): boolean {\n const value = this[COMMAND_INTERNALS].inputs[name]\n if (value === undefined || value === null) {\n return false\n }\n if (typeof value !== 'boolean') {\n throw new CommandError(`Input \"${name}\" expected a boolean, got ${typeof value}`)\n }\n return value\n }\n\n /**\n * Get a number input. Coerces strings to numbers. Throws CommandError on NaN.\n */\n number(name: string): number {\n const value = this[COMMAND_INTERNALS].inputs[name]\n if (value === undefined || value === null) {\n return 0\n }\n const num = typeof value === 'string' ? Number(value) : value\n if (typeof num !== 'number' || Number.isNaN(num)) {\n throw new CommandError(`Input \"${name}\" expected a number, got ${typeof value}`)\n }\n return num\n }\n\n /**\n * Get an array input. Throws CommandError if present but not an array.\n */\n array(name: string): string[] {\n const value = this[COMMAND_INTERNALS].inputs[name]\n if (value === undefined || value === null) {\n return []\n }\n if (!Array.isArray(value)) {\n throw new CommandError(`Input \"${name}\" expected an array, got ${typeof value}`)\n }\n return value as string[]\n }\n\n // ── Output Helpers ───────────────────────────────────────────────\n\n /** Write an informational message to output */\n info(message: string): void {\n this[COMMAND_INTERNALS].output.push(cyan(message))\n }\n\n /** Write a success message to output */\n success(message: string): void {\n this[COMMAND_INTERNALS].output.push(`${green(bold('✔'))} ${green(message)}`)\n }\n\n /** Write a warning message to output */\n warn(message: string): void {\n this[COMMAND_INTERNALS].output.push(`${yellow(bold('⚠'))} ${yellow(message)}`)\n }\n\n /** Write an error message to errors */\n error(message: string): void {\n this[COMMAND_INTERNALS].errors.push(red(message))\n }\n\n /** Write a plain line to output */\n line(message?: string): void {\n this[COMMAND_INTERNALS].output.push(message ?? '')\n }\n\n /** Write an empty line to output */\n newLine(): void {\n this[COMMAND_INTERNALS].output.push('')\n }\n\n /** Write a comment-style line to output */\n comment(message: string): void {\n this[COMMAND_INTERNALS].output.push(dim(`// ${message}`))\n }\n\n /** Write a formatted table to output */\n table(headers: string[], rows: string[][]): void {\n const colWidths = headers.map((h, i) => {\n const maxRow = rows.reduce((max, row) => Math.max(max, (row[i] ?? '').length), 0)\n return Math.max(h.length, maxRow)\n })\n\n const formatRow = (cells: string[]) =>\n cells.map((cell, i) => cell.padEnd(colWidths[i])).join(' ')\n\n this[COMMAND_INTERNALS].output.push(bold(formatRow(headers)))\n this[COMMAND_INTERNALS].output.push(dim(colWidths.map((w) => '-'.repeat(w)).join(' ')))\n for (const row of rows) {\n this[COMMAND_INTERNALS].output.push(formatRow(row))\n }\n }\n\n /** Write an error message and set exit code */\n fail(message: string, exitCode = 1): void {\n this[COMMAND_INTERNALS].errors.push(`${red(bold('✖'))} ${red(message)}`)\n this[COMMAND_INTERNALS].exitCode = exitCode\n }\n\n // ── Command Calling ──────────────────────────────────────────────\n\n /**\n * Call another command from within this command.\n * Delegates to Quarry.call() via internal reference.\n */\n async call(name: string, input?: CommandInput): Promise<CommandResult> {\n const internals = this[COMMAND_INTERNALS]\n if (!internals.quarry) {\n throw new CommandError('Cannot call commands: Quarry reference not set')\n }\n const result = await internals.quarry.call(name, input)\n\n // Forward child output/errors into parent (like Clipanion context switches)\n internals.output.push(...result.output)\n internals.errors.push(...result.errors)\n\n return result\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { dn as CommandResult, ln as CommandInput, un as CommandInternals } from "./index-
|
|
1
|
+
import { dn as CommandResult, ln as CommandInput, un as CommandInternals } from "./index-ByOyTmqf.mjs";
|
|
2
2
|
//#region src/quarry/constants.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* Symbol key for storing internal mutable state on Command instances.
|
|
@@ -117,4 +117,4 @@ declare abstract class Command {
|
|
|
117
117
|
}
|
|
118
118
|
//#endregion
|
|
119
119
|
export { Command as t };
|
|
120
|
-
//# sourceMappingURL=command-
|
|
120
|
+
//# sourceMappingURL=command-Cmmf0oHX.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-
|
|
1
|
+
{"version":3,"file":"command-Cmmf0oHX.d.mts","names":[],"sources":["../src/quarry/constants.ts","../src/quarry/command.ts"],"mappings":";;;;;;cAIa,iBAAA;;;;AAAb;;;;;;;;ACsBA;;;;;;;;;;uBAAsB,OAAA;EA8LmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAAA,OA7JhD,OAAA;EA4HC;EAAA,OA1HD,WAAA;EA+HD;EAAA,OA7HC,OAAA;EAAA,CAEN,iBAAA,GAAoB,gBAAA;;EA4IC;;;;EAAA,SA3Hb,MAAA,CAAA,mBAA0B,OAAA;EAsIa;;;EA/HhD,KAAA,GAAA,CAAS,IAAA,WAAe,CAAA;;;;EAOxB,MAAA,CAAO,IAAA;;;;EAcP,OAAA,CAAQ,IAAA;;;;EAcR,MAAA,CAAO,IAAA;;;;EAeP,KAAA,CAAM,IAAA;;EAcN,IAAA,CAAK,OAAA;;EAKL,OAAA,CAAQ,OAAA;;EAKR,IAAA,CAAK,OAAA;;EAKL,KAAA,CAAM,OAAA;;EAKN,IAAA,CAAK,OAAA;;EAKL,OAAA,CAAA;;EAKA,OAAA,CAAQ,OAAA;;EAKR,KAAA,CAAM,OAAA,YAAmB,IAAA;;EAiBzB,IAAA,CAAK,OAAA,UAAiB,QAAA;;;;;EAWhB,IAAA,CAAK,IAAA,UAAc,KAAA,GAAQ,YAAA,GAAe,OAAA,CAAQ,aAAA;AAAA"}
|
package/dist/config/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Cn as ModuleContext, En as OnInitialize, bn as FactoryProvider, vn as DynamicModule } from "../index-
|
|
1
|
+
import { Cn as ModuleContext, En as OnInitialize, bn as FactoryProvider, vn as DynamicModule } from "../index-ByOyTmqf.mjs";
|
|
2
2
|
import { t as Macroable } from "../index-7-hU3GTV.mjs";
|
|
3
3
|
import { o as z } from "../index-Bnpfq6uk.mjs";
|
|
4
4
|
import { InjectionToken } from "tsyringe";
|
package/dist/config/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { A as Scope, H as ApplicationError, k as ERROR_CODES } from "../errors-
|
|
2
|
-
import { a as __decorate, f as DI_TOKENS, o as __decorateParam, p as Transient, s as __decorateMetadata } from "../logger-
|
|
1
|
+
import { A as Scope, H as ApplicationError, k as ERROR_CODES } from "../errors-COW9-Mar.mjs";
|
|
2
|
+
import { a as __decorate, f as DI_TOKENS, o as __decorateParam, p as Transient, s as __decorateMetadata } from "../logger-DlV7NtvD.mjs";
|
|
3
3
|
import { t as Macroable } from "../macroable-BmufBshB.mjs";
|
|
4
|
-
import { k as Module } from "../module-
|
|
4
|
+
import { k as Module } from "../module-BzLg57FK.mjs";
|
|
5
5
|
import { inject } from "tsyringe";
|
|
6
6
|
//#region src/config/config.tokens.ts
|
|
7
7
|
const CONFIG_TOKENS = {
|
|
@@ -11,6 +11,7 @@ const CONFIG_TOKENS = {
|
|
|
11
11
|
//#endregion
|
|
12
12
|
//#region src/config/config.types.ts
|
|
13
13
|
var ConfigValidationError = class extends Error {
|
|
14
|
+
errors;
|
|
14
15
|
constructor(message, errors) {
|
|
15
16
|
super(message);
|
|
16
17
|
this.errors = errors;
|
|
@@ -46,6 +47,7 @@ var ConfigNotInitializedError = class extends ApplicationError {
|
|
|
46
47
|
//#endregion
|
|
47
48
|
//#region src/config/services/config.service.ts
|
|
48
49
|
let ConfigService = class ConfigService extends Macroable {
|
|
50
|
+
store;
|
|
49
51
|
overrides = /* @__PURE__ */ new Map();
|
|
50
52
|
constructor(store) {
|
|
51
53
|
super();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/config/config.tokens.ts","../../src/config/config.types.ts","../../src/config/errors/config-module-not-initialized.error.ts","../../src/config/errors/config-not-initialized.error.ts","../../src/config/services/config.service.ts","../../src/config/services/config.store.ts","../../src/config/config.module.ts","../../src/config/register-as.ts"],"sourcesContent":["export const CONFIG_TOKENS = {\n\tConfigService: Symbol.for('stratal:config:service'),\n\tConfigStore: Symbol.for('stratal:config:store'),\n} as const\n","import type { z } from '../i18n/validation'\n\nexport class ConfigValidationError extends Error {\n constructor(\n message: string,\n public readonly errors: z.ZodError\n ) {\n super(message)\n this.name = 'ConfigValidationError'\n }\n}\n\n/**\n * Configuration that can be augmented by applications\n * Apps should augment this interface with their AppConfig type using module augmentation\n *\n * @example\n * ```typescript\n * // In your app (e.g., apps/backend/src/config/types.ts)\n * declare module 'stratal' {\n * interface ModuleConfig {\n * database: { url: string; maxConnections: number }\n * email: { provider: string; from: { name: string; email: string } }\n * }\n * }\n * ```\n */\nexport interface ModuleConfig { }\n\n/**\n * Generate all valid dot-notation paths from a config object type\n * @example ConfigPath<{ database: { url: string } }> = 'database' | 'database.url'\n */\nexport type ConfigPath<T> = {\n [K in keyof T & string]: T[K] extends Record<string, unknown>\n ? K | `${K}.${ConfigPath<T[K]>}`\n : K\n}[keyof T & string]\n\n/**\n * Get the value type at a dot-notation path\n * @example ConfigPathValue<{ database: { url: string } }, 'database.url'> = string\n */\nexport type ConfigPathValue<T, P extends string> = P extends `${infer K}.${infer Rest}`\n ? K extends keyof T\n ? T[K] extends Record<string, unknown>\n ? ConfigPathValue<T[K], Rest>\n : never\n : never\n : P extends keyof T\n ? T[P]\n : never\n\n/**\n * ConfigService interface with dot notation support.\n *\n * Values are initialized on the underlying {@link ConfigStore} via\n * {@link ConfigModule}; the service itself exposes request-scoped\n * reads and per-request overrides.\n */\nexport interface IConfigService<T extends object = ModuleConfig> {\n /**\n * Get config value using dot notation\n * @example config.get('database.url')\n */\n get<P extends ConfigPath<T>>(path: P): ConfigPathValue<T, P>\n\n /**\n * Set config value at runtime (for runtime overrides)\n * @example config.set('email.from.name', 'Custom Name')\n */\n set<P extends ConfigPath<T>>(path: P, value: ConfigPathValue<T, P>): void\n\n /**\n * Reset config to original value\n * @param path - Optional path to reset (resets entire config if omitted)\n */\n reset(path?: ConfigPath<T>): void\n\n /**\n * Get entire config object\n */\n all(): Readonly<T>\n\n /**\n * Check if a config path exists\n */\n has(path: ConfigPath<T>): boolean\n}\n","import { ApplicationError, ERROR_CODES } from '../../errors'\n\n/**\n * Error thrown when ConfigModule's onInitialize runs but forRoot() was never called.\n *\n * This means the module was imported without calling ConfigModule.forRoot({ load: [...] }).\n */\nexport class ConfigModuleNotInitializedError extends ApplicationError {\n constructor() {\n super(\n 'errors.configModuleNotInitialized',\n ERROR_CODES.SYSTEM.CONFIG_MODULE_NOT_INITIALIZED\n )\n }\n}\n","import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\n/**\n * ConfigNotInitializedError\n *\n * Thrown when attempting to access ConfigService before it has been initialized.\n * This typically indicates that ConfigModule's onInitialize hook hasn't run yet,\n * or the module wasn't registered properly.\n */\nexport class ConfigNotInitializedError extends ApplicationError {\n constructor() {\n super(\n 'errors.configNotInitialized',\n ERROR_CODES.SYSTEM.CONFIG_NOT_INITIALIZED\n )\n }\n}\n","import { inject } from 'tsyringe'\nimport { Transient } from '../../di/decorators'\nimport { Macroable } from '../../macroable/macroable'\nimport { CONFIG_TOKENS } from '../config.tokens'\nimport type { ConfigPath, ConfigPathValue, IConfigService, ModuleConfig } from '../config.types'\nimport { type ConfigStore } from './config.store'\n\n/**\n * ConfigService with dot notation support and per-request overrides.\n *\n * ConfigService is **request-scoped**: each request gets its own\n * instance with a private `overrides` map layered over the shared\n * {@link ConfigStore}. Calls to {@link set} mutate only the current\n * request's overrides, which makes it safe to mutate config from\n * middleware (e.g. to pin `environment.appUrl` to the request host).\n *\n * Extends {@link Macroable} so apps can add domain-specific getters\n * and methods via `ConfigService.getter()` / `ConfigService.macro()`.\n *\n * @example\n * ```typescript\n * // Read with dot notation\n * const url = config.get('database.url')\n * const fromName = config.get('email.from.name')\n *\n * // Per-request override (e.g. in middleware)\n * config.set('environment.appUrl', `${proto}://${host}`)\n *\n * // Reset the override for the current request\n * config.reset('environment.appUrl')\n * ```\n */\n@Transient(CONFIG_TOKENS.ConfigService)\nexport class ConfigService<T extends object = ModuleConfig> extends Macroable implements IConfigService<T> {\n private overrides = new Map<string, unknown>()\n\n constructor(\n @inject(CONFIG_TOKENS.ConfigStore) private readonly store: ConfigStore<T>,\n ) {\n super()\n }\n\n /**\n * Get config value using dot notation. Request overrides take\n * precedence over the shared store.\n */\n get<P extends ConfigPath<T>>(path: P): ConfigPathValue<T, P> {\n const override = this.readOverride(path)\n if (override !== undefined) {\n return override as ConfigPathValue<T, P>\n }\n return this.store.get(path)\n }\n\n /**\n * Set a config value for the lifetime of the current request.\n * Does not mutate the shared store.\n */\n set<P extends ConfigPath<T>>(path: P, value: ConfigPathValue<T, P>): void {\n if (this.hasDangerousSegment(path)) return\n this.overrides.set(path, value)\n }\n\n /**\n * Clear a single override, or all overrides for this request.\n */\n reset(path?: ConfigPath<T>): void {\n if (path) {\n this.overrides.delete(path)\n return\n }\n this.overrides.clear()\n }\n\n /**\n * Get the full config object, with request overrides merged in.\n */\n all(): Readonly<T> {\n const base = this.store.all() as T\n if (this.overrides.size === 0) {\n return base as Readonly<T>\n }\n const merged = this.deepClone(base)\n for (const [path, value] of this.overrides) {\n this.writeByPath(merged, path, value)\n }\n return merged as Readonly<T>\n }\n\n /**\n * Check if a config path exists (in overrides or the store).\n */\n has(path: ConfigPath<T>): boolean {\n if (this.readOverride(path) !== undefined) return true\n return this.store.has(path)\n }\n\n private readOverride(path: string): unknown {\n if (this.hasDangerousSegment(path)) return undefined\n if (this.overrides.has(path)) {\n return this.overrides.get(path)\n }\n // Support partial-path reads: if an ancestor was overridden, walk into it.\n const segments = path.split('.')\n for (let i = segments.length - 1; i > 0; i--) {\n const parent = segments.slice(0, i).join('.')\n if (this.overrides.has(parent)) {\n const parentValue = this.overrides.get(parent)\n return this.walk(parentValue, segments.slice(i))\n }\n }\n return undefined\n }\n\n private walk(value: unknown, keys: string[]): unknown {\n let current = value\n for (const key of keys) {\n if (current === null || current === undefined) return undefined\n current = (current as Record<string, unknown>)[key]\n }\n return current\n }\n\n private writeByPath(obj: unknown, path: string, value: unknown): void {\n const keys = path.split('.')\n if (keys.some((key) => this.isDangerousKey(key))) return\n let current = obj as Record<string, unknown>\n for (let i = 0; i < keys.length - 1; i++) {\n const key = keys[i]\n if (!Object.hasOwn(current, key) || typeof current[key] !== 'object' || current[key] === null) {\n Object.defineProperty(current, key, {\n value: {},\n writable: true,\n enumerable: true,\n configurable: true,\n })\n }\n current = current[key] as Record<string, unknown>\n }\n Object.defineProperty(current, keys[keys.length - 1], {\n value,\n writable: true,\n enumerable: true,\n configurable: true,\n })\n }\n\n private hasDangerousSegment(path: string): boolean {\n return path.split('.').some((key) => this.isDangerousKey(key))\n }\n\n private isDangerousKey(key: string): boolean {\n return key === '__proto__' || key === 'constructor' || key === 'prototype'\n }\n\n private deepClone<V>(obj: V): V {\n if (obj === null || typeof obj !== 'object') {\n return obj\n }\n return JSON.parse(JSON.stringify(obj)) as V\n }\n}\n","import { Transient } from '../../di/decorators'\nimport { CONFIG_TOKENS } from '../config.tokens'\nimport type { ConfigPath, ConfigPathValue, ModuleConfig } from '../config.types'\nimport { ConfigNotInitializedError } from '../errors'\n\n/**\n * ConfigStore\n *\n * Singleton-scoped holder of validated, merged configuration.\n *\n * ConfigStore is the source of truth for configuration values. It is\n * initialized once during application startup by {@link ConfigModule}\n * and never mutated afterwards.\n *\n * Per-request overrides live on {@link ConfigService}, which reads\n * through to this store for any key not explicitly overridden.\n */\n@Transient(CONFIG_TOKENS.ConfigStore)\nexport class ConfigStore<T extends object = ModuleConfig> {\n private data: T | undefined\n\n /**\n * Initialize the store with validated configuration.\n * Called by {@link ConfigModule} during initialization.\n */\n initialize(config: T): void {\n this.data = this.deepClone(config)\n }\n\n /**\n * Get config value using dot notation.\n */\n get<P extends ConfigPath<T>>(path: P): ConfigPathValue<T, P> {\n this.ensureInitialized()\n return this.getByPath(this.data, path) as ConfigPathValue<T, P>\n }\n\n /**\n * Check if a config path exists.\n */\n has(path: ConfigPath<T>): boolean {\n this.ensureInitialized()\n return this.getByPath(this.data, path) !== undefined\n }\n\n /**\n * Get the entire config object (readonly snapshot).\n */\n all(): Readonly<T> {\n this.ensureInitialized()\n return this.data as Readonly<T>\n }\n\n /**\n * True once {@link initialize} has been called.\n */\n isInitialized(): boolean {\n return this.data !== undefined\n }\n\n private getByPath(obj: unknown, path: string): unknown {\n const keys = path.split('.')\n let current = obj\n for (const key of keys) {\n if (this.isDangerousKey(key)) return undefined\n if (current === null || current === undefined) return undefined\n current = (current as Record<string, unknown>)[key]\n }\n return current\n }\n\n private isDangerousKey(key: string): boolean {\n return key === '__proto__' || key === 'constructor' || key === 'prototype'\n }\n\n private ensureInitialized(): void {\n if (this.data === undefined) {\n throw new ConfigNotInitializedError()\n }\n }\n\n private deepClone<V>(obj: V): V {\n if (obj === null || typeof obj !== 'object') {\n return obj\n }\n return JSON.parse(JSON.stringify(obj)) as V\n }\n}\n","import { DI_TOKENS } from '../di/tokens'\nimport { Scope } from '../di/types'\nimport type { z } from '../i18n/validation'\nimport { Module } from '../module'\nimport type { DynamicModule, ModuleContext, OnInitialize, Provider } from '../module/types'\nimport { CONFIG_TOKENS } from './config.tokens'\nimport { ConfigValidationError, type ModuleConfig } from './config.types'\nimport { ConfigModuleNotInitializedError } from './errors'\nimport type { ConfigNamespace } from './register-as'\nimport { ConfigService } from './services/config.service'\nimport { ConfigStore } from './services/config.store'\n\n/**\n * Any config namespace - uses structural typing for flexibility\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyConfigNamespace = ConfigNamespace<string, any, object>\n\n/**\n * Options for ConfigModule.forRoot\n */\nexport interface ConfigModuleOptions {\n /**\n * Array of config namespaces created via registerAs()\n */\n load: AnyConfigNamespace[]\n\n /**\n * Optional Zod schema for validating the merged config\n * Validates the entire config object after all namespaces are merged\n */\n validateSchema?: z.ZodType<object>\n}\n\n// Store options for use in onInitialize\nlet moduleOptions: ConfigModuleOptions | null = null\n\n/**\n * ConfigModule\n *\n * Provides configuration management with namespace support.\n * Uses registerAs() to create typed config namespaces that can be injected.\n *\n * @example\n * ```typescript\n * // Define config namespaces\n * const databaseConfig = registerAs('database', (env) => ({\n * url: env.DATABASE_URL,\n * maxConnections: 10\n * }))\n *\n * const emailConfig = registerAs('email', (env) => ({\n * provider: env.EMAIL_PROVIDER,\n * from: { name: 'App', email: 'noreply@example.com' }\n * }))\n *\n * // Register in module\n * @Module({\n * imports: [\n * ConfigModule.forRoot({\n * load: [databaseConfig, emailConfig],\n * validateSchema: AppConfigSchema\n * })\n * ]\n * })\n * export class AppModule {}\n *\n * // Inject config\n * constructor(\n * @inject(CONFIG_TOKENS.ConfigService) private config: IConfigService,\n * @inject(databaseConfig.KEY) private dbConfig: DatabaseConfig\n * ) {\n * // Use dot notation\n * const url = this.config.get('database.url')\n *\n * // Or inject namespace directly\n * const url = this.dbConfig.url\n * }\n * ```\n */\n@Module({\n providers: [\n // ConfigStore is the singleton source of truth for validated config.\n {\n provide: CONFIG_TOKENS.ConfigStore,\n useClass: ConfigStore,\n scope: Scope.Singleton,\n },\n // ConfigService is request-scoped: each request gets its own\n // overrides map layered over the shared ConfigStore.\n {\n provide: CONFIG_TOKENS.ConfigService,\n useClass: ConfigService,\n scope: Scope.Request,\n },\n ],\n})\nexport class ConfigModule implements OnInitialize {\n /**\n * Configure ConfigModule with namespace loaders\n *\n * @param options - Configuration options\n * @returns Dynamic module with config infrastructure\n */\n static forRoot(options: ConfigModuleOptions): DynamicModule {\n moduleOptions = options\n\n const providers: Provider[] = []\n\n // Register each namespace config using asProvider()\n for (const namespace of options.load) {\n providers.push(namespace.asProvider())\n }\n\n return {\n module: ConfigModule,\n providers,\n }\n }\n\n /**\n * Initialize config service with merged namespaces\n * Called after all providers are registered\n */\n onInitialize(context: ModuleContext): void {\n if (!moduleOptions) {\n throw new ConfigModuleNotInitializedError()\n }\n\n const env = context.container.resolve<unknown>(DI_TOKENS.CloudflareEnv)\n const configStore = context.container.resolve<ConfigStore>(CONFIG_TOKENS.ConfigStore)\n\n // Build merged config from all namespaces\n const mergedConfig: Record<string, unknown> = {}\n\n for (const namespace of moduleOptions.load) {\n mergedConfig[namespace.namespace] = namespace.factory(env)\n }\n\n // Validate if schema provided\n if (moduleOptions.validateSchema) {\n const result = moduleOptions.validateSchema.safeParse(mergedConfig)\n if (!result.success) {\n throw new ConfigValidationError(\n 'Configuration validation failed',\n result.error\n )\n }\n }\n\n // Initialize the shared ConfigStore with merged config.\n configStore.initialize(mergedConfig as ModuleConfig)\n\n context.logger.debug('ConfigModule initialized', {\n namespaces: moduleOptions.load.map((n) => n.namespace),\n })\n }\n}\n","import type { InjectionToken } from 'tsyringe'\nimport { DI_TOKENS } from '../di/tokens'\nimport type { FactoryProvider } from '../module/types'\n\n/**\n * Configuration namespace registration result\n */\nexport interface ConfigNamespace<TKey extends string, TEnv, TConfig extends object> {\n /** Auto-derived injection token (e.g., 'database' -> Symbol('stratal:config:database')) */\n readonly KEY: InjectionToken<TConfig>\n /** The namespace key */\n readonly namespace: TKey\n /** The factory function that receives env and returns config */\n readonly factory: (env: TEnv) => TConfig\n /**\n * Returns a provider configuration for use in module registration\n * Automatically injects DI_TOKENS.CloudflareEnv\n */\n asProvider(): FactoryProvider<TConfig>\n}\n\n/**\n * Create a namespaced configuration factory\n * Similar to NestJS registerAs\n *\n * @param namespace - Configuration namespace (e.g., 'database', 'email')\n * @param factory - Factory function receiving env and returning config object\n * @returns ConfigNamespace with token, factory, and asProvider() method\n *\n * @example\n * ```typescript\n * // apps/backend/src/config/database.config.ts\n * export const databaseConfig = registerAs('database', (env: Env) => ({\n * url: env.DATABASE_URL,\n * maxConnections: parseInt(env.DATABASE_MAX_CONNECTIONS || '10'),\n * }))\n *\n * // Auto-generates: databaseConfig.KEY = Symbol('stratal:config:database')\n *\n * // Usage in module:\n * // Option 1: Manual provider\n * {\n * provide: databaseConfig.KEY,\n * useFactory: databaseConfig.factory,\n * inject: [DI_TOKENS.CloudflareEnv]\n * }\n *\n * // Option 2: asProvider() helper\n * databaseConfig.asProvider()\n * // Returns: { provide: databaseConfig.KEY, useFactory: ..., inject: [DI_TOKENS.CloudflareEnv] }\n * ```\n */\nexport function registerAs<TKey extends string, TEnv, TConfig extends object>(\n namespace: TKey,\n factory: (env: TEnv) => TConfig\n): ConfigNamespace<TKey, TEnv, TConfig> {\n const KEY = Symbol.for(`stratal:config:${namespace}`) as InjectionToken<TConfig>\n\n return {\n KEY,\n namespace,\n factory,\n asProvider(): FactoryProvider<TConfig> {\n return {\n provide: KEY,\n useFactory: factory,\n inject: [DI_TOKENS.CloudflareEnv],\n }\n },\n }\n}\n\n/**\n * Helper to derive config type from registerAs result\n *\n * @example\n * ```typescript\n * const databaseConfig = registerAs('database', (env) => ({ url: env.DATABASE_URL }))\n * type DatabaseConfig = InferConfigType<typeof databaseConfig>\n * // { url: string }\n * ```\n */\nexport type InferConfigType<T> = T extends ConfigNamespace<string, unknown, infer C> ? C : never\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/config/config.tokens.ts","../../src/config/config.types.ts","../../src/config/errors/config-module-not-initialized.error.ts","../../src/config/errors/config-not-initialized.error.ts","../../src/config/services/config.service.ts","../../src/config/services/config.store.ts","../../src/config/config.module.ts","../../src/config/register-as.ts"],"sourcesContent":["export const CONFIG_TOKENS = {\n\tConfigService: Symbol.for('stratal:config:service'),\n\tConfigStore: Symbol.for('stratal:config:store'),\n} as const\n","import type { z } from '../i18n/validation'\n\nexport class ConfigValidationError extends Error {\n constructor(\n message: string,\n public readonly errors: z.ZodError\n ) {\n super(message)\n this.name = 'ConfigValidationError'\n }\n}\n\n/**\n * Configuration that can be augmented by applications\n * Apps should augment this interface with their AppConfig type using module augmentation\n *\n * @example\n * ```typescript\n * // In your app (e.g., apps/backend/src/config/types.ts)\n * declare module 'stratal' {\n * interface ModuleConfig {\n * database: { url: string; maxConnections: number }\n * email: { provider: string; from: { name: string; email: string } }\n * }\n * }\n * ```\n */\nexport interface ModuleConfig { }\n\n/**\n * Generate all valid dot-notation paths from a config object type\n * @example ConfigPath<{ database: { url: string } }> = 'database' | 'database.url'\n */\nexport type ConfigPath<T> = {\n [K in keyof T & string]: T[K] extends Record<string, unknown>\n ? K | `${K}.${ConfigPath<T[K]>}`\n : K\n}[keyof T & string]\n\n/**\n * Get the value type at a dot-notation path\n * @example ConfigPathValue<{ database: { url: string } }, 'database.url'> = string\n */\nexport type ConfigPathValue<T, P extends string> = P extends `${infer K}.${infer Rest}`\n ? K extends keyof T\n ? T[K] extends Record<string, unknown>\n ? ConfigPathValue<T[K], Rest>\n : never\n : never\n : P extends keyof T\n ? T[P]\n : never\n\n/**\n * ConfigService interface with dot notation support.\n *\n * Values are initialized on the underlying {@link ConfigStore} via\n * {@link ConfigModule}; the service itself exposes request-scoped\n * reads and per-request overrides.\n */\nexport interface IConfigService<T extends object = ModuleConfig> {\n /**\n * Get config value using dot notation\n * @example config.get('database.url')\n */\n get<P extends ConfigPath<T>>(path: P): ConfigPathValue<T, P>\n\n /**\n * Set config value at runtime (for runtime overrides)\n * @example config.set('email.from.name', 'Custom Name')\n */\n set<P extends ConfigPath<T>>(path: P, value: ConfigPathValue<T, P>): void\n\n /**\n * Reset config to original value\n * @param path - Optional path to reset (resets entire config if omitted)\n */\n reset(path?: ConfigPath<T>): void\n\n /**\n * Get entire config object\n */\n all(): Readonly<T>\n\n /**\n * Check if a config path exists\n */\n has(path: ConfigPath<T>): boolean\n}\n","import { ApplicationError, ERROR_CODES } from '../../errors'\n\n/**\n * Error thrown when ConfigModule's onInitialize runs but forRoot() was never called.\n *\n * This means the module was imported without calling ConfigModule.forRoot({ load: [...] }).\n */\nexport class ConfigModuleNotInitializedError extends ApplicationError {\n constructor() {\n super(\n 'errors.configModuleNotInitialized',\n ERROR_CODES.SYSTEM.CONFIG_MODULE_NOT_INITIALIZED\n )\n }\n}\n","import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\n/**\n * ConfigNotInitializedError\n *\n * Thrown when attempting to access ConfigService before it has been initialized.\n * This typically indicates that ConfigModule's onInitialize hook hasn't run yet,\n * or the module wasn't registered properly.\n */\nexport class ConfigNotInitializedError extends ApplicationError {\n constructor() {\n super(\n 'errors.configNotInitialized',\n ERROR_CODES.SYSTEM.CONFIG_NOT_INITIALIZED\n )\n }\n}\n","import { inject } from 'tsyringe'\nimport { Transient } from '../../di/decorators'\nimport { Macroable } from '../../macroable/macroable'\nimport { CONFIG_TOKENS } from '../config.tokens'\nimport type { ConfigPath, ConfigPathValue, IConfigService, ModuleConfig } from '../config.types'\nimport { type ConfigStore } from './config.store'\n\n/**\n * ConfigService with dot notation support and per-request overrides.\n *\n * ConfigService is **request-scoped**: each request gets its own\n * instance with a private `overrides` map layered over the shared\n * {@link ConfigStore}. Calls to {@link set} mutate only the current\n * request's overrides, which makes it safe to mutate config from\n * middleware (e.g. to pin `environment.appUrl` to the request host).\n *\n * Extends {@link Macroable} so apps can add domain-specific getters\n * and methods via `ConfigService.getter()` / `ConfigService.macro()`.\n *\n * @example\n * ```typescript\n * // Read with dot notation\n * const url = config.get('database.url')\n * const fromName = config.get('email.from.name')\n *\n * // Per-request override (e.g. in middleware)\n * config.set('environment.appUrl', `${proto}://${host}`)\n *\n * // Reset the override for the current request\n * config.reset('environment.appUrl')\n * ```\n */\n@Transient(CONFIG_TOKENS.ConfigService)\nexport class ConfigService<T extends object = ModuleConfig> extends Macroable implements IConfigService<T> {\n private overrides = new Map<string, unknown>()\n\n constructor(\n @inject(CONFIG_TOKENS.ConfigStore) private readonly store: ConfigStore<T>,\n ) {\n super()\n }\n\n /**\n * Get config value using dot notation. Request overrides take\n * precedence over the shared store.\n */\n get<P extends ConfigPath<T>>(path: P): ConfigPathValue<T, P> {\n const override = this.readOverride(path)\n if (override !== undefined) {\n return override as ConfigPathValue<T, P>\n }\n return this.store.get(path)\n }\n\n /**\n * Set a config value for the lifetime of the current request.\n * Does not mutate the shared store.\n */\n set<P extends ConfigPath<T>>(path: P, value: ConfigPathValue<T, P>): void {\n if (this.hasDangerousSegment(path)) return\n this.overrides.set(path, value)\n }\n\n /**\n * Clear a single override, or all overrides for this request.\n */\n reset(path?: ConfigPath<T>): void {\n if (path) {\n this.overrides.delete(path)\n return\n }\n this.overrides.clear()\n }\n\n /**\n * Get the full config object, with request overrides merged in.\n */\n all(): Readonly<T> {\n const base = this.store.all() as T\n if (this.overrides.size === 0) {\n return base as Readonly<T>\n }\n const merged = this.deepClone(base)\n for (const [path, value] of this.overrides) {\n this.writeByPath(merged, path, value)\n }\n return merged as Readonly<T>\n }\n\n /**\n * Check if a config path exists (in overrides or the store).\n */\n has(path: ConfigPath<T>): boolean {\n if (this.readOverride(path) !== undefined) return true\n return this.store.has(path)\n }\n\n private readOverride(path: string): unknown {\n if (this.hasDangerousSegment(path)) return undefined\n if (this.overrides.has(path)) {\n return this.overrides.get(path)\n }\n // Support partial-path reads: if an ancestor was overridden, walk into it.\n const segments = path.split('.')\n for (let i = segments.length - 1; i > 0; i--) {\n const parent = segments.slice(0, i).join('.')\n if (this.overrides.has(parent)) {\n const parentValue = this.overrides.get(parent)\n return this.walk(parentValue, segments.slice(i))\n }\n }\n return undefined\n }\n\n private walk(value: unknown, keys: string[]): unknown {\n let current = value\n for (const key of keys) {\n if (current === null || current === undefined) return undefined\n current = (current as Record<string, unknown>)[key]\n }\n return current\n }\n\n private writeByPath(obj: unknown, path: string, value: unknown): void {\n const keys = path.split('.')\n if (keys.some((key) => this.isDangerousKey(key))) return\n let current = obj as Record<string, unknown>\n for (let i = 0; i < keys.length - 1; i++) {\n const key = keys[i]\n if (!Object.hasOwn(current, key) || typeof current[key] !== 'object' || current[key] === null) {\n Object.defineProperty(current, key, {\n value: {},\n writable: true,\n enumerable: true,\n configurable: true,\n })\n }\n current = current[key] as Record<string, unknown>\n }\n Object.defineProperty(current, keys[keys.length - 1], {\n value,\n writable: true,\n enumerable: true,\n configurable: true,\n })\n }\n\n private hasDangerousSegment(path: string): boolean {\n return path.split('.').some((key) => this.isDangerousKey(key))\n }\n\n private isDangerousKey(key: string): boolean {\n return key === '__proto__' || key === 'constructor' || key === 'prototype'\n }\n\n private deepClone<V>(obj: V): V {\n if (obj === null || typeof obj !== 'object') {\n return obj\n }\n return JSON.parse(JSON.stringify(obj)) as V\n }\n}\n","import { Transient } from '../../di/decorators'\nimport { CONFIG_TOKENS } from '../config.tokens'\nimport type { ConfigPath, ConfigPathValue, ModuleConfig } from '../config.types'\nimport { ConfigNotInitializedError } from '../errors'\n\n/**\n * ConfigStore\n *\n * Singleton-scoped holder of validated, merged configuration.\n *\n * ConfigStore is the source of truth for configuration values. It is\n * initialized once during application startup by {@link ConfigModule}\n * and never mutated afterwards.\n *\n * Per-request overrides live on {@link ConfigService}, which reads\n * through to this store for any key not explicitly overridden.\n */\n@Transient(CONFIG_TOKENS.ConfigStore)\nexport class ConfigStore<T extends object = ModuleConfig> {\n private data: T | undefined\n\n /**\n * Initialize the store with validated configuration.\n * Called by {@link ConfigModule} during initialization.\n */\n initialize(config: T): void {\n this.data = this.deepClone(config)\n }\n\n /**\n * Get config value using dot notation.\n */\n get<P extends ConfigPath<T>>(path: P): ConfigPathValue<T, P> {\n this.ensureInitialized()\n return this.getByPath(this.data, path) as ConfigPathValue<T, P>\n }\n\n /**\n * Check if a config path exists.\n */\n has(path: ConfigPath<T>): boolean {\n this.ensureInitialized()\n return this.getByPath(this.data, path) !== undefined\n }\n\n /**\n * Get the entire config object (readonly snapshot).\n */\n all(): Readonly<T> {\n this.ensureInitialized()\n return this.data as Readonly<T>\n }\n\n /**\n * True once {@link initialize} has been called.\n */\n isInitialized(): boolean {\n return this.data !== undefined\n }\n\n private getByPath(obj: unknown, path: string): unknown {\n const keys = path.split('.')\n let current = obj\n for (const key of keys) {\n if (this.isDangerousKey(key)) return undefined\n if (current === null || current === undefined) return undefined\n current = (current as Record<string, unknown>)[key]\n }\n return current\n }\n\n private isDangerousKey(key: string): boolean {\n return key === '__proto__' || key === 'constructor' || key === 'prototype'\n }\n\n private ensureInitialized(): void {\n if (this.data === undefined) {\n throw new ConfigNotInitializedError()\n }\n }\n\n private deepClone<V>(obj: V): V {\n if (obj === null || typeof obj !== 'object') {\n return obj\n }\n return JSON.parse(JSON.stringify(obj)) as V\n }\n}\n","import { DI_TOKENS } from '../di/tokens'\nimport { Scope } from '../di/types'\nimport type { z } from '../i18n/validation'\nimport { Module } from '../module'\nimport type { DynamicModule, ModuleContext, OnInitialize, Provider } from '../module/types'\nimport { CONFIG_TOKENS } from './config.tokens'\nimport { ConfigValidationError, type ModuleConfig } from './config.types'\nimport { ConfigModuleNotInitializedError } from './errors'\nimport type { ConfigNamespace } from './register-as'\nimport { ConfigService } from './services/config.service'\nimport { ConfigStore } from './services/config.store'\n\n/**\n * Any config namespace - uses structural typing for flexibility\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyConfigNamespace = ConfigNamespace<string, any, object>\n\n/**\n * Options for ConfigModule.forRoot\n */\nexport interface ConfigModuleOptions {\n /**\n * Array of config namespaces created via registerAs()\n */\n load: AnyConfigNamespace[]\n\n /**\n * Optional Zod schema for validating the merged config\n * Validates the entire config object after all namespaces are merged\n */\n validateSchema?: z.ZodType<object>\n}\n\n// Store options for use in onInitialize\nlet moduleOptions: ConfigModuleOptions | null = null\n\n/**\n * ConfigModule\n *\n * Provides configuration management with namespace support.\n * Uses registerAs() to create typed config namespaces that can be injected.\n *\n * @example\n * ```typescript\n * // Define config namespaces\n * const databaseConfig = registerAs('database', (env) => ({\n * url: env.DATABASE_URL,\n * maxConnections: 10\n * }))\n *\n * const emailConfig = registerAs('email', (env) => ({\n * provider: env.EMAIL_PROVIDER,\n * from: { name: 'App', email: 'noreply@example.com' }\n * }))\n *\n * // Register in module\n * @Module({\n * imports: [\n * ConfigModule.forRoot({\n * load: [databaseConfig, emailConfig],\n * validateSchema: AppConfigSchema\n * })\n * ]\n * })\n * export class AppModule {}\n *\n * // Inject config\n * constructor(\n * @inject(CONFIG_TOKENS.ConfigService) private config: IConfigService,\n * @inject(databaseConfig.KEY) private dbConfig: DatabaseConfig\n * ) {\n * // Use dot notation\n * const url = this.config.get('database.url')\n *\n * // Or inject namespace directly\n * const url = this.dbConfig.url\n * }\n * ```\n */\n@Module({\n providers: [\n // ConfigStore is the singleton source of truth for validated config.\n {\n provide: CONFIG_TOKENS.ConfigStore,\n useClass: ConfigStore,\n scope: Scope.Singleton,\n },\n // ConfigService is request-scoped: each request gets its own\n // overrides map layered over the shared ConfigStore.\n {\n provide: CONFIG_TOKENS.ConfigService,\n useClass: ConfigService,\n scope: Scope.Request,\n },\n ],\n})\nexport class ConfigModule implements OnInitialize {\n /**\n * Configure ConfigModule with namespace loaders\n *\n * @param options - Configuration options\n * @returns Dynamic module with config infrastructure\n */\n static forRoot(options: ConfigModuleOptions): DynamicModule {\n moduleOptions = options\n\n const providers: Provider[] = []\n\n // Register each namespace config using asProvider()\n for (const namespace of options.load) {\n providers.push(namespace.asProvider())\n }\n\n return {\n module: ConfigModule,\n providers,\n }\n }\n\n /**\n * Initialize config service with merged namespaces\n * Called after all providers are registered\n */\n onInitialize(context: ModuleContext): void {\n if (!moduleOptions) {\n throw new ConfigModuleNotInitializedError()\n }\n\n const env = context.container.resolve<unknown>(DI_TOKENS.CloudflareEnv)\n const configStore = context.container.resolve<ConfigStore>(CONFIG_TOKENS.ConfigStore)\n\n // Build merged config from all namespaces\n const mergedConfig: Record<string, unknown> = {}\n\n for (const namespace of moduleOptions.load) {\n mergedConfig[namespace.namespace] = namespace.factory(env)\n }\n\n // Validate if schema provided\n if (moduleOptions.validateSchema) {\n const result = moduleOptions.validateSchema.safeParse(mergedConfig)\n if (!result.success) {\n throw new ConfigValidationError(\n 'Configuration validation failed',\n result.error\n )\n }\n }\n\n // Initialize the shared ConfigStore with merged config.\n configStore.initialize(mergedConfig as ModuleConfig)\n\n context.logger.debug('ConfigModule initialized', {\n namespaces: moduleOptions.load.map((n) => n.namespace),\n })\n }\n}\n","import type { InjectionToken } from 'tsyringe'\nimport { DI_TOKENS } from '../di/tokens'\nimport type { FactoryProvider } from '../module/types'\n\n/**\n * Configuration namespace registration result\n */\nexport interface ConfigNamespace<TKey extends string, TEnv, TConfig extends object> {\n /** Auto-derived injection token (e.g., 'database' -> Symbol('stratal:config:database')) */\n readonly KEY: InjectionToken<TConfig>\n /** The namespace key */\n readonly namespace: TKey\n /** The factory function that receives env and returns config */\n readonly factory: (env: TEnv) => TConfig\n /**\n * Returns a provider configuration for use in module registration\n * Automatically injects DI_TOKENS.CloudflareEnv\n */\n asProvider(): FactoryProvider<TConfig>\n}\n\n/**\n * Create a namespaced configuration factory\n * Similar to NestJS registerAs\n *\n * @param namespace - Configuration namespace (e.g., 'database', 'email')\n * @param factory - Factory function receiving env and returning config object\n * @returns ConfigNamespace with token, factory, and asProvider() method\n *\n * @example\n * ```typescript\n * // apps/backend/src/config/database.config.ts\n * export const databaseConfig = registerAs('database', (env: Env) => ({\n * url: env.DATABASE_URL,\n * maxConnections: parseInt(env.DATABASE_MAX_CONNECTIONS || '10'),\n * }))\n *\n * // Auto-generates: databaseConfig.KEY = Symbol('stratal:config:database')\n *\n * // Usage in module:\n * // Option 1: Manual provider\n * {\n * provide: databaseConfig.KEY,\n * useFactory: databaseConfig.factory,\n * inject: [DI_TOKENS.CloudflareEnv]\n * }\n *\n * // Option 2: asProvider() helper\n * databaseConfig.asProvider()\n * // Returns: { provide: databaseConfig.KEY, useFactory: ..., inject: [DI_TOKENS.CloudflareEnv] }\n * ```\n */\nexport function registerAs<TKey extends string, TEnv, TConfig extends object>(\n namespace: TKey,\n factory: (env: TEnv) => TConfig\n): ConfigNamespace<TKey, TEnv, TConfig> {\n const KEY = Symbol.for(`stratal:config:${namespace}`) as InjectionToken<TConfig>\n\n return {\n KEY,\n namespace,\n factory,\n asProvider(): FactoryProvider<TConfig> {\n return {\n provide: KEY,\n useFactory: factory,\n inject: [DI_TOKENS.CloudflareEnv],\n }\n },\n }\n}\n\n/**\n * Helper to derive config type from registerAs result\n *\n * @example\n * ```typescript\n * const databaseConfig = registerAs('database', (env) => ({ url: env.DATABASE_URL }))\n * type DatabaseConfig = InferConfigType<typeof databaseConfig>\n * // { url: string }\n * ```\n */\nexport type InferConfigType<T> = T extends ConfigNamespace<string, unknown, infer C> ? C : never\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { f as ROUTE_METADATA_KEYS } from "./errors-
|
|
2
|
-
import { p as Transient } from "./logger-
|
|
1
|
+
import { f as ROUTE_METADATA_KEYS } from "./errors-COW9-Mar.mjs";
|
|
2
|
+
import { p as Transient } from "./logger-DlV7NtvD.mjs";
|
|
3
3
|
//#region src/router/decorators/controller.decorator.ts
|
|
4
4
|
const CONTROLLER_ROUTE_KEY = ROUTE_METADATA_KEYS.CONTROLLER_ROUTE;
|
|
5
5
|
/**
|
|
@@ -63,4 +63,4 @@ function getControllerVersion(target) {
|
|
|
63
63
|
//#endregion
|
|
64
64
|
export { getControllerVersion as i, getControllerOptions as n, getControllerRoute as r, Controller as t };
|
|
65
65
|
|
|
66
|
-
//# sourceMappingURL=controller.decorator-
|
|
66
|
+
//# sourceMappingURL=controller.decorator-B9vwn0zK.mjs.map
|
package/dist/{controller.decorator-DQzenvSN.mjs.map → controller.decorator-B9vwn0zK.mjs.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller.decorator-
|
|
1
|
+
{"version":3,"file":"controller.decorator-B9vwn0zK.mjs","names":[],"sources":["../src/router/decorators/controller.decorator.ts"],"sourcesContent":["import { Transient } from '../../di/decorators'\nimport { type Constructor } from '../../types'\nimport { ROUTE_METADATA_KEYS } from '../constants'\nimport { type ControllerOptions } from '../types'\n\nconst CONTROLLER_ROUTE_KEY = ROUTE_METADATA_KEYS.CONTROLLER_ROUTE\n\n/**\n * Base controller decorator for route registration\n *\n * This is the core controller decorator that handles:\n * - Transient scope registration (request-scoped)\n * - Route metadata storage\n * - Controller options (tags, security schemes, hideFromDocs)\n *\n * @param route - Base route for this controller (e.g., '/api/v1/users')\n * @param options - Optional configuration (tags, security schemes, hideFromDocs)\n *\n * @example\n * ```typescript\n * import { Controller } from 'stratal/router'\n *\n * @Controller('/api/v1/users', { tags: ['Users'] })\n * export class UsersController implements IController {\n * // All routes accessible\n * }\n * ```\n */\nexport function Controller(route: string, options?: ControllerOptions) {\n return function <T extends Constructor>(target: T) {\n // Wrap @Transient (handles @injectable and scope metadata)\n Transient()(target)\n\n // Store route metadata on the class\n Reflect.defineMetadata(CONTROLLER_ROUTE_KEY, route, target)\n\n // Store options metadata if provided\n if (options) {\n Reflect.defineMetadata(ROUTE_METADATA_KEYS.CONTROLLER_OPTIONS, options, target)\n }\n\n return target\n }\n}\n\n/**\n * Get the route from controller class metadata\n *\n * @param target - Controller class or instance\n * @returns Route string or undefined if not set\n */\nexport function getControllerRoute(target: object): string | undefined {\n // Check if target is a class constructor (function) or an instance\n // If class, get metadata from it directly; if instance, get from constructor\n const metadataTarget = typeof target === 'function' ? target : (target as { constructor: object }).constructor\n return Reflect.getMetadata(CONTROLLER_ROUTE_KEY, metadataTarget) as string | undefined\n}\n\n/**\n * Get the options from controller class metadata\n *\n * @param target - Controller class or instance\n * @returns Controller options or undefined if not set\n */\nexport function getControllerOptions(target: object): ControllerOptions | undefined {\n const metadataTarget = typeof target === 'function' ? target : (target as { constructor: object }).constructor\n return Reflect.getMetadata(ROUTE_METADATA_KEYS.CONTROLLER_OPTIONS, metadataTarget) as ControllerOptions | undefined\n}\n\n/**\n * Get the version from controller class metadata\n *\n * @param target - Controller class or instance\n * @returns Version string, array, VERSION_NEUTRAL symbol, or undefined if not set\n */\nexport function getControllerVersion(target: object): ControllerOptions['version'] {\n const options = getControllerOptions(target)\n return options?.version\n}\n"],"mappings":";;;AAKA,MAAM,uBAAuB,oBAAoB;;;;;;;;;;;;;;;;;;;;;;AAuBjD,SAAgB,WAAW,OAAe,SAA6B;CACrE,OAAO,SAAiC,QAAW;EAEjD,WAAW,CAAC,OAAO;EAGnB,QAAQ,eAAe,sBAAsB,OAAO,OAAO;EAG3D,IAAI,SACF,QAAQ,eAAe,oBAAoB,oBAAoB,SAAS,OAAO;EAGjF,OAAO;;;;;;;;;AAUX,SAAgB,mBAAmB,QAAoC;CAGrE,MAAM,iBAAiB,OAAO,WAAW,aAAa,SAAU,OAAmC;CACnG,OAAO,QAAQ,YAAY,sBAAsB,eAAe;;;;;;;;AASlE,SAAgB,qBAAqB,QAA+C;CAClF,MAAM,iBAAiB,OAAO,WAAW,aAAa,SAAU,OAAmC;CACnG,OAAO,QAAQ,YAAY,oBAAoB,oBAAoB,eAAe;;;;;;;;AASpF,SAAgB,qBAAqB,QAA8C;CAEjF,OADgB,qBAAqB,OACvB,EAAE"}
|
package/dist/cron/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { d as ApplicationError } from "../index-
|
|
2
|
-
import { n as CronJob, r as RegisteredJob, t as CronManager } from "../cron-manager-
|
|
1
|
+
import { d as ApplicationError } from "../index-ByOyTmqf.mjs";
|
|
2
|
+
import { n as CronJob, r as RegisteredJob, t as CronManager } from "../cron-manager-CmTimEjf.mjs";
|
|
3
3
|
import { ScheduledController } from "@cloudflare/workers-types";
|
|
4
4
|
|
|
5
5
|
//#region src/cron/errors/cron-execution.error.d.ts
|
package/dist/cron/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as CronExecutionError, t as CronManager } from "../cron-manager-
|
|
1
|
+
import { n as CronExecutionError, t as CronManager } from "../cron-manager-DQSK8uoV.mjs";
|
|
2
2
|
export { CronExecutionError, CronManager };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Dr as Container } from "./index-
|
|
1
|
+
import { Dr as Container } from "./index-ByOyTmqf.mjs";
|
|
2
2
|
import { t as Constructor } from "./types-cySNS_lp.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/cron/cron-job.d.ts
|
|
@@ -128,4 +128,4 @@ declare class CronManager {
|
|
|
128
128
|
}
|
|
129
129
|
//#endregion
|
|
130
130
|
export { CronJob as n, RegisteredJob as r, CronManager as t };
|
|
131
|
-
//# sourceMappingURL=cron-manager-
|
|
131
|
+
//# sourceMappingURL=cron-manager-CmTimEjf.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron-manager-CmTimEjf.d.mts","names":[],"sources":["../src/cron/cron-job.ts","../src/cron/cron-manager.ts"],"mappings":";;;;;;;AA6BA;;;;;;;;;;AAOA;;;;;;;;;;;;;;UAPiB,aAAA;EAiChB;EA/BA,QAAA;EA+BS;EA7BT,QAAA,EAAU,WAAA,CAAY,OAAA;AAAA;AAAA,UAGN,OAAA;EA0BgD;;;;;AC5CjE;;ED4CiE,SAlBvD,QAAA;ECR+B;;;;;;EDgBxC,OAAA,CAAQ,UAAA,EAAY,mBAAA,GAAsB,OAAA;EC3BlC;;;;;;;;EDqCR,OAAA,EAAS,KAAA,EAAO,KAAA,EAAO,UAAA,EAAY,mBAAA,GAAsB,OAAA;AAAA;;;;;AAjC1D;;;;;;;;;cCVa,WAAA;EDiBI;;;;;EAAA,QCXR,IAAA;EDqC2B;;;;;;;;;EC1BnC,WAAA,CAAY,QAAA,UAAkB,QAAA,EAAU,aAAA;ED0BxB;;;;;;;;;;AC5CjB;;;;EAsCO,gBAAA,CAAiB,UAAA,EAAY,mBAAA,EAAqB,SAAA,EAAW,SAAA,GAAY,OAAA;EAAZ;;;;;;EA2DnE,kBAAA,CAAmB,QAAA,WAAmB,aAAA;EA/E1B;;;;;EAwFZ,eAAA,CAAA;EApEmE;;;;;EA6EnE,gBAAA,CAAA;AAAA"}
|