@rexezuge/runtime 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,81 @@
1
+ # @rexezuge/runtime
2
+
3
+ DI container, configuration, worker bases, logger, and KV cache for Cloudflare Workers.
4
+
5
+ Zero dependencies (the one platform import is type-only, resolved through each consumer's generated wrangler types).
6
+
7
+ ```bash
8
+ pnpm add @rexezuge/runtime
9
+ ```
10
+
11
+ ---
12
+
13
+ ## 1. DI — `Container` / `Token` / `RequestScope`
14
+
15
+ Minimal by design: factory + singleton scopes, branded tokens for inference, nothing else.
16
+
17
+ ```ts
18
+ import { Container, type Token } from '@rexezuge/runtime';
19
+
20
+ interface Mailer { send(to: string): Promise<void> }
21
+ const MailerToken: Token<Mailer> = 'Mailer';
22
+
23
+ const root = new Container().bindValue(MailerToken, new SmtpMailer());
24
+ const mailer = root.get(MailerToken); // Mailer, no explicit generic needed
25
+ ```
26
+
27
+ Composition roots wire implementations once; request handlers resolve via `asScopedContext` / `getRequestScope` rather than passing a container through business logic.
28
+
29
+ ## 2. Config — `AppConfiguration` / `EnvParser`
30
+
31
+ Consumers subclass `AppConfiguration` and compose their own typed sections (limits, auth, replication), each reading env once through `EnvParser`:
32
+
33
+ ```ts
34
+ import { AppConfiguration, EnvParser } from '@rexezuge/runtime';
35
+
36
+ class MyConfig extends AppConfiguration {
37
+ public getPageSize(): number {
38
+ return EnvParser.number(this.raw(), 'PAGE_SIZE', 50);
39
+ }
40
+ }
41
+
42
+ const config = MyConfig.fromEnv(env);
43
+ for (const warning of config.validate()) console.warn(warning); // warnings, never throws
44
+ ```
45
+
46
+ `getSiteUrl()` strips trailing slashes so callers can concatenate paths. `validate()` returns startup warnings (e.g. `DEMO_MODE` in production) instead of throwing a 500 on a request path.
47
+
48
+ ## 3. Worker bases
49
+
50
+ | Base | Extends for |
51
+ | --- | --- |
52
+ | `AbstractEntrypointWorker` | HTTP + cron entrypoints (`onRequest` / `onScheduled`) |
53
+ | `AbstractDurableObjectWorker` | Durable Object workers |
54
+ | `AbstractQueueWorker` | Queue consumers |
55
+ | `AbstractWorkflowWorker` | Workflows |
56
+
57
+ `fetch()` / `scheduled()` log-and-contain: an unhandled throw is a 500 response or a logged cron failure, never a platform crash. There is deliberately no `/__scheduled` HTTP branch — cron runs through the wrangler `triggers.crons` binding. The structural `WorkerExecutionContext` / `WorkerScheduledController` types mean this package typechecks without `@cloudflare/workers-types`.
58
+
59
+ ## 4. Logger and KV cache
60
+
61
+ ```ts
62
+ import { createLogger, KvCache } from '@rexezuge/runtime';
63
+
64
+ const logger = createLogger('Sync', 'my-repo', env); // level from env.LOG_LEVEL ?? process.env, defaults to info
65
+ logger.info('starting sync');
66
+
67
+ const cache = new KvCache(env.CACHE); // fail-soft: reads null, writes false, D1/DO stay authoritative
68
+ await cache.putText('session', 'sess:abc', 'payload', { ttlSeconds: 300 });
69
+ ```
70
+
71
+ `KV_DOMAINS` / `buildKvKey` / `clampTtl` keep every repo's key shapes and TTL ceilings identical.
72
+
73
+ ---
74
+
75
+ ## Verifying this package
76
+
77
+ ```bash
78
+ pnpm --filter @rexezuge/runtime exec tsc -p tsconfig.json
79
+ pnpm --filter @rexezuge/runtime typecheck
80
+ pnpm --filter @rexezuge/runtime test
81
+ ```
@@ -1 +1 @@
1
- {"version":3,"file":"AbstractDurableObjectWorker.js","sourceRoot":"","sources":["../../src/base/AbstractDurableObjectWorker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;;;;;;;;;;;;GAaG;AACH,MAAe,2BAAwC,SAAQ,aAAmB;IACzE,KAAK,CAAC,KAAK,CAAC,OAAgB;QACjC,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACvC,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,4CAA4C,EAAE,GAAG,CAAC,CAAC;YACjE,OAAO,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;IAED;;;OAGG;IACO,sBAAsB;QAC9B,OAAO;YACL,SAAS,EAAE,CAAC,OAAyB,EAAQ,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC;YAC3E,sBAAsB,EAAE,GAAS,EAAE,CAAC,SAAS;SACf,CAAC;IACnC,CAAC;CAGF;AAED,OAAO,EAAE,2BAA2B,EAAE,CAAC"}
1
+ {"version":3,"file":"AbstractDurableObjectWorker.js","sourceRoot":"","sources":["../../src/base/AbstractDurableObjectWorker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;;;;;;;;;;;;GAaG;AACH,MAAe,2BAAwC,SAAQ,aAAmB;IACzE,KAAK,CAAC,KAAK,CAAC,OAAgB;QACjC,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACvC,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,4CAA4C,EAAE,GAAG,CAAC,CAAC;YACjE,OAAO,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;IAED;;;OAGG;IACO,sBAAsB;QAC9B,OAAO;YACL,SAAS,EAAE,CAAC,OAAyB,EAAQ,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC;YAC3E,sBAAsB,EAAE,GAAS,EAAE,CAAC,SAAS;SACf,CAAC;IACnC,CAAC;CAGF;AAED,OAAO,EAAE,2BAA2B,EAAE,CAAC","sourcesContent":["import { DurableObject } from 'cloudflare:workers';\n\n/**\n * The Durable Object base: one `fetch` entry, error containment inside it.\n *\n * Converged from the `AbstractDurableObjectWorker` copies in AWS-AccessBridge,\n * CalDAV-Bridge, ChordDHT-Tracker, Edge-Git, Mail-Meow and Mail-Otter (the\n * union is exactly Mail-Meow's shape: the fetch wrapper plus\n * `createExecutionContext` for handlers that need to forward `waitUntil`).\n * Durable-DAV's DO writes more context per handler, but the *base* is the same.\n *\n * A DO has no routing layer, so an unhandled rejection here would surface as a\n * raw 500 with no JSON body and no log. The catch is the boundary: it logs the\n * sanitized error and answers `{ error: 'Internal Error' }` so a caller always\n * gets a parseable response.\n */\nabstract class AbstractDurableObjectWorker<TEnv = Env> extends DurableObject<TEnv> {\n public async fetch(request: Request): Promise<Response> {\n try {\n return await this.onRequest(request);\n } catch (err: unknown) {\n console.error('Unhandled error in durable object fetch():', err);\n return Response.json({ error: 'Internal Error' }, { status: 500 });\n }\n }\n\n /**\n * The platform `ExecutionContext` shape, forwards `waitUntil` into the DO's\n * own `ctx` so a handler can keep a task alive past the response.\n */\n protected createExecutionContext(): ExecutionContext {\n return {\n waitUntil: (promise: Promise<unknown>): void => this.ctx.waitUntil(promise),\n passThroughOnException: (): void => undefined,\n } as unknown as ExecutionContext;\n }\n\n protected abstract onRequest(request: Request): Promise<Response>;\n}\n\nexport { AbstractDurableObjectWorker };\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"AbstractEntrypointWorker.js","sourceRoot":"","sources":["../../src/base/AbstractEntrypointWorker.ts"],"names":[],"mappings":"AAmBA,MAAe,wBAAwB;IACrC;;;;;;;;;;;;;OAaG;IACI,KAAK,CAAC,KAAK,CAAC,OAAgB,EAAE,GAAQ,EAAE,GAA2B;QACxE,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QACjD,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;YAClD,OAAO,IAAI,QAAQ,CAAC,gBAAgB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QACzD,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,SAAS,CAAC,KAAgC,EAAE,GAAQ,EAAE,GAA2B;QAC5F,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,iCAAiC,EAAE,GAAG,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;CAKF;AAED,OAAO,EAAE,wBAAwB,EAAE,CAAC"}
1
+ {"version":3,"file":"AbstractEntrypointWorker.js","sourceRoot":"","sources":["../../src/base/AbstractEntrypointWorker.ts"],"names":[],"mappings":"AAmBA,MAAe,wBAAwB;IACrC;;;;;;;;;;;;;OAaG;IACI,KAAK,CAAC,KAAK,CAAC,OAAgB,EAAE,GAAQ,EAAE,GAA2B;QACxE,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QACjD,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;YAClD,OAAO,IAAI,QAAQ,CAAC,gBAAgB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QACzD,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,SAAS,CAAC,KAAgC,EAAE,GAAQ,EAAE,GAA2B;QAC5F,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,iCAAiC,EAAE,GAAG,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;CAKF;AAED,OAAO,EAAE,wBAAwB,EAAE,CAAC","sourcesContent":["/**\n * Minimal Workers-compatible context types so backend-runtime typechecks\n * without @cloudflare/workers-types. Apps pass the real ExecutionContext /\n * ScheduledController which satisfy these structurally.\n *\n * Converged verbatim from `backend-runtime/src/base/AbstractEntrypointWorker.ts`\n * (identical in all nine repos).\n */\ninterface WorkerExecutionContext {\n waitUntil(promise: Promise<unknown>): void;\n passThroughOnException(): void;\n}\n\ninterface WorkerScheduledController {\n cron: string;\n scheduledTime: number;\n noRetry(): void;\n}\n\nabstract class AbstractEntrypointWorker {\n /**\n * The HTTP request path.\n *\n * There is deliberately no `/__scheduled` branch here. It used to run before\n * `onRequest`, which made `GET /__scheduled` an unauthenticated, un-rated\n * trigger for the scheduled work: it bypassed the app's security headers, its\n * request scope, and its rate limits, and any caller could fire the cron\n * Durable Object on demand. `noRetry` was a `(): void => undefined` stub, so\n * the retry semantics were lost too.\n *\n * Nothing needed it — `scheduled()` is wired through the platform by the\n * `triggers.crons` entry in the wrangler config, which is how the cron\n * actually runs.\n */\n public async fetch(request: Request, env: Env, ctx: WorkerExecutionContext): Promise<Response> {\n try {\n return await this.onRequest(request, env, ctx);\n } catch (err: unknown) {\n console.error('Unhandled error in fetch():', err);\n return new Response('Internal Error', { status: 500 });\n }\n }\n\n public async scheduled(event: WorkerScheduledController, env: Env, ctx: WorkerExecutionContext): Promise<void> {\n try {\n await this.onScheduled(event, env, ctx);\n } catch (err: unknown) {\n console.error('Unhandled error in scheduled():', err);\n }\n }\n\n protected abstract onRequest(request: Request, env: Env, ctx: WorkerExecutionContext): Promise<Response>;\n\n protected abstract onScheduled(event: WorkerScheduledController, env: Env, ctx: WorkerExecutionContext): Promise<void>;\n}\n\nexport { AbstractEntrypointWorker };\nexport type { WorkerExecutionContext, WorkerScheduledController };\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"AbstractQueueWorker.js","sourceRoot":"","sources":["../../src/base/AbstractQueueWorker.ts"],"names":[],"mappings":"AAeA,MAAe,mBAAmB;IACzB,KAAK,CAAC,KAAK,CAAC,KAA4B,EAAE,GAAQ,EAAE,GAA2B;QACpF,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;YAClD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;CAGF;AAED,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
1
+ {"version":3,"file":"AbstractQueueWorker.js","sourceRoot":"","sources":["../../src/base/AbstractQueueWorker.ts"],"names":[],"mappings":"AAeA,MAAe,mBAAmB;IACzB,KAAK,CAAC,KAAK,CAAC,KAA4B,EAAE,GAAQ,EAAE,GAA2B;QACpF,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;YAClD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;CAGF;AAED,OAAO,EAAE,mBAAmB,EAAE,CAAC","sourcesContent":["import type { WorkerExecutionContext } from './AbstractEntrypointWorker';\n\n/**\n * The queue consumer base, converged verbatim from `AbstractQueueWorker.ts`\n * (identical in Edge-Git and Mail-Otter; the only two repos with queue\n * consumers).\n *\n * It rethrows after logging: a queue message that failed must be *retried* by\n * the platform, and a base that swallowed the rejection would turn a transient\n * handler failure into an acked, dropped message.\n */\ninterface WorkerMessageBatch<T = unknown> {\n messages: T[];\n}\n\nabstract class AbstractQueueWorker<T = unknown> {\n public async queue(batch: WorkerMessageBatch<T>, env: Env, ctx: WorkerExecutionContext): Promise<void> {\n try {\n await this.onQueue(batch, env, ctx);\n } catch (err: unknown) {\n console.error('Unhandled error in queue():', err);\n throw err;\n }\n }\n\n protected abstract onQueue(batch: WorkerMessageBatch<T>, env: Env, ctx: WorkerExecutionContext): Promise<void>;\n}\n\nexport { AbstractQueueWorker };\nexport type { WorkerMessageBatch };\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"AbstractWorkflowWorker.js","sourceRoot":"","sources":["../../src/base/AbstractWorkflowWorker.ts"],"names":[],"mappings":"AAiBA,MAAe,sBAAsB;IAC5B,KAAK,CAAC,GAAG,CAAC,KAA4C,EAAE,IAAsB;QACnF,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC5C,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,GAAG,CAAC,CAAC;YACzD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;CAGF;AAED,OAAO,EAAE,sBAAsB,EAAE,CAAC"}
1
+ {"version":3,"file":"AbstractWorkflowWorker.js","sourceRoot":"","sources":["../../src/base/AbstractWorkflowWorker.ts"],"names":[],"mappings":"AAiBA,MAAe,sBAAsB;IAC5B,KAAK,CAAC,GAAG,CAAC,KAA4C,EAAE,IAAsB;QACnF,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC5C,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,GAAG,CAAC,CAAC;YACzD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;CAGF;AAED,OAAO,EAAE,sBAAsB,EAAE,CAAC","sourcesContent":["/**\n * The Workflow base, converged verbatim from `AbstractWorkflowWorker.ts`\n * (identical in Edge-Git and Mail-Otter; Edge-Sonic ships the same shape as\n * `runWorkflow.ts` with a `WorkflowEntrypoint` wrapper around it).\n *\n * `WorkflowStepLike` is the minimal `step.do` surface: a workflow whose steps\n * are not retried by the platform is just a coroutine, and the wrapper exists\n * to keep the retry semantics visible in one place.\n */\ninterface WorkflowEventLike<T = unknown> {\n payload: T;\n}\n\ninterface WorkflowStepLike {\n do<T>(name: string, callback: () => Promise<T>): Promise<T>;\n}\n\nabstract class AbstractWorkflowWorker<TPayload = unknown, TResult = unknown> {\n public async run(event: Readonly<WorkflowEventLike<TPayload>>, step: WorkflowStepLike): Promise<TResult> {\n try {\n return await this.onWorkflow(event, step);\n } catch (err: unknown) {\n console.error('Unhandled error in workflow run():', err);\n throw err;\n }\n }\n\n protected abstract onWorkflow(event: Readonly<WorkflowEventLike<TPayload>>, step: WorkflowStepLike): Promise<TResult>;\n}\n\nexport { AbstractWorkflowWorker };\nexport type { WorkflowEventLike, WorkflowStepLike };\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/base/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAEtE,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/base/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAEtE,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC","sourcesContent":["export { AbstractEntrypointWorker } from './AbstractEntrypointWorker';\nexport type { WorkerExecutionContext, WorkerScheduledController } from './AbstractEntrypointWorker';\nexport { AbstractDurableObjectWorker } from './AbstractDurableObjectWorker';\nexport { AbstractQueueWorker } from './AbstractQueueWorker';\nexport type { WorkerMessageBatch } from './AbstractQueueWorker';\nexport { AbstractWorkflowWorker } from './AbstractWorkflowWorker';\nexport type { WorkflowEventLike, WorkflowStepLike } from './AbstractWorkflowWorker';\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"AppConfiguration.js","sourceRoot":"","sources":["../../src/config/AppConfiguration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D;;;;;;;;;;;;;GAaG;AACH,MAAe,gBAAgB;IACY;IAAzC,YAAyC,GAAY;QAAZ,QAAG,GAAH,GAAG,CAAS;IAAG,CAAC;IAElD,MAAM,CAAC,OAAO,CAA4D,GAAY;QAC3F,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IAED;;;OAGG;IACI,UAAU;QACf,IAAI,GAAG,GAAG,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,gBAAgB,CAAC,CAAC;QACnE,OAAO,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACjD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,kEAAkE;IAC3D,cAAc;QACnB,OAAO,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC;IAClE,CAAC;IAED;;;;OAIG;IACI,QAAQ;QACb,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;QAC1C,IAAI,WAAW,KAAK,YAAY,EAAE,CAAC;YACjC,IAAI,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,CAAC;gBACtD,QAAQ,CAAC,IAAI,CAAC,gFAAgF,CAAC,CAAC;YAClG,CAAC;YACD,IAAI,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,KAAK,SAAS,EAAE,CAAC;gBACnE,QAAQ,CAAC,IAAI,CAAC,0EAA0E,CAAC,CAAC;YAC5F,CAAC;QACH,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,2EAA2E;IACjE,GAAG;QACX,OAAO,IAAI,CAAC,GAAG,CAAC;IAClB,CAAC;CACF;AAED,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"AppConfiguration.js","sourceRoot":"","sources":["../../src/config/AppConfiguration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D;;;;;;;;;;;;;GAaG;AACH,MAAe,gBAAgB;IACY;IAAzC,YAAyC,GAAY;QAAZ,QAAG,GAAH,GAAG,CAAS;IAAG,CAAC;IAElD,MAAM,CAAC,OAAO,CAA4D,GAAY;QAC3F,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IAED;;;OAGG;IACI,UAAU;QACf,IAAI,GAAG,GAAG,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,gBAAgB,CAAC,CAAC;QACnE,OAAO,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACjD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,kEAAkE;IAC3D,cAAc;QACnB,OAAO,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC;IAClE,CAAC;IAED;;;;OAIG;IACI,QAAQ;QACb,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;QAC1C,IAAI,WAAW,KAAK,YAAY,EAAE,CAAC;YACjC,IAAI,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,CAAC;gBACtD,QAAQ,CAAC,IAAI,CAAC,gFAAgF,CAAC,CAAC;YAClG,CAAC;YACD,IAAI,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,KAAK,SAAS,EAAE,CAAC;gBACnE,QAAQ,CAAC,IAAI,CAAC,0EAA0E,CAAC,CAAC;YAC5F,CAAC;QACH,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,2EAA2E;IACjE,GAAG;QACX,OAAO,IAAI,CAAC,GAAG,CAAC;IAClB,CAAC;CACF;AAED,OAAO,EAAE,gBAAgB,EAAE,CAAC","sourcesContent":["import { EnvParser } from './EnvParser';\nimport { DEFAULT_SITE_URL } from './ConfigurationDefaults';\n\n/**\n * The base class every consumer's `AppConfiguration` extends.\n *\n * Converged from the six `config/AppConfiguration.ts` files and Mail-Meow's\n * `config/AppConfig.ts` (the same class under a different name — consumers\n * adapt to this one). The family's design — a thin facade over typed section\n * objects, each owning one group of getters — is kept, minus the sections,\n * which are per-project by nature: a consumer subclasses this and composes its\n * own sections (limits, auth, replication …), each of which reads the env once\n * through `EnvParser`.\n *\n * `validate()` returns warnings rather than throwing: a config typo must be a\n * startup log line, not a 500 on a request path.\n */\nabstract class AppConfiguration {\n protected constructor(protected readonly env: unknown) {}\n\n public static fromEnv<T extends AppConfiguration>(this: new (env: unknown) => T, env: unknown): T {\n return new this(env);\n }\n\n /**\n * The public origin, trailing slashes stripped. Callers concatenate paths\n * onto it, so a trailing `/` would double them in every generated link.\n */\n public getSiteUrl(): string {\n let url = EnvParser.string(this.env, 'SITE_URL', DEFAULT_SITE_URL);\n while (url.endsWith('/')) url = url.slice(0, -1);\n return url;\n }\n\n /** The deployment stage this configuration believes itself in. */\n public getEnvironment(): string {\n return EnvParser.string(this.env, 'ENVIRONMENT', 'development');\n }\n\n /**\n * Warnings for suspicious settings, logged at startup. The base checks the\n * one the whole family agrees on — a dev bypass left enabled in production;\n * a subclass appends its own.\n */\n public validate(): string[] {\n const warnings: string[] = [];\n const environment = this.getEnvironment();\n if (environment === 'production') {\n if (EnvParser.boolean(this.env, 'DEMO_MODE', 'false')) {\n warnings.push('DEMO_MODE is enabled in production — every request will bypass authentication.');\n }\n if (EnvParser.readString(this.env, 'DEV_AUTH_EMAIL') !== undefined) {\n warnings.push('DEV_AUTH_EMAIL is set in production — a fixed identity can authenticate.');\n }\n }\n return warnings;\n }\n\n /** The raw env, for subclasses that need a key this base does not know. */\n protected raw(): unknown {\n return this.env;\n }\n}\n\nexport { AppConfiguration };\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ConfigurationDefaults.js","sourceRoot":"","sources":["../../src/config/ConfigurationDefaults.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,8FAA8F;AAC9F,MAAM,gBAAgB,GAAG,uBAAuB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"ConfigurationDefaults.js","sourceRoot":"","sources":["../../src/config/ConfigurationDefaults.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,8FAA8F;AAC9F,MAAM,gBAAgB,GAAG,uBAAuB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,CAAC","sourcesContent":["/**\n * Defaults shared by the family's configuration layers.\n *\n * Converged from `backend-runtime/src/config/ConfigurationDefaults.ts` (five\n * repos) and the `ConfigurationManager` default table in the other four. Only\n * the values every repo agrees on live here; a project-specific default belongs\n * in that project's config section.\n */\n\n/** Used when `SITE_URL` is unset — the value that renders correct absolute links in tests. */\nconst DEFAULT_SITE_URL = 'http://localhost:8787';\n\nexport { DEFAULT_SITE_URL };\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"EnvParser.js","sourceRoot":"","sources":["../../src/config/EnvParser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,SAAS;IACN,MAAM,CAAC,WAAW,CAAC,GAAY,EAAE,GAAW,EAAE,YAAoB;QACvE,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,IAAI,YAAY,CAAC,CAAC;QAC7C,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IACpF,CAAC;IAED;;;;;;;OAOG;IACI,MAAM,CAAC,kBAAkB,CAAC,GAAY,EAAE,GAAW;QACxD,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACxC,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC;QACrC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC7B,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC;IACpD,CAAC;IAEM,MAAM,CAAC,MAAM,CAAC,GAAY,EAAE,GAAW,EAAE,YAAoB;QAClE,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,YAAY,CAAC;IACnD,CAAC;IAED;;;;;;;OAOG;IACI,MAAM,CAAC,cAAc,CAAC,GAAY,EAAE,GAAW,EAAE,YAAoB;QAC1E,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,IAAI,YAAY,CAAC,CAAC;QAC7C,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IACrF,CAAC;IAEM,MAAM,CAAC,OAAO,CAAC,GAAY,EAAE,GAAW,EAAE,YAAoB;QACnE,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,YAAY,CAAC,KAAK,MAAM,CAAC;IAChE,CAAC;IAED,iGAAiG;IAC1F,MAAM,CAAC,UAAU,CAAC,GAAY,EAAE,GAAW;QAChD,OAAQ,GAA0C,CAAC,GAAG,CAAC,CAAC;IAC1D,CAAC;CACF;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"EnvParser.js","sourceRoot":"","sources":["../../src/config/EnvParser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,SAAS;IACN,MAAM,CAAC,WAAW,CAAC,GAAY,EAAE,GAAW,EAAE,YAAoB;QACvE,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,IAAI,YAAY,CAAC,CAAC;QAC7C,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IACpF,CAAC;IAED;;;;;;;OAOG;IACI,MAAM,CAAC,kBAAkB,CAAC,GAAY,EAAE,GAAW;QACxD,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACxC,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC;QACrC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC7B,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC;IACpD,CAAC;IAEM,MAAM,CAAC,MAAM,CAAC,GAAY,EAAE,GAAW,EAAE,YAAoB;QAClE,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,YAAY,CAAC;IACnD,CAAC;IAED;;;;;;;OAOG;IACI,MAAM,CAAC,cAAc,CAAC,GAAY,EAAE,GAAW,EAAE,YAAoB;QAC1E,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,IAAI,YAAY,CAAC,CAAC;QAC7C,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IACrF,CAAC;IAEM,MAAM,CAAC,OAAO,CAAC,GAAY,EAAE,GAAW,EAAE,YAAoB;QACnE,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,YAAY,CAAC,KAAK,MAAM,CAAC;IAChE,CAAC;IAED,iGAAiG;IAC1F,MAAM,CAAC,UAAU,CAAC,GAAY,EAAE,GAAW;QAChD,OAAQ,GAA0C,CAAC,GAAG,CAAC,CAAC;IAC1D,CAAC;CACF;AAED,OAAO,EAAE,SAAS,EAAE,CAAC","sourcesContent":["/**\n * Typed readers for a Worker `env` binding.\n *\n * Converged from `backend-runtime/src/config/EnvParser.ts` — effectively\n * identical in all six repos that have the file (Mail-Meow/CalDAV-Bridge call\n * their copy `ConfigurationManager` with the same three readers).\n *\n * The var table is `Record<string, string | undefined>` by contract: Cloudflare\n * passes every binding as a string, so a reader that returned `number` for\n * `MAX_*` would be inventing a parse that never happened. `boolean` is\n * presence-of-\"true\", and anything else is `false` — never \"absent means true\".\n */\nclass EnvParser {\n public static positiveInt(env: unknown, key: string, defaultValue: string): number {\n const value = this.readString(env, key);\n const parsed = Number(value ?? defaultValue);\n return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : Number(defaultValue);\n }\n\n /**\n * Whether an explicitly-set numeric var is a usable positive integer.\n *\n * Used by `AppConfiguration.validate()` to *report* misconfiguration at\n * startup while still running with the default. The throwing counterpart\n * (`strictPositiveInt`) is gone: no caller opted in, and a fail-fast parse on\n * a request path would turn a config typo into a 500 rather than a warning.\n */\n public static isValidPositiveInt(env: unknown, key: string): boolean {\n const value = this.readString(env, key);\n if (value === undefined) return true;\n const parsed = Number(value);\n return Number.isSafeInteger(parsed) && parsed > 0;\n }\n\n public static string(env: unknown, key: string, defaultValue: string): string {\n return this.readString(env, key) ?? defaultValue;\n }\n\n /**\n * A non-negative integer, zero included.\n *\n * Distinct from `positiveInt` because zero is a meaningful configuration for\n * retention and quota knobs (\"keep nothing\"), and a parser that rejected it\n * would silently substitute the default — so setting `0` in the dashboard\n * would appear to do nothing at all.\n */\n public static nonNegativeInt(env: unknown, key: string, defaultValue: string): number {\n const value = this.readString(env, key);\n const parsed = Number(value ?? defaultValue);\n return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : Number(defaultValue);\n }\n\n public static boolean(env: unknown, key: string, defaultValue: string): boolean {\n return (this.readString(env, key) ?? defaultValue) === 'true';\n }\n\n /** The raw value, or undefined when unset. Public because presence checks (validate) need it. */\n public static readString(env: unknown, key: string): string | undefined {\n return (env as Record<string, string | undefined>)[key];\n }\n}\n\nexport { EnvParser };\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC","sourcesContent":["export { AppConfiguration } from './AppConfiguration';\nexport { EnvParser } from './EnvParser';\nexport { DEFAULT_SITE_URL } from './ConfigurationDefaults';\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"Container.js","sourceRoot":"","sources":["../../src/di/Container.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAWH;;;;;GAKG;AACH,MAAM,SAAS;IACI,SAAS,GAAG,IAAI,GAAG,EAAoC,CAAC;IAExD,UAAU,GAAG,IAAI,GAAG,EAA2B,CAAC;IAE1D,IAAI,CAAI,KAAe,EAAE,OAAmB;QACjD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;IAEM,SAAS,CAAI,KAAe,EAAE,KAAQ;QAC3C,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACI,GAAG,CAAI,KAAe;QAC3B,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACjE,CAAC;IAEM,GAAG,CAAI,KAAe;QAC3B,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAM,CAAC;QACzC,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,0CAA0C,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC7E,CAAC;QACD,MAAM,QAAQ,GAAI,OAAsB,CAAC,IAAI,CAAC,CAAC;QAC/C,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACrC,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"Container.js","sourceRoot":"","sources":["../../src/di/Container.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAWH;;;;;GAKG;AACH,MAAM,SAAS;IACI,SAAS,GAAG,IAAI,GAAG,EAAoC,CAAC;IAExD,UAAU,GAAG,IAAI,GAAG,EAA2B,CAAC;IAE1D,IAAI,CAAI,KAAe,EAAE,OAAmB;QACjD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;IAEM,SAAS,CAAI,KAAe,EAAE,KAAQ;QAC3C,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACI,GAAG,CAAI,KAAe;QAC3B,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACjE,CAAC;IAEM,GAAG,CAAI,KAAe;QAC3B,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAM,CAAC;QACzC,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,0CAA0C,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC7E,CAAC;QACD,MAAM,QAAQ,GAAI,OAAsB,CAAC,IAAI,CAAC,CAAC;QAC/C,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACrC,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF;AAED,OAAO,EAAE,SAAS,EAAE,CAAC","sourcesContent":["/**\n * The dependency-injection container.\n *\n * Converged verbatim from `backend-runtime/src/di/Container.ts` — the file is\n * byte-identical (modulo scope) across all nine full-framework consumer repos,\n * because the last divergence in it was fixed in all of them at once.\n *\n * Minimal by design: factory + singleton scopes, branded tokens for inference,\n * nothing else. A DI container that grows features grows coupling with it.\n */\n\ntype Factory<T> = (container: Container) => T;\n\n/**\n * Branded token so `scope.get(Tokens.X)` infers `X` without an explicit generic\n * at call sites. The brand is optional (and `unknown`-compatible) so\n * `Token<Service>` remains assignable to `Token<unknown>` for Map storage.\n */\ntype Token<T = unknown> = (string | symbol) & { readonly __type?: T };\n\n/**\n * Composition roots (a request scope, a cron entrypoint, tests) wire concrete\n * implementations once; handlers resolve via `scope.get(Tokens.X)`. Prefer\n * constructor injection of ports at registration time over inline\n * `scope.get()` in business logic.\n */\nclass Container {\n private readonly factories = new Map<Token<unknown>, Factory<unknown>>();\n\n private readonly singletons = new Map<Token<unknown>, unknown>();\n\n public bind<T>(token: Token<T>, factory: Factory<T>): this {\n this.factories.set(token, factory);\n return this;\n }\n\n public bindValue<T>(token: Token<T>, value: T): this {\n this.singletons.set(token, value);\n return this;\n }\n\n /**\n * Is a token bound (as a value or a factory)? Used to assert wiring.\n */\n public has<T>(token: Token<T>): boolean {\n return this.singletons.has(token) || this.factories.has(token);\n }\n\n public get<T>(token: Token<T>): T {\n if (this.singletons.has(token)) {\n return this.singletons.get(token) as T;\n }\n const factory = this.factories.get(token);\n if (!factory) {\n throw new Error(`DI container has no binding for token: ${String(token)}`);\n }\n const instance = (factory as Factory<T>)(this);\n this.singletons.set(token, instance);\n return instance;\n }\n}\n\nexport { Container };\nexport type { Factory, Token };\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"RequestScope.js","sourceRoot":"","sources":["../../src/di/RequestScope.ts"],"names":[],"mappings":"AAiBA,MAAM,SAAS,GAAG,YAAY,CAAC;AAE/B,SAAS,eAAe,CAAC,CAAgB,EAAE,KAAgB;IACzD,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;;GAMG;AACH,SAAS,eAAe,CAAC,CAIxB;IACC,OAAO,CAA6B,CAAC;AACvC,CAAC;AAED,SAAS,eAAe,CAAC,CAAgB;IACvC,MAAM,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAA0B,CAAC;IACxD,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAC;IACtG,OAAO,KAAK,CAAC;AACf,CAAC;AAED,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"RequestScope.js","sourceRoot":"","sources":["../../src/di/RequestScope.ts"],"names":[],"mappings":"AAiBA,MAAM,SAAS,GAAG,YAAY,CAAC;AAE/B,SAAS,eAAe,CAAC,CAAgB,EAAE,KAAgB;IACzD,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;;GAMG;AACH,SAAS,eAAe,CAAC,CAIxB;IACC,OAAO,CAA6B,CAAC;AACvC,CAAC;AAED,SAAS,eAAe,CAAC,CAAgB;IACvC,MAAM,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAA0B,CAAC;IACxD,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAC;IACtG,OAAO,KAAK,CAAC;AACf,CAAC;AAED,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,CAAC","sourcesContent":["import type { Container } from './Container';\n\n/**\n * Single-scope-per-request helper.\n *\n * Converged verbatim from `backend-runtime/src/di/RequestScope.ts` (identical in\n * all nine repos). Middleware creates one `Container` per request and stores it\n * on the request context; handlers resolve via `getRequestScope(c)` instead of\n * building a scope per handler — which minted N scopes per request and broke\n * singleton memoization.\n */\ninterface ScopedContext {\n get(key: string): unknown;\n set(key: string, value: unknown): void;\n readonly env: unknown;\n}\n\nconst SCOPE_KEY = '__kitScope';\n\nfunction setRequestScope(c: ScopedContext, scope: Container): void {\n c.set(SCOPE_KEY, scope);\n}\n\n/**\n * Structural adapter for framework contexts.\n *\n * Hono's `Context.get` overloads are not assignable to `ScopedContext['get']`,\n * so call sites used `c as never`. Centralize that single unsafe cast here —\n * one audited location instead of many scattered ones.\n */\nfunction asScopedContext(c: {\n get(key: string): unknown;\n set?(key: string, value: unknown): void;\n readonly env: unknown;\n}): ScopedContext {\n return c as unknown as ScopedContext;\n}\n\nfunction getRequestScope(c: ScopedContext): Container {\n const scope = c.get(SCOPE_KEY) as Container | undefined;\n if (!scope) throw new Error('Request scope is not set. Register the scope middleware before routes.');\n return scope;\n}\n\nexport { setRequestScope, getRequestScope, asScopedContext };\nexport type { ScopedContext };\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/di/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/di/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC","sourcesContent":["export { Container } from './Container';\nexport type { Factory, Token } from './Container';\nexport { asScopedContext, getRequestScope, setRequestScope } from './RequestScope';\nexport type { ScopedContext } from './RequestScope';\n"]}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEtF,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAE3E,OAAO,EAAE,2BAA2B,EAAE,MAAM,oCAAoC,CAAC;AACjF,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAEvE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAErE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEtF,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAE3E,OAAO,EAAE,2BAA2B,EAAE,MAAM,oCAAoC,CAAC;AACjF,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAEvE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAErE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC","sourcesContent":["/**\n * `@rexezuge/runtime` — the platform foundation layer: DI, configuration,\n * worker bases, logger, KV cache. Zero dependencies (the one platform import\n * is type-only, resolved through each consumer's generated wrangler types).\n */\n\nexport { Container } from './di/Container';\nexport type { Factory, Token } from './di/Container';\nexport { asScopedContext, getRequestScope, setRequestScope } from './di/RequestScope';\nexport type { ScopedContext } from './di/RequestScope';\nexport { AppConfiguration } from './config/AppConfiguration';\nexport { EnvParser } from './config/EnvParser';\nexport { DEFAULT_SITE_URL } from './config/ConfigurationDefaults';\nexport { AbstractEntrypointWorker } from './base/AbstractEntrypointWorker';\nexport type { WorkerExecutionContext, WorkerScheduledController } from './base/AbstractEntrypointWorker';\nexport { AbstractDurableObjectWorker } from './base/AbstractDurableObjectWorker';\nexport { AbstractQueueWorker } from './base/AbstractQueueWorker';\nexport type { WorkerMessageBatch } from './base/AbstractQueueWorker';\nexport { AbstractWorkflowWorker } from './base/AbstractWorkflowWorker';\nexport type { WorkflowEventLike, WorkflowStepLike } from './base/AbstractWorkflowWorker';\nexport { createLogger, isLogLevel, resolveLogLevel } from './logger';\nexport type { LogLevel, Logger } from './logger';\nexport { KvCache, KV_DOMAINS, buildKvKey, clampTtl, digest128 } from './kv';\nexport type { KvDomainDef, KvDomainName, KvNamespaceLike } from './kv';\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"KvCache.js","sourceRoot":"","sources":["../../src/kv/KvCache.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"KvCache.js","sourceRoot":"","sources":["../../src/kv/KvCache.ts"],"names":[],"mappings":"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","sourcesContent":["import { createLogger } from '../logger';\nimport { KV_DOMAINS, buildKvKey, clampTtl, utf8ByteLength } from './KvDomains';\nimport type { KvDomainName } from './KvDomains';\n\n/**\n * `KvCache` — typed facade over the single `CACHE` KV binding.\n *\n * Converged from `backend-runtime/src/kv/KvCache.ts`, identical in the four\n * repos that cache through KV. Semantics are fail-soft by design: reads return\n * `null` on miss, missing binding, or backend error; writes return `false`\n * when skipped (no binding, oversize value, backend error) and `true` when\n * stored. Callers treat KV as a pure optimization — D1/DO stay authoritative.\n */\n\nconst logger = createLogger('KvCache');\n\ninterface KvListPage {\n keys: Array<{ name: string }>;\n list_complete: boolean;\n cursor?: string;\n}\n\ninterface KvGetWithMetadataResult {\n value: string | ArrayBuffer | null;\n metadata: unknown;\n}\n\ninterface KvNamespaceLike {\n get(key: string): Promise<string | null>;\n get(key: string, type: 'text'): Promise<string | null>;\n get(key: string, type: 'arrayBuffer'): Promise<ArrayBuffer | null>;\n getWithMetadata?(key: string, type: 'arrayBuffer'): Promise<KvGetWithMetadataResult>;\n put(key: string, value: string | ArrayBuffer, options?: { expirationTtl?: number; metadata?: unknown }): Promise<void>;\n delete(key: string): Promise<unknown>;\n list(options: { prefix: string; limit?: number; cursor?: string }): Promise<KvListPage>;\n}\n\ninterface KvPutOptions {\n ttlSeconds?: number;\n}\n\ninterface KvFileMetadata {\n etag: string;\n contentType: string | null;\n}\n\ninterface KvBinaryEntry {\n bytes: Uint8Array;\n metadata: KvFileMetadata;\n}\n\nconst PURGE_LIST_LIMIT = 1000;\nconst PURGE_MAX_PAGES = 10;\n\nclass KvCache {\n public constructor(private readonly namespace?: KvNamespaceLike | null) {}\n\n public get available(): boolean {\n return !!this.namespace;\n }\n\n public async getText(domain: KvDomainName, parts: readonly string[]): Promise<string | null> {\n const ns = this.namespace;\n if (!ns) return null;\n try {\n return await ns.get(buildKvKey(domain, parts));\n } catch (error) {\n logger.debug(`KV get failed for ${domain}: ${error instanceof Error ? error.message : String(error)}`);\n return null;\n }\n }\n\n public async putText(domain: KvDomainName, parts: readonly string[], value: string, options?: KvPutOptions): Promise<boolean> {\n const ns = this.namespace;\n if (!ns) return false;\n // No unknown-domain check: `buildKvKey` below throws for one, and the\n // return type has never been able to express that. A silent `false` here\n // would have made an unknown domain look like a namespace miss.\n const def = KV_DOMAINS[domain];\n if (utf8ByteLength(value) > def.maxValueBytes) {\n logger.debug(`KV put skipped for ${domain}: value exceeds ${def.maxValueBytes} bytes.`);\n return false;\n }\n try {\n const ttl = clampTtl(options?.ttlSeconds, domain);\n await ns.put(buildKvKey(domain, parts), value, { expirationTtl: ttl });\n return true;\n } catch (error) {\n logger.debug(`KV put failed for ${domain}: ${error instanceof Error ? error.message : String(error)}`);\n return false;\n }\n }\n\n public async getJson<T>(domain: KvDomainName, parts: readonly string[]): Promise<T | null> {\n const raw = await this.getText(domain, parts);\n if (raw === null) return null;\n try {\n return JSON.parse(raw) as T;\n } catch {\n return null;\n }\n }\n\n public async putJson(domain: KvDomainName, parts: readonly string[], value: unknown, options?: KvPutOptions): Promise<boolean> {\n let raw: unknown;\n try {\n raw = JSON.stringify(value);\n } catch {\n return false;\n }\n return typeof raw === 'string' && this.putText(domain, parts, raw, options);\n }\n\n /**\n * Binary read for the `asset` domain: value bytes plus `{etag, contentType}`\n * KV metadata in a single entry. Legacy base64-JSON entries carry no metadata\n * and read as a miss here — the caller falls back to `getJson` for one TTL\n * window rather than this layer knowing the legacy shape.\n */\n public async getBinary(domain: KvDomainName, parts: readonly string[]): Promise<KvBinaryEntry | null> {\n const ns = this.namespace;\n if (!ns || typeof ns.getWithMetadata !== 'function') return null;\n try {\n const res = await ns.getWithMetadata(buildKvKey(domain, parts), 'arrayBuffer');\n if (!res || res.value == null) return null;\n const value: unknown = res.value;\n let bytes: Uint8Array | null = null;\n if (value instanceof ArrayBuffer) {\n bytes = new Uint8Array(value.slice(0));\n } else if (value instanceof Uint8Array) {\n bytes = value.slice();\n } else if (typeof value === 'string') {\n bytes = new TextEncoder().encode(value);\n }\n if (!bytes) return null;\n const meta = res.metadata as { etag?: unknown; contentType?: unknown } | null | undefined;\n if (typeof meta !== 'object' || meta === null || typeof meta.etag !== 'string' || meta.etag === '') return null;\n return { bytes, metadata: { etag: meta.etag, contentType: typeof meta.contentType === 'string' ? meta.contentType : null } };\n } catch (error) {\n logger.debug(`KV getBinary failed for ${domain}: ${error instanceof Error ? error.message : String(error)}`);\n return null;\n }\n }\n\n /**\n * Binary write for the `asset` domain. Size is enforced on raw bytes (no\n * base64 inflation) and failures stay fail-soft like `putText`.\n */\n public async putBinary(\n domain: KvDomainName,\n parts: readonly string[],\n bytes: Uint8Array,\n metadata: { etag: string; contentType: string | null },\n options?: KvPutOptions,\n ): Promise<boolean> {\n const ns = this.namespace;\n if (!ns) return false;\n if (!(bytes instanceof Uint8Array)) {\n logger.debug(`KV putBinary skipped for ${domain}: value is not bytes.`);\n return false;\n }\n const def = KV_DOMAINS[domain];\n if (bytes.byteLength > def.maxValueBytes) {\n logger.debug(`KV putBinary skipped for ${domain}: value exceeds ${def.maxValueBytes} bytes.`);\n return false;\n }\n if (typeof metadata?.etag !== 'string' || metadata.etag === '') {\n logger.debug(`KV putBinary skipped for ${domain}: missing etag metadata.`);\n return false;\n }\n try {\n const ttl = clampTtl(options?.ttlSeconds, domain);\n const contentType = typeof metadata.contentType === 'string' ? metadata.contentType : null;\n await ns.put(buildKvKey(domain, parts), bytes.slice().buffer, {\n expirationTtl: ttl,\n metadata: { etag: metadata.etag, contentType },\n });\n return true;\n } catch (error) {\n logger.debug(`KV putBinary failed for ${domain}: ${error instanceof Error ? error.message : String(error)}`);\n return false;\n }\n }\n\n public async del(domain: KvDomainName, parts: readonly string[]): Promise<void> {\n const ns = this.namespace;\n if (!ns) return;\n try {\n await ns.delete(buildKvKey(domain, parts));\n } catch (error) {\n logger.debug(`KV delete failed for ${domain}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n /**\n * Delete every key under a prefix, page-capped. Restarts from the start after\n * each page: deleting while a positional cursor advances would skip keys.\n */\n public async purgePrefix(domain: KvDomainName, parts: readonly string[] = []): Promise<number> {\n const ns = this.namespace;\n if (!ns) return 0;\n const prefix = parts.length === 0 ? `${domain}:` : buildKvKey(domain, parts);\n let deleted = 0;\n try {\n for (let page = 0; page < PURGE_MAX_PAGES; page += 1) {\n const result = await ns.list({ prefix, limit: PURGE_LIST_LIMIT });\n if (result.keys.length === 0) return deleted;\n for (const key of result.keys) {\n await ns.delete(key.name);\n deleted += 1;\n }\n if (result.keys.length < PURGE_LIST_LIMIT) return deleted;\n }\n // The cap was hit with a full page still coming back, so keys remain and\n // the caller sees a count indistinguishable from a complete purge. A\n // write-invalidation that silently under-purges serves pre-write bytes\n // for a whole TTL while reporting success, so this is never silent.\n logger.warn(\n `KV purge for ${domain} hit the ${PURGE_MAX_PAGES * PURGE_LIST_LIMIT}-key page cap; ` +\n `at least one key may survive invalidation`,\n );\n return deleted;\n } catch (error) {\n logger.warn(`KV purge for ${domain} failed: ${error instanceof Error ? error.message : String(error)}`);\n return deleted;\n }\n }\n}\n\nexport { KvCache, PURGE_LIST_LIMIT, PURGE_MAX_PAGES };\nexport type { KvBinaryEntry, KvFileMetadata, KvNamespaceLike, KvPutOptions };\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"KvDomains.js","sourceRoot":"","sources":["../../src/kv/KvDomains.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"KvDomains.js","sourceRoot":"","sources":["../../src/kv/KvDomains.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Single-KV keyspace: one `CACHE` binding, domains separated by key prefix.\n *\n * Converged from `backend-runtime/src/kv/KvDomains.ts` (Durable-DAV,\n * Durable-DAV-Router, Edge-Sonic, Mail-Otter — the same table under four sets\n * of names). The domains are generalized to the three the whole family shares;\n * a consumer with a different cache vocabulary renames its call sites (clients\n * adapt) rather than extending the registry, because an open registry is how\n * prefix collisions start.\n *\n * Rationale: D1 and the Durable Object stay the source of truth. KV is a\n * loss-tolerant, read-heavy cache only — a miss or eviction must always be\n * recoverable by recompute. Call sites never touch `env.CACHE` directly; they\n * go through `KvCache` with a closed `KvDomainName` registry so prefixes cannot\n * collide and TTL/size policy lives in one table.\n */\nconst KV_KEY_VERSION = 'v1';\nconst KV_MAX_KEY_LENGTH = 512;\nconst KV_MIN_TTL_SECONDS = 60;\n\ntype KvDomainName = 'session' | 'asset' | 'metadata';\n\ninterface KvDomainDef {\n ttlSeconds: number;\n maxValueBytes: number;\n description: string;\n}\n\nconst KV_DOMAINS: Record<KvDomainName, KvDomainDef> = {\n session: {\n ttlSeconds: 300,\n maxValueBytes: 65_536,\n description: 'Per-user session/profile snapshots; invalidated on any credential change.',\n },\n asset: {\n ttlSeconds: 300,\n maxValueBytes: 10_485_760,\n description: 'Binary payloads (file bodies, sealed secrets) with etag/contentType metadata; invalidated on write.',\n },\n metadata: {\n ttlSeconds: 120,\n maxValueBytes: 1_048_576,\n description: 'Listing/derived snapshots keyed by owner or collection; invalidated on mutation.',\n },\n};\n\n/**\n * 128-bit digest built from four independent FNV-1a lanes.\n *\n * Why not a single 32-bit FNV: `buildKvKey` falls back to a digest when a key\n * exceeds the platform's 512-character limit, and the longest keys embed a\n * user-controlled path or name. A 32-bit digest over a shared keyspace is\n * collision-searchable — someone who controls names in their own scope could\n * grind a colliding key and read another tenant's cached bytes. Four lanes over\n * the same bytes with different offsets/primes cost one extra pass and take a\n * birthday collision to ~2^64 work, which is not worth attacking.\n *\n * Synchronous on purpose: `buildKvKey` is called from sync cache-key builders.\n */\nfunction digest128(input: string): string {\n const LANES = 4;\n const offsets = [0x81_1c_9d_c5, 0xc2_b2_ae_35, 0x27_d4_eb_2f, 0x16_56_67_b1];\n let out = '';\n for (let lane = 0; lane < LANES; lane += 1) {\n let hash = offsets[lane] as number;\n const prime = 0x01_00_01_93 + lane * 0x9e_37_79_b9;\n for (let i = 0; i < input.length; i += 1) {\n hash ^= input.codePointAt(i) ?? 0;\n hash = Math.imul(hash, prime);\n }\n out += (hash >>> 0).toString(16).padStart(8, '0');\n }\n return out;\n}\n\nfunction sanitizeSegment(segment: string): string {\n const trimmed = segment.trim();\n if (!trimmed) throw new Error('KV key segment must not be empty.');\n return encodeURIComponent(trimmed);\n}\n\nfunction buildKvKey(domain: KvDomainName, parts: readonly string[]): string {\n const def = KV_DOMAINS[domain];\n if (!def) throw new Error(`Unknown KV domain: ${domain}.`);\n if (parts.length === 0) throw new Error(`KV domain ${domain} requires at least one key part.`);\n const prefix = `${domain}:${KV_KEY_VERSION}:`;\n const joined = parts.map((part) => sanitizeSegment(part)).join(':');\n const full = prefix + joined;\n if (full.length <= KV_MAX_KEY_LENGTH) return full;\n // Deterministic overflow form. Note the consequence for invalidation: an\n // overflowing key does not start with the plain prefix, so `purgePrefix` on\n // the parts will not match it. Callers must therefore bound the key material\n // they cache (path length, identifier length) — the digest is a crash guard,\n // not a caching strategy.\n return `${prefix}h:${digest128(joined)}`;\n}\n\nfunction utf8ByteLength(value: string): number {\n return new TextEncoder().encode(value).length;\n}\n\n/**\n * Resolve a TTL, defaulting to the domain's own. Every domain declares a\n * required `ttlSeconds`, so there is no \"no TTL\" case to represent.\n */\nfunction clampTtl(ttlSeconds: number | undefined, domain: KvDomainName): number {\n const effective = ttlSeconds ?? KV_DOMAINS[domain].ttlSeconds;\n return Number.isFinite(effective) ? Math.max(KV_MIN_TTL_SECONDS, Math.floor(effective)) : KV_DOMAINS[domain].ttlSeconds;\n}\n\nexport { KV_DOMAINS, KV_MAX_KEY_LENGTH, KV_MIN_TTL_SECONDS, buildKvKey, clampTtl, digest128, sanitizeSegment, utf8ByteLength };\nexport type { KvDomainDef, KvDomainName };\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/kv/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEvE,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,EACV,QAAQ,EACR,SAAS,EACT,eAAe,EACf,cAAc,GACf,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/kv/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEvE,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,EACV,QAAQ,EACR,SAAS,EACT,eAAe,EACf,cAAc,GACf,MAAM,aAAa,CAAC","sourcesContent":["export { KvCache, PURGE_LIST_LIMIT, PURGE_MAX_PAGES } from './KvCache';\nexport type { KvBinaryEntry, KvFileMetadata, KvNamespaceLike, KvPutOptions } from './KvCache';\nexport {\n KV_DOMAINS,\n KV_MAX_KEY_LENGTH,\n KV_MIN_TTL_SECONDS,\n buildKvKey,\n clampTtl,\n digest128,\n sanitizeSegment,\n utf8ByteLength,\n} from './KvDomains';\nexport type { KvDomainDef, KvDomainName } from './KvDomains';\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAeA,MAAM,UAAU,GAA6B;IAC3C,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;CACA,CAAC;AAEX,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAW,CAAC,QAAQ,CAAC,KAAiB,CAAC,CAAC;AACnF,CAAC;AAED,SAAS,eAAe,CAAC,GAAa;IACpC,MAAM,YAAY,GAChB,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAE,GAA0C,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACjH,MAAM,OAAO,GAAI,UAAyE,CAAC,OAAO,EAAE,GAAG,EAAE,SAAS,CAAC;IACnH,MAAM,KAAK,GAAG,YAAY,IAAI,OAAO,IAAI,MAAM,CAAC;IAChD,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;AAC5C,CAAC;AASD,SAAS,YAAY,CAAC,SAAkB,EAAE,YAAqB,EAAE,GAAa;IAC5E,MAAM,YAAY,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IAC1C,MAAM,QAAQ,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC;IAE1C,MAAM,OAAO,GAAG,CAAC,YAAY,EAAE,SAAS,CAAC;SACtC,MAAM,CAAC,OAAO,CAAC;SACf,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC;SACpB,IAAI,CAAC,GAAG,CAAC,CAAC;IAEb,OAAO;QACL,KAAK,EAAE,CAAC,GAAG,IAAe,EAAQ,EAAE;YAClC,IAAI,UAAU,CAAC,KAAK,IAAI,QAAQ,EAAE,CAAC;gBACjC,OAAO,CAAC,KAAK,CAAC,WAAW,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;YAC/C,CAAC;QACH,CAAC;QACD,IAAI,EAAE,CAAC,GAAG,IAAe,EAAQ,EAAE;YACjC,IAAI,UAAU,CAAC,IAAI,IAAI,QAAQ,EAAE,CAAC;gBAChC,OAAO,CAAC,IAAI,CAAC,UAAU,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;QACD,IAAI,EAAE,CAAC,GAAG,IAAe,EAAQ,EAAE;YACjC,IAAI,UAAU,CAAC,IAAI,IAAI,QAAQ,EAAE,CAAC;gBAChC,OAAO,CAAC,IAAI,CAAC,UAAU,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;QACD,KAAK,EAAE,CAAC,GAAG,IAAe,EAAQ,EAAE;YAClC,IAAI,UAAU,CAAC,KAAK,IAAI,QAAQ,EAAE,CAAC;gBACjC,OAAO,CAAC,KAAK,CAAC,WAAW,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;YAC/C,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAeA,MAAM,UAAU,GAA6B;IAC3C,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;CACA,CAAC;AAEX,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAW,CAAC,QAAQ,CAAC,KAAiB,CAAC,CAAC;AACnF,CAAC;AAED,SAAS,eAAe,CAAC,GAAa;IACpC,MAAM,YAAY,GAChB,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAE,GAA0C,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACjH,MAAM,OAAO,GAAI,UAAyE,CAAC,OAAO,EAAE,GAAG,EAAE,SAAS,CAAC;IACnH,MAAM,KAAK,GAAG,YAAY,IAAI,OAAO,IAAI,MAAM,CAAC;IAChD,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;AAC5C,CAAC;AASD,SAAS,YAAY,CAAC,SAAkB,EAAE,YAAqB,EAAE,GAAa;IAC5E,MAAM,YAAY,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IAC1C,MAAM,QAAQ,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC;IAE1C,MAAM,OAAO,GAAG,CAAC,YAAY,EAAE,SAAS,CAAC;SACtC,MAAM,CAAC,OAAO,CAAC;SACf,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC;SACpB,IAAI,CAAC,GAAG,CAAC,CAAC;IAEb,OAAO;QACL,KAAK,EAAE,CAAC,GAAG,IAAe,EAAQ,EAAE;YAClC,IAAI,UAAU,CAAC,KAAK,IAAI,QAAQ,EAAE,CAAC;gBACjC,OAAO,CAAC,KAAK,CAAC,WAAW,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;YAC/C,CAAC;QACH,CAAC;QACD,IAAI,EAAE,CAAC,GAAG,IAAe,EAAQ,EAAE;YACjC,IAAI,UAAU,CAAC,IAAI,IAAI,QAAQ,EAAE,CAAC;gBAChC,OAAO,CAAC,IAAI,CAAC,UAAU,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;QACD,IAAI,EAAE,CAAC,GAAG,IAAe,EAAQ,EAAE;YACjC,IAAI,UAAU,CAAC,IAAI,IAAI,QAAQ,EAAE,CAAC;gBAChC,OAAO,CAAC,IAAI,CAAC,UAAU,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;QACD,KAAK,EAAE,CAAC,GAAG,IAAe,EAAQ,EAAE;YAClC,IAAI,UAAU,CAAC,KAAK,IAAI,QAAQ,EAAE,CAAC;gBACjC,OAAO,CAAC,KAAK,CAAC,WAAW,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;YAC/C,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,CAAC","sourcesContent":["/**\n * `KvLogger` — the family's console logger with a level floor.\n *\n * Converged from `backend-runtime/src/logger.ts`, which is identical in\n * Durable-DAV, Durable-DAV-Router, Edge-Sonic, Mail-Otter and Mail-Meow (the\n * copies in AWS/ChordDHT's `shared` are the same shape without the env floor).\n *\n * The level resolves from an injected `env` first, then `process.env`, then\n * `info`: Workers have no `process.env` at runtime, so an injected object is\n * the configuration path, and `process.env` is a local-tooling affordance. An\n * unrecognized level floors at `info` rather than throwing — a typo in\n * `LOG_LEVEL` costing a worker a cold start is not a trade worth making.\n */\ntype LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n} as const;\n\nfunction isLogLevel(level: string): level is LogLevel {\n return (['debug', 'info', 'warn', 'error'] as const).includes(level as LogLevel);\n}\n\nfunction resolveLogLevel(env?: unknown): LogLevel {\n const fromInjected =\n env !== null && typeof env === 'object' ? (env as Record<string, string | undefined>)['LOG_LEVEL'] : undefined;\n const fromEnv = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env?.LOG_LEVEL;\n const level = fromInjected ?? fromEnv ?? 'info';\n return isLogLevel(level) ? level : 'info';\n}\n\ninterface Logger {\n debug(...args: unknown[]): void;\n info(...args: unknown[]): void;\n warn(...args: unknown[]): void;\n error(...args: unknown[]): void;\n}\n\nfunction createLogger(namespace?: string, fullRepoName?: string, env?: unknown): Logger {\n const currentLevel = resolveLogLevel(env);\n const minLevel = LOG_LEVELS[currentLevel];\n\n const argsStr = [fullRepoName, namespace]\n .filter(Boolean)\n .map((s) => `[${s}]`)\n .join(' ');\n\n return {\n debug: (...args: unknown[]): void => {\n if (LOG_LEVELS.debug >= minLevel) {\n console.debug(`[DEBUG] ${argsStr}`, ...args);\n }\n },\n info: (...args: unknown[]): void => {\n if (LOG_LEVELS.info >= minLevel) {\n console.info(`[INFO] ${argsStr}`, ...args);\n }\n },\n warn: (...args: unknown[]): void => {\n if (LOG_LEVELS.warn >= minLevel) {\n console.warn(`[WARN] ${argsStr}`, ...args);\n }\n },\n error: (...args: unknown[]): void => {\n if (LOG_LEVELS.error >= minLevel) {\n console.error(`[ERROR] ${argsStr}`, ...args);\n }\n },\n };\n}\n\nexport { createLogger, isLogLevel, resolveLogLevel };\nexport type { LogLevel, Logger };\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rexezuge/runtime",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -29,6 +29,7 @@
29
29
  "typescript": "6.0.3",
30
30
  "vitest": "4.1.11"
31
31
  },
32
+ "description": "DI container, configuration, worker bases, logger, and KV cache for Cloudflare Workers.",
32
33
  "scripts": {
33
34
  "build": "tsc -p tsconfig.json",
34
35
  "typecheck": "tsc -p tsconfig.test.json --noEmit",