@lunora/codegen 1.0.0-alpha.317 → 1.0.0-alpha.319
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/index.mjs +1 -1
- package/dist/packem_shared/{SCHEMA_SNAPSHOT_FILENAME-By-jJ8_K.mjs → SCHEMA_SNAPSHOT_FILENAME-DwqkR6hn.mjs} +1 -1
- package/dist/packem_shared/{emitAgents-CVN1D17z.mjs → emitAgents-DuSp0uSJ.mjs} +1 -1
- package/dist/packem_shared/{emitApp-BOUdd-2R.mjs → emitApp-BEe4wd3R.mjs} +88 -58
- package/dist/packem_shared/{emitShard-o8m4pR4Z.mjs → emitShard-Ddgmq6De.mjs} +1 -1
- package/dist/packem_shared/{shard-26v1MJxM.mjs → shard-DYYhXxEG.mjs} +91 -65
- package/dist/packem_shared/{shard-runtime-CkTgY8tL.mjs → shard-runtime-BQ6ZNigW.mjs} +1 -1
- package/package.json +8 -8
|
@@ -5,7 +5,7 @@ import{APP_METHOD_CAPABILITIES as k}from"./CAPABILITY_PROBES-brcmKenl.mjs";impor
|
|
|
5
5
|
|
|
6
6
|
return namespace ? createScheduler({${e.jurisdiction?` jurisdiction: ${JSON.stringify(e.jurisdiction)},`:""} namespace }) : undefined;
|
|
7
7
|
}
|
|
8
|
-
`:"",
|
|
8
|
+
`:"",A=e=>e?`
|
|
9
9
|
/**
|
|
10
10
|
* One bucket's \`Storage\`, signing under the name it is registered as.
|
|
11
11
|
*
|
|
@@ -19,12 +19,16 @@ import{APP_METHOD_CAPABILITIES as k}from"./CAPABILITY_PROBES-brcmKenl.mjs";impor
|
|
|
19
19
|
* declared.
|
|
20
20
|
*/
|
|
21
21
|
private makeStorage(env: Env, declaration: StorageDeclaration<Env>, bucket: R2BucketLike, bucketName: string, origin?: string): Storage {
|
|
22
|
+
const publicBaseUrl = declaration.publicBaseUrl?.(env) ?? origin;
|
|
23
|
+
const s3 = declaration.s3?.(env);
|
|
24
|
+
const signingSecret = declaration.signingSecret?.(env);
|
|
25
|
+
|
|
22
26
|
return createStorage({
|
|
23
27
|
bucket,
|
|
24
28
|
bucketName,
|
|
25
|
-
publicBaseUrl:
|
|
26
|
-
s3:
|
|
27
|
-
signingSecret:
|
|
29
|
+
...(publicBaseUrl === undefined ? {} : { publicBaseUrl }),
|
|
30
|
+
...(s3 === undefined ? {} : { s3 }),
|
|
31
|
+
...(signingSecret === undefined ? {} : { signingSecret }),
|
|
28
32
|
});
|
|
29
33
|
}
|
|
30
34
|
|
|
@@ -103,14 +107,14 @@ import{APP_METHOD_CAPABILITIES as k}from"./CAPABILITY_PROBES-brcmKenl.mjs";impor
|
|
|
103
107
|
storageDelete: (key: string, opts?: { bucket?: string }) => pick(opts?.bucket).delete(key),
|
|
104
108
|
storageDownload: (key: string, opts?: { bucket?: string }) => pick(opts?.bucket).download(key),
|
|
105
109
|
storageList: (prefix?: string, opts?: { bucket?: string; cursor?: string; limit?: number }) => pick(opts?.bucket).list(prefix, opts),
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
+
...(hasSigning ? {
|
|
111
|
+
storageSignedUrl: (key: string, opts?: { bucket?: string; contentType?: string; expiresInSeconds?: number; method?: "GET" | "PUT"; origin?: string }) =>
|
|
112
|
+
pick(opts?.bucket, opts?.origin).getSignedUrl(key, opts),
|
|
113
|
+
} : {}),
|
|
110
114
|
storageUpload: (key: string, body: ArrayBuffer, opts?: { bucket?: string; contentType?: string; sha256?: string }) => pick(opts?.bucket).upload(key, body, opts),
|
|
111
115
|
};
|
|
112
116
|
}
|
|
113
|
-
`:"",
|
|
117
|
+
`:"",x=e=>e?`
|
|
114
118
|
/**
|
|
115
119
|
* Adapt the raw D1 binding to \`@lunora/d1\`'s \`D1Exec\` (reads via \`all\`, writes via \`run\`, and — when the binding exposes it — several writes in one round trip via \`batch\`).
|
|
116
120
|
*
|
|
@@ -186,29 +190,29 @@ const buildExec = (database: D1DatabaseLike, bookmark?: string, onBookmark?: (bo
|
|
|
186
190
|
// \`target\`, so the real workerd \`D1Database\`/session doesn't throw
|
|
187
191
|
// \`TypeError: Illegal invocation\` the way a detached
|
|
188
192
|
// \`const fn = target.batch; fn(...)\` capture would.
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
193
|
+
...(batchFn ? {
|
|
194
|
+
batch: async (statements) => {
|
|
195
|
+
const results = await batchFn.call(
|
|
196
|
+
target,
|
|
197
|
+
statements.map(({ params, sql }) => target.prepare(sql).bind(...params)),
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
// Meter each leg. D1 returns one result per statement, in
|
|
201
|
+
// order, each with its own \`meta\` — and a batch is where the
|
|
202
|
+
// expensive writes live (\`@lunora/sql-store\` runs its
|
|
203
|
+
// backfills through here), so discarding it left exactly the
|
|
204
|
+
// statements worth costing unaccounted. Guarded on the array
|
|
205
|
+
// because \`batch\` is optional in the structural type and a
|
|
206
|
+
// test double may resolve to anything.
|
|
207
|
+
if (Array.isArray(results)) {
|
|
208
|
+
for (const [index, statement] of statements.entries()) {
|
|
209
|
+
meter(statement.sql, (results[index] as { meta?: Record<string, unknown> } | undefined)?.meta);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
208
212
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
213
|
+
onBookmark?.(session?.getBookmark() ?? undefined);
|
|
214
|
+
},
|
|
215
|
+
} : {}),
|
|
212
216
|
run: async (sql, parameters) => {
|
|
213
217
|
const result = await target
|
|
214
218
|
.prepare(sql)
|
|
@@ -258,7 +262,7 @@ const buildGlobalImporter =
|
|
|
258
262
|
return importGlobalRows(writer, schema as unknown as D1CtxDbOptions["schema"], {
|
|
259
263
|
exec,
|
|
260
264
|
rows: request.rows.map((row) => ({ doc: row.doc, line: row.line, table: row.table })),
|
|
261
|
-
startLine: request.startLine,
|
|
265
|
+
...(request.startLine === undefined ? {} : { startLine: request.startLine }),
|
|
262
266
|
});
|
|
263
267
|
};
|
|
264
268
|
|
|
@@ -299,7 +303,7 @@ const buildGlobalCdcSync =
|
|
|
299
303
|
return { changes: [], cursor: request.sinceSeq };
|
|
300
304
|
}
|
|
301
305
|
|
|
302
|
-
const page = await readD1CdcChanges(exec,
|
|
306
|
+
const page = await readD1CdcChanges(exec, request);
|
|
303
307
|
|
|
304
308
|
// \`as unknown as\`, because \`CdcChange\` is an interface and interfaces carry
|
|
305
309
|
// no implicit index signature — the shapes are otherwise identical.
|
|
@@ -332,7 +336,7 @@ const buildGlobalCdcApplier =
|
|
|
332
336
|
|
|
333
337
|
return request.changes.length;
|
|
334
338
|
};
|
|
335
|
-
`:"",C=e=>[...e.hasStorage?["/** `.storage(...)` declaration — one bucket (required) plus optional extra named buckets and signed-URL config. Backs `ctx.storage` AND the studio file browser. */\ninterface StorageDeclaration<Env> {\n /** The default R2 bucket binding (the bare `ctx.storage`). */\n bucket: Selector<Env, R2BucketLike>;\n /** Extra named buckets, reached via `ctx.storage.bucket(\"name\")` and the studio's bucket picker. */\n buckets?: Record<string, Selector<Env, R2BucketLike>>;\n /** Public base URL signed/public object URLs resolve against. Omit it and `ctx.storage` in a mutation, action or HTTP handler (and the studio's copy-URL) signs against the origin the request reached the worker on — no per-environment value to ship. Queries get no such fallback (a live query re-runs with no request behind it), so a query that signs URLs needs this set. */\n publicBaseUrl?: Selector<Env, string>;\n /** R2 S3-API credentials (`{ accountId, accessKeyId, secretAccessKey, bucket, jurisdiction? }`) enabling `ctx.storage.getPresignedUrl` — native S3 presigned URLs that hit R2 directly, bypassing the worker. Omit to use only the worker-signed `getSignedUrl` path. */\n s3?: Selector<Env, R2S3Credentials>;\n /** HMAC secret for signed URLs. */\n signingSecret?: Selector<Env, string>;\n}"]:[],...e.hasScheduler?["/** `.scheduler(...)` declaration — the `SchedulerDO` namespace. Backs `ctx.scheduler` AND the studio's scheduled-jobs view. The origin its callbacks dispatch back to is not declared here: the DO reads `env.LUNORA_ORIGIN_URL` at fire time, because a caller-supplied dispatch target would be an SSRF vector. */\ninterface SchedulerDeclaration<Env> {\n /** The `SchedulerDO` namespace binding (typically `env.SCHEDULER`). */\n namespace: Selector<Env, DurableObjectNamespaceLike & ShardNamespaceLike>;\n}"]:[],...e.hasGlobal?["/** `.global(...)` declaration — the D1 binding backing `.global()` tables. Backs cross-tenant `ctx.db` reads/writes AND the studio's global data browser. */\ninterface GlobalDeclaration<Env> {\n /** The D1 binding (typically `env.DB`). */\n d1: Selector<Env, D1DatabaseLike>;\n /** The worker origin used to fan reverse cross-backend relations across shards. Without it, such a relation throws a clear error. */\n origin?: Selector<Env, string>;\n}"]:[],...e.hasHyperdriveGlobal?['/** `.hyperdriveGlobal(...)` declaration — backs `.global({ backend: "hyperdrive" })` tables on a Postgres/MySQL database via Hyperdrive. Stays reactive: the writer is injected as `globalDb` and the broadcast hook drives live queries. */\ninterface HyperdriveGlobalDeclaration<Env> {\n /** The Hyperdrive engine — selects the Postgres or MySQL dialect. */\n engine: HyperdriveEngine;\n /** Build the `SqlExec` from `env` — e.g. `buildPgExec(fromPostgresJs(postgres(env.HYPERDRIVE.connectionString)))`. Cache the driver on the DO instance; rebuild lazily after hibernation. */\n exec: (env: Env) => SqlExec;\n /** The worker origin used to fan reverse cross-backend relations across shards. Without it, such a relation throws a clear error. */\n origin?: Selector<Env, string>;\n}']:[],...e.hasAuth?['/** `.auth(...)` declaration — better-auth options plus the storage the adapter reads. Give it `d1` (the default) or `namespace` (a Durable Object that hosts the auth tables), never both. The builder owns the lazy build + `ensureMigrated` dance and wires `authHandler` / `resolveIdentity` / `authAdmin`. */\ninterface AuthDeclaration<Env> {\n /** The D1 binding the auth SQL adapter is wired over (via `lunoraD1Adapter`). Omit only when using `namespace`. */\n d1?: Selector<Env, unknown>;\n /** Shared secret the worker presents on the object\'s internal session route. REQUIRED with `namespace`: the binding is reachable from any worker bound to it, so the secret — not the binding — is the authorization boundary. Without it identity resolution fails closed. */\n internalSecret?: Selector<Env, string>;\n /** Name of the Durable Object instance holding the auth tables. Defaults to `"auth"`. Set it to run separate auth objects (per deployment, per tenant) off one namespace. */\n objectName?: Selector<Env, string>;\n /** The auth Durable Object namespace — the DO-backed mode. Needed for `@better-auth/scim`, which requires native transactions that D1 has none of. The object owns the auth tables, so `/api/auth/*` and identity resolution both go through it. Typed as `AuthNamespaceLike` because `createDoAuthWiring` resolves through `idFromName` + `get` and has no `getByName` fallback — both members are load-bearing here, and `ShardNamespaceLike` leaves both optional. */\n namespace?: Selector<Env, AuthNamespaceLike>;\n /** Build the better-auth options from `env` (secret, plugins, email/password, …). */\n options: (env: Env) => LunoraAuthOptions;\n}']:[]],O=e=>[...e.hasAccess?[" private accessSelector?: Selector<Env, CreateAccessResolverOptions | undefined>;"]:[]," private adminToken?: Selector<Env, string>;",...e.hasAuth?[" private authDeclaration?: AuthDeclaration<Env>;"]:[]," private cdcEnabled = false;"," private reactiveCacheConfig: boolean | { maxBytes?: number; maxEntries?: number } = false;",' private maxRelationKeysLimit?: ShardConfig["maxRelationKeys"];',' private observabilitySink?: ShardConfig["observability"];',' private relationExistsPushDownMode?: ShardConfig["relationExistsPushDown"];'," private readonly extendFns: ((env: Env, derived: Readonly<WorkerOptions>) => Partial<WorkerOptions>)[] = [];",...e.hasGlobal?[" private globalDeclaration?: GlobalDeclaration<Env>;"]:[],...e.hasHyperdriveGlobal?[" private hyperdriveGlobalDeclaration?: HyperdriveGlobalDeclaration<Env>;"]:[]," private httpRouterApp?: HttpRouterLike;"," private readonly routeMap: Record<string, Route> = {};",...e.hasScheduler?[" private schedulerDeclaration?: SchedulerDeclaration<Env>;"]:[],...g(e)?[" private readonly shardExtras: Partial<ShardConfig> = {};"]:[],...d(e)?[" private shardRegistrySelector?: Selector<Env, ShardNamespaceLike>;"]:[]," private shardSelector?: Selector<Env, ShardNamespaceLike>;",...e.hasSourcedTables?[' private sourceClientFactory?: NonNullable<ShardConfig["sourceClient"]>;']:[],...e.hasStorage?[" private storageDeclaration?: StorageDeclaration<Env>;"]:[]],T=e=>m(e).map(({configKey:r,doc:t,method:a})=>` /** ${t} */
|
|
339
|
+
`:"",C=e=>[...e.hasStorage?["/** `.storage(...)` declaration — one bucket (required) plus optional extra named buckets and signed-URL config. Backs `ctx.storage` AND the studio file browser. */\ninterface StorageDeclaration<Env> {\n /** The default R2 bucket binding (the bare `ctx.storage`). */\n bucket: Selector<Env, R2BucketLike>;\n /** Extra named buckets, reached via `ctx.storage.bucket(\"name\")` and the studio's bucket picker. */\n buckets?: Record<string, Selector<Env, R2BucketLike>>;\n /** Public base URL signed/public object URLs resolve against. Omit it and `ctx.storage` in a mutation, action or HTTP handler (and the studio's copy-URL) signs against the origin the request reached the worker on — no per-environment value to ship. Queries get no such fallback (a live query re-runs with no request behind it), so a query that signs URLs needs this set. */\n publicBaseUrl?: Selector<Env, string>;\n /** R2 S3-API credentials (`{ accountId, accessKeyId, secretAccessKey, bucket, jurisdiction? }`) enabling `ctx.storage.getPresignedUrl` — native S3 presigned URLs that hit R2 directly, bypassing the worker. Omit to use only the worker-signed `getSignedUrl` path. */\n s3?: Selector<Env, R2S3Credentials>;\n /** HMAC secret for signed URLs. */\n signingSecret?: Selector<Env, string>;\n}"]:[],...e.hasScheduler?["/** `.scheduler(...)` declaration — the `SchedulerDO` namespace. Backs `ctx.scheduler` AND the studio's scheduled-jobs view. The origin its callbacks dispatch back to is not declared here: the DO reads `env.LUNORA_ORIGIN_URL` at fire time, because a caller-supplied dispatch target would be an SSRF vector. */\ninterface SchedulerDeclaration<Env> {\n /** The `SchedulerDO` namespace binding (typically `env.SCHEDULER`). */\n namespace: Selector<Env, DurableObjectNamespaceLike & ShardNamespaceLike>;\n}"]:[],...e.hasGlobal?["/** `.global(...)` declaration — the D1 binding backing `.global()` tables. Backs cross-tenant `ctx.db` reads/writes AND the studio's global data browser. */\ninterface GlobalDeclaration<Env> {\n /** The D1 binding (typically `env.DB`). */\n d1: Selector<Env, D1DatabaseLike>;\n /** The worker origin used to fan reverse cross-backend relations across shards. Without it, such a relation throws a clear error. */\n origin?: Selector<Env, string>;\n}"]:[],...e.hasHyperdriveGlobal?['/** `.hyperdriveGlobal(...)` declaration — backs `.global({ backend: "hyperdrive" })` tables on a Postgres/MySQL database via Hyperdrive. Stays reactive: the writer is injected as `globalDb` and the broadcast hook drives live queries. */\ninterface HyperdriveGlobalDeclaration<Env> {\n /** The Hyperdrive engine — selects the Postgres or MySQL dialect. */\n engine: HyperdriveEngine;\n /** Build the `SqlExec` from `env` — e.g. `buildPgExec(fromPostgresJs(postgres(env.HYPERDRIVE.connectionString)))`. Cache the driver on the DO instance; rebuild lazily after hibernation. */\n exec: (env: Env) => SqlExec;\n /** The worker origin used to fan reverse cross-backend relations across shards. Without it, such a relation throws a clear error. */\n origin?: Selector<Env, string>;\n}']:[],...e.hasAuth?['/** `.auth(...)` declaration — better-auth options plus the storage the adapter reads. Give it `d1` (the default) or `namespace` (a Durable Object that hosts the auth tables), never both. The builder owns the lazy build + `ensureMigrated` dance and wires `authHandler` / `resolveIdentity` / `authAdmin`. */\ninterface AuthDeclaration<Env> {\n /** The D1 binding the auth SQL adapter is wired over (via `lunoraD1Adapter`). Omit only when using `namespace`. */\n d1?: Selector<Env, unknown>;\n /** Shared secret the worker presents on the object\'s internal session route. REQUIRED with `namespace`: the binding is reachable from any worker bound to it, so the secret — not the binding — is the authorization boundary. Without it identity resolution fails closed. */\n internalSecret?: Selector<Env, string>;\n /** Name of the Durable Object instance holding the auth tables. Defaults to `"auth"`. Set it to run separate auth objects (per deployment, per tenant) off one namespace. */\n objectName?: Selector<Env, string>;\n /** The auth Durable Object namespace — the DO-backed mode. Needed for `@better-auth/scim`, which requires native transactions that D1 has none of. The object owns the auth tables, so `/api/auth/*` and identity resolution both go through it. Typed as `AuthNamespaceLike` because `createDoAuthWiring` resolves through `idFromName` + `get` and has no `getByName` fallback — both members are load-bearing here, and `ShardNamespaceLike` leaves both optional. */\n namespace?: Selector<Env, AuthNamespaceLike>;\n /** Build the better-auth options from `env` (secret, plugins, email/password, …). */\n options: (env: Env) => LunoraAuthOptions;\n}']:[]],O=e=>[...e.hasAccess?[" private accessSelector?: Selector<Env, CreateAccessResolverOptions | undefined>;"]:[]," private adminToken?: Selector<Env, string>;",...e.hasAuth?[" private authDeclaration?: AuthDeclaration<Env>;"]:[]," private cdcEnabled = false;",' private deliveryAuthorizationSelector?: ShardConfig["deliveryAuthorization"];'," private reactiveCacheConfig: boolean | { maxBytes?: number; maxEntries?: number } = false;",' private maxRelationKeysLimit?: ShardConfig["maxRelationKeys"];',' private observabilitySink?: ShardConfig["observability"];',' private relationExistsPushDownMode?: ShardConfig["relationExistsPushDown"];'," private readonly extendFns: ((env: Env, derived: Readonly<WorkerOptions>) => Partial<WorkerOptions>)[] = [];",...e.hasGlobal?[" private globalDeclaration?: GlobalDeclaration<Env>;"]:[],...e.hasHyperdriveGlobal?[" private hyperdriveGlobalDeclaration?: HyperdriveGlobalDeclaration<Env>;"]:[]," private httpRouterApp?: HttpRouterLike;"," private readonly routeMap: Record<string, Route> = {};",...e.hasScheduler?[" private schedulerDeclaration?: SchedulerDeclaration<Env>;"]:[],...g(e)?[" private readonly shardExtras: Partial<ShardConfig> = {};"]:[],...d(e)?[" private shardRegistrySelector?: Selector<Env, ShardNamespaceLike>;"]:[]," private shardSelector?: Selector<Env, ShardNamespaceLike>;",...e.hasSourcedTables?[' private sourceClientFactory?: NonNullable<ShardConfig["sourceClient"]>;']:[],...e.hasStorage?[" private storageDeclaration?: StorageDeclaration<Env>;"]:[]],T=e=>m(e).map(({configKey:r,doc:t,method:a})=>` /** ${t} */
|
|
336
340
|
public ${a}(factory: (env: Env) => ReturnType<NonNullable<ShardConfig["${r}"]>>): this {
|
|
337
341
|
this.shardExtras.${r} = factory as NonNullable<ShardConfig["${r}"]>;
|
|
338
342
|
|
|
@@ -356,7 +360,11 @@ const buildGlobalCdcApplier =
|
|
|
356
360
|
this.maxRelationKeysLimit = limit;
|
|
357
361
|
|
|
358
362
|
return this;
|
|
359
|
-
}`," /**\n * Route the shard's `ctx.log` lines, `ctx.trace` spans and `ctx.metrics` measurements to a telemetry sink.\n *\n * The DO half of observability: without it every in-handler signal stays in the shard's local ring buffer (the studio Logs panel) and reaches no collector. The worker half — one `onRpc` event per dispatched RPC — is a `createWorker` option; pass the SAME sink to both via `.extend((env) => ({ observability: sink(env) }))` to correlate them.\n */\n public observability(selector: NonNullable<ShardConfig[\"observability\"]>): this {\n this.observabilitySink = selector;\n\n return this;\n }",' /** Resolution policy for a relation-crossing `where` whose child is co-located in this shard: `"auto"` (cost-based, the engine default), `"always"` (inline correlated EXISTS) or `"never"` (universal semijoin). All three return identical rows. */\n public relationExistsPushDown(mode: NonNullable<ShardConfig["relationExistsPushDown"]>): this {\n this.relationExistsPushDownMode = mode;\n\n return this;\n }'
|
|
363
|
+
}`," /**\n * Route the shard's `ctx.log` lines, `ctx.trace` spans and `ctx.metrics` measurements to a telemetry sink.\n *\n * The DO half of observability: without it every in-handler signal stays in the shard's local ring buffer (the studio Logs panel) and reaches no collector. The worker half — one `onRpc` event per dispatched RPC — is a `createWorker` option; pass the SAME sink to both via `.extend((env) => ({ observability: sink(env) }))` to correlate them.\n */\n public observability(selector: NonNullable<ShardConfig[\"observability\"]>): this {\n this.observabilitySink = selector;\n\n return this;\n }",' /** Resolution policy for a relation-crossing `where` whose child is co-located in this shard: `"auto"` (cost-based, the engine default), `"always"` (inline correlated EXISTS) or `"never"` (universal semijoin). All three return identical rows. */\n public relationExistsPushDown(mode: NonNullable<ShardConfig["relationExistsPushDown"]>): this {\n this.relationExistsPushDownMode = mode;\n\n return this;\n }',` /** Authorize each RPC/subscription read and fence its eventual delivery against durable authority epochs. */
|
|
364
|
+
public deliveryAuthorization(selector: NonNullable<ShardConfig["deliveryAuthorization"]>): this {
|
|
365
|
+
this.deliveryAuthorizationSelector = selector;
|
|
366
|
+
return this;
|
|
367
|
+
}`,...e.hasAuth?[' /** Wire better-auth — the builder lazily builds the instance, runs `ensureMigrated`, and dispatches `/api/auth/*` inside the worker (instrumented for the auth-failure SLO). Pass `d1` for the D1-backed default, or `namespace` + `internalSecret` to host the auth tables in a Durable Object (what `@better-auth/scim` needs). */\n public auth(declaration: AuthDeclaration<Env>): this {\n // Reject the ambiguous and the empty shapes here rather than at the first\n // request: with neither storage set, auth would silently never answer, and\n // with both it is unclear which one owns the tables.\n if (declaration.d1 && declaration.namespace) {\n throw new Error(".auth(): pass either `d1` or `namespace`, not both — they are two different homes for the same tables.");\n }\n\n if (!declaration.d1 && !declaration.namespace) {\n throw new Error(".auth(): needs `d1` (D1-backed) or `namespace` (Durable-Object-backed) to know where the auth tables live.");\n }\n\n if (declaration.namespace && !declaration.internalSecret) {\n throw new Error(\n ".auth(): `namespace` requires `internalSecret` — the auth DO binding is reachable from any worker bound to it, so identity resolution is gated on a shared secret and would otherwise fail closed on every request.",\n );\n }\n\n this.authDeclaration = declaration;\n\n return this;\n }']:[]," /** Escape hatch — merge raw `WorkerOptions` (anything not yet sugared) over the derived options at build time. The second `derived` argument is a snapshot of the options assembled so far (after `.auth(...)` etc.), so you can compose rather than clobber — e.g. wrap `derived.resolveIdentity` instead of replacing it. */\n public extend(fn: (env: Env, derived: Readonly<WorkerOptions>) => Partial<WorkerOptions>): this {\n this.extendFns.push(fn);\n\n return this;\n }",...e.hasGlobal?[` /** Back \`.global()\` (cross-tenant) tables with D1 — wires \`ctx.db\` routing, the studio global browser, and reverse cross-shard relations. */
|
|
360
368
|
public global(declaration: GlobalDeclaration<Env>): this {
|
|
361
369
|
this.globalDeclaration = declaration;
|
|
362
370
|
|
|
@@ -397,7 +405,7 @@ const buildGlobalCdcApplier =
|
|
|
397
405
|
|
|
398
406
|
return this;
|
|
399
407
|
}`]:[],...T(e)],I=e=>{const r=a=>e.hasScheduler?`
|
|
400
|
-
...(this.schedulerDeclaration ? { scheduler: this.resolveScheduler(env) as unknown as ${a}["scheduler"] } : {}),`:"",t=[" cdc: this.cdcEnabled,"," reactiveCache: this.reactiveCacheConfig,"," ...(this.maxRelationKeysLimit === undefined ? {} : { maxRelationKeys: this.maxRelationKeysLimit }),"," ...(this.observabilitySink === undefined ? {} : { observability: this.observabilitySink }),"," ...(this.relationExistsPushDownMode === undefined ? {} : { relationExistsPushDown: this.relationExistsPushDownMode }),",...e.hasGlobal?[` ...(this.globalDeclaration
|
|
408
|
+
...(this.schedulerDeclaration ? { scheduler: this.resolveScheduler(env) as unknown as ${a}["scheduler"] } : {}),`:"",t=[" cdc: this.cdcEnabled,"," reactiveCache: this.reactiveCacheConfig,"," ...(this.maxRelationKeysLimit === undefined ? {} : { maxRelationKeys: this.maxRelationKeysLimit }),"," ...(this.observabilitySink === undefined ? {} : { observability: this.observabilitySink }),"," ...(this.deliveryAuthorizationSelector === undefined ? {} : { deliveryAuthorization: this.deliveryAuthorizationSelector }),"," ...(this.relationExistsPushDownMode === undefined ? {} : { relationExistsPushDown: this.relationExistsPushDownMode }),",...e.hasGlobal?[` ...(this.globalDeclaration
|
|
401
409
|
? {
|
|
402
410
|
d1: (rawEnv: Record<string, unknown>, request?: { bookmark?: string; cdc?: boolean; cdcRetentionMs?: number; identity?: Record<string, unknown>; onBookmark?: (bookmark: string | undefined) => void; userId?: string | null }) => {
|
|
403
411
|
const env = rawEnv as Env;
|
|
@@ -409,7 +417,11 @@ const buildGlobalCdcApplier =
|
|
|
409
417
|
|
|
410
418
|
const origin = this.globalDeclaration?.origin?.(env);
|
|
411
419
|
const crossShard = origin
|
|
412
|
-
? createCrossShardRelationCapabilities({
|
|
420
|
+
? createCrossShardRelationCapabilities({
|
|
421
|
+
...(request?.identity === undefined ? {} : { identity: request.identity }),
|
|
422
|
+
origin,
|
|
423
|
+
...(request?.userId == null ? {} : { userId: request.userId }),
|
|
424
|
+
})
|
|
413
425
|
: undefined;
|
|
414
426
|
|
|
415
427
|
return createD1CtxDb({
|
|
@@ -443,7 +455,11 @@ const buildGlobalCdcApplier =
|
|
|
443
455
|
|
|
444
456
|
const origin = declaration.origin?.(env);
|
|
445
457
|
const crossShard = origin
|
|
446
|
-
? createCrossShardRelationCapabilities({
|
|
458
|
+
? createCrossShardRelationCapabilities({
|
|
459
|
+
...(request?.identity === undefined ? {} : { identity: request.identity }),
|
|
460
|
+
origin,
|
|
461
|
+
...(request?.userId == null ? {} : { userId: request.userId }),
|
|
462
|
+
})
|
|
447
463
|
: undefined;
|
|
448
464
|
|
|
449
465
|
return createHyperdriveGlobalCtxDb({
|
|
@@ -471,7 +487,7 @@ const buildGlobalCdcApplier =
|
|
|
471
487
|
: {}),`]:[],...d(e)?[" ...(this.shardRegistrySelector ? { shardRegistry: (rawEnv: Record<string, unknown>) => this.shardRegistrySelector?.(rawEnv as Env) } : {}),"]:[],...e.hasSourcedTables?[" ...(this.sourceClientFactory === undefined ? {} : { sourceClient: this.sourceClientFactory }),"]:[],...e.hasStorage?[" ...(this.storageDeclaration ? { storage: (rawEnv: Record<string, unknown>, origin?: string) => this.resolveStorage(rawEnv as Env, origin) } : {}),"]:[],...g(e)?[" ...this.shardExtras,"]:[]];return t.length>0?`
|
|
472
488
|
${t.join(`
|
|
473
489
|
`)}
|
|
474
|
-
`:""},q=e=>e?['import * as lunoraIdentityContract from "../identity.js";']:[],L=(e,r)=>e?['import type { CreateAccessResolverOptions } from "@lunora/cloudflare-access";',`import { createAccessResolver${r?", composeResolvers":""} } from "@lunora/cloudflare-access";`]:[],j=e=>e?['import { createKvIntrospectorFromEnv } from "@lunora/bindings/kv";']:[],B=e=>e?['import { createVectorAdminIntrospector } from "@lunora/bindings/vectors";']:[],
|
|
490
|
+
`:""},q=e=>e?['import * as lunoraIdentityContract from "../identity.js";']:[],L=(e,r)=>e?['import type { CreateAccessResolverOptions } from "@lunora/cloudflare-access";',`import { createAccessResolver${r?", composeResolvers":""} } from "@lunora/cloudflare-access";`]:[],j=e=>e?['import { createKvIntrospectorFromEnv } from "@lunora/bindings/kv";']:[],B=e=>e?['import { createVectorAdminIntrospector } from "@lunora/bindings/vectors";']:[],P=e=>e?['import type { D1CtxDbOptions, D1DatabaseLike, D1Exec } from "@lunora/d1";','import { applyCdcChanges, createD1CtxDb, emitD1QueryCost, exportGlobalRows, facetGlobalColumn, importGlobalRows, listGlobalTables, readD1CdcChanges, readGlobalTablePage, retryingExec } from "@lunora/d1";']:[],G=e=>e?['import notifyConfig from "../notify.js";']:[],_=e=>v(e)?['import { dispatchAgentEmail } from "@lunora/agent/inbound";']:[],W=e=>v(e)?['import * as lunoraAgentDefinitions from "../agents.js";']:[],M=e=>{const{hasFramework:r,hasGlobal:t,hasHyperdriveGlobal:a,hasQueue:n,useUmbrella:o}=e,i=o?"lunorash/runtime":"@lunora/runtime",c=["ExecutionContextLike","HttpRouterLike","LunoraWorker","Route","ScheduledControllerLike","ShardNamespaceLike","WorkerOptions",...n?["TriggerTrace"]:[],...t?["GlobalIntrospector"]:[],...e.tables.length>0?["ShardingInfo"]:[],...r?["FrameworkHostHandler"]:[]],l=[...t||a?["createCrossShardRelationCapabilities"]:[],...d(e)?["createDynamicShardRegistry","createQueryCoordinator"]:[],"createWorker",...e.jurisdiction?["declareAppJurisdiction"]:[],"resolveLogArchiveFromEnv",...e.hasAuth?["memoizeIdentity"]:[],...r?["withFrameworkWorker"]:[]].join(", ");return[`import type { ${[...c].toSorted((s,h)=>s.localeCompare(h)).join(", ")} } from "${i}";`,`import { ${l} } from "${i}";`]},H=e=>{const{hasAccess:r,hasAuth:t,hasGlobal:a,hasHyperdriveGlobal:n,hasKvIntrospector:o,hasQueue:i,hasScheduler:c,hasStorage:l,hasWorkflow:s,wantsOpenApi:h,wantsOpenRpc:u}=e;return[...t?['import type { AuthNamespaceLike, LunoraAuth, LunoraAuthOptions } from "@lunora/auth";','import { authDiscoveryPathsFor, createAuth, createAuthAdmin, createAuthAuditReader, createDoAuthWiring, d1Executor, handleAuthDiscoveryRequest, handleAuthRequest, lunoraD1Adapter } from "@lunora/auth";']:[],...L(r,t),...P(a),...n?['import type { HyperdriveEngine } from "@lunora/hyperdrive/global";','import { createHyperdriveGlobalCtxDb } from "@lunora/hyperdrive/global";','import type { SqlCtxDbOptions, SqlExec } from "@lunora/sql-store";']:[],...j(o),...B(e.hasVectors),...c?['import type { DurableObjectNamespaceLike } from "@lunora/scheduler";','import { createScheduler } from "@lunora/scheduler";']:[],...l?['import type { R2BucketLike, R2S3Credentials, Storage } from "@lunora/storage";','import { createBucketStorage, createStorage } from "@lunora/storage";']:[],...s?['import { createWorkflowsRestClient } from "@lunora/workflow";']:[],..._(e),...M(e),"",...q(e.identity),...W(e),...a||n?['import schema from "../schema.js";']:[],...G(e.hasNotify),'import { LUNORA_CRONS } from "./crons.js";','import { LUNORA_FUNCTIONS } from "./functions.js";',...i?['import { createQueueCaptureSink, dispatchQueueBatch, shouldCaptureQueue } from "@lunora/queue";','import { LUNORA_QUEUE_REGISTRY } from "./queues.js";']:[],...e.wantsArchitecture?['import { architecture } from "./architecture.js";']:[],...h?['import { openApiSpec } from "./openapi.js";']:[],...u?['import { openRpcSpec } from "./openrpc.js";']:[],'import { createShardDO } from "./shard.js";',...e.hasVectors?['import { LUNORA_VECTOR_INDEXES } from "./vectors.js";']:[]]},$=e=>e.jurisdiction&&e.jurisdictionPinsAuth===!0?`
|
|
475
491
|
// The schema's jurisdiction pins the auth object like every other DO.
|
|
476
492
|
jurisdiction: ${JSON.stringify(e.jurisdiction)},`:"",U=e=>typeof e=="string"?`{ mode: { kind: ${JSON.stringify(e)} } }`:`{ mode: { field: ${JSON.stringify(e.field)}, kind: "shardBy" } }`,F=e=>[...e.tables.length>0?[` const tableSharding = new Map<string, ShardingInfo>([
|
|
477
493
|
${e.tables.map(r=>` [${JSON.stringify(r.name)}, ${U(r.shardMode)}],`).join(`
|
|
@@ -532,7 +548,13 @@ ${e.tables.map(r=>` [${JSON.stringify(r.name)}, ${U(r.shardMode)}],`)
|
|
|
532
548
|
throw new Error(
|
|
533
549
|
".vectors(): the schema declares vector index(es) but no binding map was chained. Pass \`.vectors((env) => ({ <indexName>: env.<BINDING> }))\` so \`ctx.vectors\` resolves and the studio's Vectors tab can list them.",
|
|
534
550
|
);
|
|
535
|
-
}`]:[],...e.hasNotify?[
|
|
551
|
+
}`]:[],...e.hasNotify?[` if (notifyConfig.store) {
|
|
552
|
+
options.notifySubscriptionStore = notifyConfig.store(env as Record<string, unknown>);
|
|
553
|
+
}`]:[],` const logArchive = resolveLogArchiveFromEnv(env);
|
|
554
|
+
|
|
555
|
+
if (logArchive !== undefined) {
|
|
556
|
+
options.logArchive = logArchive;
|
|
557
|
+
}`,...e.hasAuth?[` // Captured before the branch so the narrowing survives — reading
|
|
536
558
|
// \`this.authDeclaration.namespace\` again below would be optional all over again.
|
|
537
559
|
const authDeclaration = this.authDeclaration;
|
|
538
560
|
const authNamespace = authDeclaration?.namespace;
|
|
@@ -544,16 +566,20 @@ ${e.tables.map(r=>` [${JSON.stringify(r.name)}, ${U(r.shardMode)}],`)
|
|
|
544
566
|
// to it. \`createDoAuthWiring\` is a tested function in \`@lunora/auth\` rather
|
|
545
567
|
// than more emitted code: request-path logic in generated output can only be
|
|
546
568
|
// typechecked, never unit-tested.
|
|
569
|
+
const discoveryPaths = authDiscoveryPathsFor(authDeclaration, env);
|
|
570
|
+
const internalSecret = authDeclaration.internalSecret?.(env);
|
|
571
|
+
const namespace = authNamespace(env);
|
|
572
|
+
const objectName = authDeclaration.objectName?.(env);
|
|
547
573
|
const authWiring = createDoAuthWiring({
|
|
548
574
|
// The OAuth discovery documents (an \`mcp()\` resource's metadata, the
|
|
549
575
|
// issuer's) are derived here from the declared options, so the worker
|
|
550
576
|
// forwards only those exact paths and no other probe reaches the object.
|
|
551
577
|
// Memoised on the declaration: a framework-hosted worker rebuilds these
|
|
552
578
|
// options per request, and \`options(env)\` rebuilds every plugin.
|
|
553
|
-
discoveryPaths
|
|
554
|
-
internalSecret
|
|
555
|
-
namespace
|
|
556
|
-
objectName:
|
|
579
|
+
discoveryPaths,
|
|
580
|
+
internalSecret,${$(e)}
|
|
581
|
+
namespace,
|
|
582
|
+
...(objectName === undefined ? {} : { objectName }),
|
|
557
583
|
});
|
|
558
584
|
|
|
559
585
|
options.authHandler = authWiring.authHandler;
|
|
@@ -625,7 +651,9 @@ ${e.tables.map(r=>` [${JSON.stringify(r.name)}, ${U(r.shardMode)}],`)
|
|
|
625
651
|
};
|
|
626
652
|
const authInstance = getAuth();
|
|
627
653
|
|
|
628
|
-
|
|
654
|
+
if (authInstance) {
|
|
655
|
+
options.authAdmin = createAuthAdmin(authInstance);
|
|
656
|
+
}
|
|
629
657
|
options.authAuditReader = createAuthAuditReader(d1Executor(authD1(env) as never));
|
|
630
658
|
}
|
|
631
659
|
|
|
@@ -719,10 +747,10 @@ ${e.tables.map(r=>` [${JSON.stringify(r.name)}, ${U(r.shardMode)}],`)
|
|
|
719
747
|
}`]:[],...e.voiceAgents&&e.voiceAgents.length>0?[` options.voiceAgents = {
|
|
720
748
|
${e.voiceAgents.map(r=>` ${JSON.stringify(r.exportName)}: (env as Record<string, unknown>)[${JSON.stringify(r.bindingName)}] as ShardNamespaceLike,`).join(`
|
|
721
749
|
`)}
|
|
722
|
-
};`]:[]],
|
|
750
|
+
};`]:[]],z=e=>[" cronJobs: LUNORA_CRONS,"," functions: LUNORA_FUNCTIONS,",...e.identity?[` identity: lunoraIdentityContract.${e.identity.exportName},`]:[],...e.jurisdiction?[` jurisdiction: ${JSON.stringify(e.jurisdiction)},`]:[],...e.wantsArchitecture?[" architecture,"]:[],...e.wantsOpenApi?[" openApiSpec,"]:[],...e.wantsOpenRpc?[" openRpcSpec,"]:[],...e.hasQueue?[" queue: (batch: unknown, queueEnv: unknown, _context: ExecutionContextLike, trigger: TriggerTrace): Promise<void> =>"," dispatchQueueBatch(batch as Parameters<typeof dispatchQueueBatch>[0], LUNORA_QUEUE_REGISTRY, {"," capture: shouldCaptureQueue(queueEnv as Record<string, unknown>)",` ? createQueueCaptureSink(queueEnv as Record<string, unknown>${e.jurisdiction?`, { jurisdiction: ${JSON.stringify(e.jurisdiction)} }`:""})`," : undefined,"," env: queueEnv as Record<string, unknown>,"," traceparent: trigger.traceparent,"," }),"]:[]," ...(this.httpRouterApp ? { httpRouter: this.httpRouterApp } : {}),"," routes: this.routeMap,"," shardDO: this.shardSelector?.(env) ?? (undefined as unknown as ShardNamespaceLike),"],J=e=>e?`
|
|
723
751
|
/** The identity memo per \`env\` object, owned by one assembled worker. */
|
|
724
752
|
type IdentityMemoStore = WeakMap<object, ReturnType<typeof memoizeIdentity>>;
|
|
725
|
-
`:"",
|
|
753
|
+
`:"",K=e=>[...e.hasAuth?["AuthDeclaration"]:[],"ComposedApp",...e.hasGlobal?["GlobalDeclaration"]:[],"LunoraConfig",...e.hasScheduler?["SchedulerDeclaration"]:[],"Selector",...e.hasStorage?["StorageDeclaration"]:[]].toSorted((r,t)=>r.localeCompare(t)).join(", "),Z=e=>{const r=(e.hasVectors??!0)&&(e.vectorIndexCount??0)>0,t={...e,hasVectors:r},{hasAuth:a}=t,n=C(t),o=Q(t),i=a?` let auth: LunoraAuth | null = null;
|
|
726
754
|
let authInit: Promise<void> | null = null;
|
|
727
755
|
// One memo per env for THIS assembled worker: a framework-hosted worker rebuilds its options per
|
|
728
756
|
// request and must reuse it, but a second \`assemble()\` has its own auth closure and must not share.
|
|
@@ -780,8 +808,8 @@ type IdentityMemoStore = WeakMap<object, ReturnType<typeof memoizeIdentity>>;
|
|
|
780
808
|
throw error;
|
|
781
809
|
}));
|
|
782
810
|
`:"",l=a?`
|
|
783
|
-
await ensureAuth(env);`:"",
|
|
784
|
-
host ? withFrameworkWorker(host, (hostEnv) => this.buildWorkerOptions(hostEnv as Env, ${
|
|
811
|
+
await ensureAuth(env);`:"",s=a?"() => auth, identityMemos":"() => null",h=a?"getAuth: () => LunoraAuth | null, identityMemos: IdentityMemoStore":"_getAuth: () => null",u=t.hasFramework?` const buildWorker = (env: Env): LunoraWorker =>
|
|
812
|
+
host ? withFrameworkWorker(host, (hostEnv) => this.buildWorkerOptions(hostEnv as Env, ${s})) : createWorker(this.buildWorkerOptions(env, ${s}));`:` const buildWorker = (env: Env): LunoraWorker => createWorker(this.buildWorkerOptions(env, ${s}));`,y=t.hasFramework?"host?: FrameworkHostHandler":"",p=t.emailAgents??[],f=p.length>0?` composed.email = dispatchAgentEmail([
|
|
785
813
|
${p.map(b=>` { agent: lunoraAgentDefinitions.${b.exportName}, className: ${JSON.stringify(b.className)} },`).join(`
|
|
786
814
|
`)}
|
|
787
815
|
]);
|
|
@@ -797,15 +825,15 @@ type Selector<Env, T> = (env: Env) => T | undefined;
|
|
|
797
825
|
|
|
798
826
|
/** The generated \`createShardDO\` config — \`.observability()\`, \`.maxRelationKeys()\` and the long-tail \`.ai()\` / \`.kv()\` / … methods pass straight through to it. */
|
|
799
827
|
type ShardConfig = NonNullable<Parameters<typeof createShardDO>[0]>;
|
|
800
|
-
${
|
|
828
|
+
${J(a)}${t.jurisdiction?`
|
|
801
829
|
// Module scope, so every isolate loading this script (the worker and each Durable
|
|
802
830
|
// Object class it exports) knows the schema's jurisdiction before a request runs.
|
|
803
831
|
// \`@lunora/mail\` reads it to pin its shard RPC like every other DO path.
|
|
804
832
|
declareAppJurisdiction(${JSON.stringify(t.jurisdiction)});
|
|
805
833
|
`:""}
|
|
806
|
-
${
|
|
834
|
+
${n.join(`
|
|
807
835
|
|
|
808
|
-
`)}${
|
|
836
|
+
`)}${n.length>0?`
|
|
809
837
|
|
|
810
838
|
`:""}/** The composed app: a Cloudflare module worker (\`fetch\` / \`scheduled\` / optional \`email\`) plus the \`ShardDO\` class binding. */
|
|
811
839
|
interface ComposedApp extends LunoraWorker {
|
|
@@ -889,16 +917,18 @@ ${t.hasFramework?`
|
|
|
889
917
|
`:""}
|
|
890
918
|
return composed;
|
|
891
919
|
}
|
|
892
|
-
${R(t)}${
|
|
920
|
+
${R(t)}${A(t.hasStorage)}
|
|
893
921
|
/** Fan the recorded declarations into the worker-side \`createWorker\` options. */
|
|
894
922
|
private buildWorkerOptions(env: Env, ${h}): WorkerOptions {
|
|
895
923
|
const options: WorkerOptions = {
|
|
896
|
-
${
|
|
924
|
+
${z(t).join(`
|
|
897
925
|
`)}
|
|
898
926
|
};
|
|
899
927
|
|
|
900
|
-
|
|
901
|
-
|
|
928
|
+
const adminToken = this.adminToken?.(env);
|
|
929
|
+
|
|
930
|
+
if (adminToken !== undefined) {
|
|
931
|
+
options.adminToken = adminToken;
|
|
902
932
|
}
|
|
903
933
|
|
|
904
934
|
${o.join(`
|
|
@@ -912,7 +942,7 @@ ${o.join(`
|
|
|
912
942
|
return options;
|
|
913
943
|
}
|
|
914
944
|
}
|
|
915
|
-
${
|
|
945
|
+
${x(t.hasGlobal)}
|
|
916
946
|
/**
|
|
917
947
|
* Shape of the project's root \`lunora.config.*\`.
|
|
918
948
|
*
|
|
@@ -951,5 +981,5 @@ interface LunoraConfig<Env extends object = object> {
|
|
|
951
981
|
const defineApp = <Env extends object>(): AppBuilder<Env> => new AppBuilder<Env>();
|
|
952
982
|
|
|
953
983
|
export { AppBuilder, defineApp };
|
|
954
|
-
export type { ${
|
|
984
|
+
export type { ${K(t)} };
|
|
955
985
|
`};export{Z as emitApp};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./SCHEMA_SNAPSHOT_VERSION-C0oHwiJZ.mjs";import"./isD1GlobalTable-udvHAAzD.mjs";import"./json-data-Chfs2Cz5.mjs";import{e as d}from"./shard-
|
|
1
|
+
import"./SCHEMA_SNAPSHOT_VERSION-C0oHwiJZ.mjs";import"./isD1GlobalTable-udvHAAzD.mjs";import"./json-data-Chfs2Cz5.mjs";import{e as d}from"./shard-DYYhXxEG.mjs";import"./shard-runtime-BQ6ZNigW.mjs";import"./shared-DnCokNcE.mjs";import"./platform-8oj7iXQy.mjs";import"./schema-BgM8A3XV.mjs";export{d as default};
|