@lunora/codegen 1.0.0-alpha.319 → 1.0.0-alpha.320

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.
Files changed (36) hide show
  1. package/dist/index.d.mts +23 -2
  2. package/dist/index.d.ts +23 -2
  3. package/dist/index.mjs +1 -1
  4. package/dist/packem_shared/{NOTIFY_FILENAME-CjbDYC2a.mjs → NOTIFY_FILENAME-bAt7J3cs.mjs} +1 -1
  5. package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-Bo67h-3B.mjs +11 -0
  6. package/dist/packem_shared/chain-Cm6BMT8g.mjs +1 -0
  7. package/dist/packem_shared/classify-procedure-call-DVxdUhZt.mjs +1 -0
  8. package/dist/packem_shared/{context-property-calls-Bw8u2Pz4.mjs → context-property-calls-Cn3upNgZ.mjs} +1 -1
  9. package/dist/packem_shared/{context-root-YkWLB6M2.mjs → context-root-BdxINX-T.mjs} +1 -1
  10. package/dist/packem_shared/{database-calls-BnVUlTx_.mjs → database-calls-BKozZUEW.mjs} +1 -1
  11. package/dist/packem_shared/discoverFunctions-CZgLhsMn.mjs +1 -0
  12. package/dist/packem_shared/discoverHyperdriveCalls-DV4IglLE.mjs +1 -0
  13. package/dist/packem_shared/{discoverInserts-DUbjhNzk.mjs → discoverInserts-BjxXCACZ.mjs} +1 -1
  14. package/dist/packem_shared/discoverMaskProcedures-DE-8CDen.mjs +1 -0
  15. package/dist/packem_shared/{discoverNondeterministicCalls-D7Ovq8ae.mjs → discoverNondeterministicCalls-DvhyKM-f.mjs} +1 -1
  16. package/dist/packem_shared/{discoverQueries-BNqjOBY_.mjs → discoverQueries-C8E7TeRT.mjs} +1 -1
  17. package/dist/packem_shared/discoverR2sqlCalls-DVcfMO6-.mjs +1 -0
  18. package/dist/packem_shared/{discoverRlsMetadata-CbdfaVep.mjs → discoverRlsMetadata-QRsWRQbM.mjs} +1 -1
  19. package/dist/packem_shared/{discoverRlsProcedures-BeLdV5RT.mjs → discoverRlsProcedures-Du7ITNTQ.mjs} +1 -1
  20. package/dist/packem_shared/{discoverStorageRulesMetadata-BBMy9JVZ.mjs → discoverStorageRulesMetadata-ClzKLdCV.mjs} +1 -1
  21. package/dist/packem_shared/{emitAgents-DuSp0uSJ.mjs → emitAgents-CR2_X_ov.mjs} +1 -1
  22. package/dist/packem_shared/emitFunctions-rjyb7h7k.mjs +422 -0
  23. package/dist/packem_shared/{emitShard-Ddgmq6De.mjs → emitShard-D3Po46nf.mjs} +1 -1
  24. package/dist/packem_shared/{exported-procedure-chains-DAl7xBBx.mjs → exported-procedure-chains-BNBUkXui.mjs} +1 -1
  25. package/dist/packem_shared/{index-DvmKcoFV.mjs → index-JnqBWRYO.mjs} +1 -1
  26. package/dist/packem_shared/{shard-DYYhXxEG.mjs → shard-CsOnD3Na.mjs} +226 -117
  27. package/dist/packem_shared/{shard-runtime-BQ6ZNigW.mjs → shard-runtime-BpoCV-aM.mjs} +13 -8
  28. package/package.json +1 -1
  29. package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-DwqkR6hn.mjs +0 -11
  30. package/dist/packem_shared/chain-CubC5VoS.mjs +0 -1
  31. package/dist/packem_shared/classify-procedure-call-CcgP-9I0.mjs +0 -1
  32. package/dist/packem_shared/discoverFunctions-5Zy6K4uA.mjs +0 -1
  33. package/dist/packem_shared/discoverHyperdriveCalls-DFbp-ILH.mjs +0 -1
  34. package/dist/packem_shared/discoverMaskProcedures-BfVFPpAJ.mjs +0 -1
  35. package/dist/packem_shared/discoverR2sqlCalls-TNwsmYje.mjs +0 -1
  36. package/dist/packem_shared/emitFunctions-amc10WSc.mjs +0 -291
@@ -1,4 +1,4 @@
1
- import{LunoraError as At}from"@lunora/errors";import{serializeSchemaSnapshot as Ot,hashSchemaSnapshot as Dt}from"./SCHEMA_SNAPSHOT_VERSION-C0oHwiJZ.mjs";import{isHyperdriveGlobalTable as Tt,isD1GlobalTable as Et}from"./isD1GlobalTable-udvHAAzD.mjs";import{r as Ct}from"./json-data-Chfs2Cz5.mjs";import{r as T,e as Lt,a as _t,b as It,c as Mt,d as Pt,f as Nt,g as $t,h as qt,i as Ft,j as Ut,k as Bt,l as Wt,m as jt,n as Ht,o as Vt,p as Kt,q as Gt}from"./shard-runtime-BQ6ZNigW.mjs";import{u as K,i as zt,G as Qt,d as Jt}from"./shared-DnCokNcE.mjs";import{p as Yt}from"./platform-8oj7iXQy.mjs";import{i as Xt}from"./schema-BgM8A3XV.mjs";const h=(n,e)=>`((): (() => ${e}) => { let cached: ${e} | undefined; return () => (cached ??= JSON.parse(${JSON.stringify(JSON.stringify(n))}) as ${e}); })()`,te=["categories","description","facing","level","remediation","title"],Zt=n=>{const e={};return{advisoryRows:n.map(a=>{let r=e[a.name];return r||(r=Object.fromEntries(te.filter(s=>s in a).map(s=>[s,a[s]])),e[a.name]=r),Object.fromEntries(Object.entries(a).filter(([s,d])=>!te.includes(s)||JSON.stringify(d)!==JSON.stringify(r[s])))}),advisoryRules:e}},er=` /**
1
+ import{LunoraError as It}from"@lunora/errors";import{serializeSchemaSnapshot as Pt,hashSchemaSnapshot as Nt}from"./SCHEMA_SNAPSHOT_VERSION-C0oHwiJZ.mjs";import{isHyperdriveGlobalTable as Mt,isD1GlobalTable as $t}from"./isD1GlobalTable-udvHAAzD.mjs";import{r as qt}from"./json-data-Chfs2Cz5.mjs";import{r as _,e as Ft,a as Ut,b as Bt,c as jt,d as Wt,f as Ht,g as Vt,h as Kt,i as Gt,j as Qt,k as Jt,l as zt,m as Yt,n as Xt,o as Zt,p as er,q as tr}from"./shard-runtime-BpoCV-aM.mjs";import{u as J,i as rr,G as nr,d as ar}from"./shared-DnCokNcE.mjs";import{p as sr}from"./platform-8oj7iXQy.mjs";import{i as or}from"./schema-BgM8A3XV.mjs";const h=(n,e)=>`((): (() => ${e}) => { let cached: ${e} | undefined; return () => (cached ??= JSON.parse(${JSON.stringify(JSON.stringify(n))}) as ${e}); })()`,oe=["categories","description","facing","level","remediation","title"],ir=n=>{const e={};return{advisoryRows:n.map(a=>{let r=e[a.name];return r||(r=Object.fromEntries(oe.filter(s=>s in a).map(s=>[s,a[s]])),e[a.name]=r),Object.fromEntries(Object.entries(a).filter(([s,d])=>!oe.includes(s)||JSON.stringify(d)!==JSON.stringify(r[s])))}),advisoryRules:e}},dr=` /**
2
2
  * The bare writer every admin/maintenance entry point writes through.
3
3
  *
4
4
  * Admin and maintenance writes go through the SAME reactive-cache hooks as a
@@ -30,7 +30,7 @@ import{LunoraError as At}from"@lunora/errors";import{serializeSchemaSnapshot as
30
30
  schema: schema as unknown as SchemaLike,
31
31
  sql: this.sql as SqlExec,
32
32
  });
33
- }`,m=(n="")=>` const writer = this.adminWriter(${n});`,tr=`${er}
33
+ }`,g=(n="")=>` const writer = this.adminWriter(${n});`,cr=`${dr}
34
34
 
35
35
  protected override async runShardDataMigration(args: RunShardMigrationArgs): Promise<MigrationRunResult> {
36
36
  this.ensureMigrated();
@@ -47,7 +47,7 @@ import{LunoraError as At}from"@lunora/errors";import{serializeSchemaSnapshot as
47
47
  throw new LunoraError("MIGRATION_NOT_FOUND", \`data migration "\${args.id}" is not registered\`, { status: 404 });
48
48
  }
49
49
 
50
- ${m()}
50
+ ${g()}
51
51
 
52
52
  return runDataMigration({
53
53
  ...(args.batchSize === undefined ? {} : { batchSize: args.batchSize }),
@@ -80,7 +80,7 @@ ${m()}
80
80
 
81
81
  this.ensureMigrated();
82
82
 
83
- ${m("headroom ?? this.transactionHeadroom()")}
83
+ ${g("headroom ?? this.transactionHeadroom()")}
84
84
 
85
85
  if (args.op === "insert") {
86
86
  const id = await writer.insert(args.table, args.doc ?? {});
@@ -135,7 +135,7 @@ ${m("headroom ?? this.transactionHeadroom()")}
135
135
  protected override async runShardExport(args: RunShardExportArgs): Promise<ExportRow[]> {
136
136
  this.ensureMigrated();
137
137
 
138
- ${m()}
138
+ ${g()}
139
139
 
140
140
  const rows: ExportRow[] = [];
141
141
 
@@ -152,7 +152,7 @@ ${m()}
152
152
  protected override async runShardImport(args: RunShardImportArgs): Promise<ImportShardResult> {
153
153
  this.ensureMigrated();
154
154
 
155
- ${m()}
155
+ ${g()}
156
156
 
157
157
  // \`importShardRows\` inserts with \`allowExplicitId\`, so a source
158
158
  // database's \`_id\`s carry across verbatim and every foreign key
@@ -163,7 +163,7 @@ ${m()}
163
163
  protected override async runShardRankBefore(args: RunShardRankBeforeArgs): Promise<{ before: number; total: number }> {
164
164
  this.ensureMigrated();
165
165
 
166
- ${m()}
166
+ ${g()}
167
167
 
168
168
  // \`rankBefore\` is optional on \`DatabaseWriterLike\` (the D1 twin omits it),
169
169
  // but the shard writer from \`createShardCtxDb\` always defines it.
@@ -181,7 +181,7 @@ ${m()}
181
181
  protected override async runShardFindRelated(args: RunShardFindRelatedArgs): Promise<RelatedPage> {
182
182
  this.ensureMigrated();
183
183
 
184
- ${m()}
184
+ ${g()}
185
185
 
186
186
  // \`related\` is optional on \`DatabaseWriterLike\` (the D1 twin omits it),
187
187
  // but the shard writer from \`createShardCtxDb\` always defines it — it
@@ -199,7 +199,7 @@ ${m()}
199
199
  protected override async runShardRankPage(args: RunShardRankPageArgs): Promise<ShardRankPageResult> {
200
200
  this.ensureMigrated();
201
201
 
202
- ${m()}
202
+ ${g()}
203
203
 
204
204
  // \`rankPageRows\` is optional on \`DatabaseWriterLike\` (the D1 twin omits it),
205
205
  // but the shard writer from \`createShardCtxDb\` always defines it. The sort
@@ -220,16 +220,18 @@ ${m()}
220
220
  protected override async runShardApplyCdc(args: RunShardApplyCdcArgs): Promise<{ applied: number }> {
221
221
  this.ensureMigrated();
222
222
 
223
- ${m()}
223
+ ${g()}
224
224
 
225
225
  await applyCdcChanges(writer, args.changes);
226
226
 
227
227
  return { applied: args.changes.length };
228
- }`,rr=({actionOnlyBuild:n,actionOnlyFields:e,agentsBuild:t,agentsContextField:a,containersBuild:r,containersContextField:s,databaseOptions:d,everyContextBuild:g,everyContextField:y,facadeBlock:c,globalDatabaseLine:w,notifyBuild:S,ormContextField:E,paymentsBuild:v,paymentsContextField:C,queuesBuild:i,queuesContextField:f,topicsBuild:L,topicsContextField:_,vectorsBuild:I,vectorsContextField:x,workflowsBuild:M,workflowsContextField:P})=>{const k=e.length>0,l=k?`
228
+ }`,lr=({actionOnlyBuild:n,actionOnlyFields:e,agentsBuild:t,agentsContextField:a,containersBuild:r,containersContextField:s,databaseOptions:d,everyContextBuild:f,everyContextField:v,facadeBlock:c,globalDatabaseLine:l,lazyFunctions:p=!1,notifyBuild:L,ormContextField:x,paymentsBuild:k,paymentsContextField:I,queuesBuild:i,queuesContextField:b,topicsBuild:P,topicsContextField:N,vectorsBuild:M,vectorsContextField:O,workflowsBuild:$,workflowsContextField:q})=>{const S=e.length>0,u=x===""?"{ db }":"{ db, orm: bindOrm(facade) }",D=x===""?"":`
229
+ orm: databaseContext.orm,`,w=x===""?"":`
230
+ orm: { configurable: true, enumerable: true, value: mutationDatabase.orm, writable: true },`,F=S?`
229
231
  // ActionCtx-only helpers (external, non-deterministic I/O): constructed
230
232
  // and attached only for an \`action\` so query/mutation ctx never carry them.
231
233
  if (isAction) {
232
- ${n.replaceAll(/^(?=.)/gmu," ")}${e.map(u=>` ctx.${u} = ${u};`).join(`
234
+ ${n.replaceAll(/^(?=.)/gmu," ")}${e.map(R=>` ctx.${R} = ${R};`).join(`
233
235
  `)}
234
236
  }
235
237
  `:"";return` private buildCtx(options: { bookmarks?: DispatchBookmark | undefined; functionPath?: string | undefined; headroom?: TransactionHeadroomTracker | undefined; identity?: SubscriptionIdentity | undefined; kind?: "query" | undefined; onRead?: ((table: string, idOrScan?: string) => void) | undefined; onReadRange?: ((range: KeyRange) => void) | undefined; scope?: QueryReadScope | undefined; trusted?: boolean | undefined } = {}): unknown {
@@ -259,7 +261,7 @@ ${n.replaceAll(/^(?=.)/gmu," ")}${e.map(u=>` ctx.${u} = ${u};`
259
261
  };
260
262
  })();
261
263
  const { identity, ip, userId } = caller;
262
- ${I}${g}${r}${M}${i}${L}${t}
264
+ ${M}${f}${r}${$}${i}${P}${t}
263
265
  // Which dispatch this ctx belongs to. Drives the two deferral facades
264
266
  // below and the \`ctx.run*\` caller guard; a ctx built for an
265
267
  // admin/lifecycle path has no registered function, and so no kind. An
@@ -275,11 +277,9 @@ ${I}${g}${r}${M}${i}${L}${t}
275
277
  // equivalent of an \`afterCommit\` hook, and the SchedulerDO persists the
276
278
  // job the moment it is called — so inside a mutation the call is BUFFERED
277
279
  // and replayed after the transaction commits (a rollback drops it).
278
- // Wrapped on the same dispatches as the deferred-delete queue and for the
279
- // same reason: \`ctx.runMutation\` hands the CALLER's ctx to the callee, so
280
- // a mutation reached from an action schedules through the action's ctx.
281
- // An action's own schedules stay immediate — the window is only open
282
- // while a transaction is (see \`runMutationTransaction\`).
280
+ // Composed mutations get their own facade when the caller is outside
281
+ // a transaction. True nested calls share the enclosing facade and open
282
+ // a nested window. The action's own schedules stay immediate.
283
283
  //
284
284
  // Every kind but \`query\` is wrapped, because \`runMutationTransaction\`
285
285
  // is installed on \`ctx.runMutation\` for every kind but \`query\`: a
@@ -332,12 +332,11 @@ ${I}${g}${r}${M}${i}${L}${t}
332
332
  ]);
333
333
  const storage = makeStorage(requestOrigin);
334
334
  // \`ctx.storage.deleteAfterCommit(key)\`, on every dispatch that can host
335
- // a MUTATION handler — which is not only a mutation dispatch:
336
- // \`ctx.runMutation\` hands the CALLER's ctx to the callee, so a mutation
337
- // reached from an action runs on the action's ctx. Wrapping mutations
338
- // alone made that composition throw a bare TypeError on a method the
339
- // handler's own type promises. Queries stay unwrapped: they cannot host
340
- // one, and their ctx is built on the hot subscription path.
335
+ // a MUTATION handler — which is not only a mutation dispatch. An
336
+ // action's composed mutation gets a child ctx with its own deferred
337
+ // delete queue, while mutations reuse the admitted ctx. Queries stay
338
+ // unwrapped: they cannot host one, and their ctx is built on the hot
339
+ // subscription path.
341
340
  //
342
341
  // Every dispatch wrapped here also flushes (see \`handleRpc\` and
343
342
  // \`runReactor\`) — a queue nothing drains leaks silently, which is worse
@@ -368,13 +367,20 @@ ${I}${g}${r}${M}${i}${L}${t}
368
367
  // so both write to the same trace.
369
368
  const span = this.makeDispatchSpan(traceAnchor, observability);
370
369
 
371
- ${w} // \`ctx.db\`, wrapped in automatic instrumentation: by default this
370
+ ${l} // \`ctx.db\`, wrapped in automatic instrumentation: by default this
372
371
  // adds aggregate counters (call count, total time, per-operation
373
372
  // breakdown) to the wide event rather than a span per call, so a
374
373
  // handler making hundreds of queries stays readable. See
375
374
  // \`instrumentDatabase\` for the \`"spans"\` / \`"off"\` levels.
376
- const db: DatabaseWriterLike = this.instrumentDb(createShardCtxDb(${d}), logFunctionPath, traceAnchor, observability);
377
- ${c}${v}
375
+ // Schema triggers close over this DB's scheduler, so a composed
376
+ // mutation must rebuild its DB and table/ORM views with its own queue.
377
+ const makeDatabaseContext = (scheduler: SchedulerLike) => {
378
+ const db: DatabaseWriterLike = this.instrumentDb(createShardCtxDb(${d}), logFunctionPath, traceAnchor, observability);
379
+ ${c} return ${u};
380
+ };
381
+ const databaseContext = makeDatabaseContext(scheduler);
382
+ const db = databaseContext.db;
383
+ ${k}
378
384
 
379
385
  // \`ctx.trace\` / \`ctx.metrics\`: spans and measurements to the same sink.
380
386
  // The trace anchor is threaded explicitly for the same reason \`identity\`
@@ -382,7 +388,7 @@ ${c}${v}
382
388
  // writing mutation's trace from the shared per-request field.
383
389
  const trace = this.makeTracer(logFunctionPath, observability, traceAnchor);
384
390
  const metrics = this.makeMetrics(logFunctionPath, observability);
385
- ${S}
391
+ ${L}
386
392
  // \`ctx.now\`: the wall-clock instant (epoch ms) this function began,
387
393
  // captured ONCE so the whole handler body sees a single stable value.
388
394
  // A \`query\` handler is re-run by every live subscription that reads it,
@@ -433,21 +439,48 @@ ${S}
433
439
  // to the handler so code that signs its own URLs (a copy-in
434
440
  // \`createStorage\`) can fall back to it too. \`undefined\` for a
435
441
  // query and for a deferred dispatch, for the reasons given there.
436
- origin: requestOrigin,${E}
442
+ origin: requestOrigin,${D}
437
443
  scheduler,
438
444
  span,
439
445
  storage: contextStorage,
440
- trace,${x}${y}${C}${s}${P}${f}${_}${a}
446
+ trace,${O}${v}${I}${s}${q}${b}${N}${a}
447
+ };
448
+ ${S?` const isAction = contextKind === "action";
449
+ `:""}${F}
450
+ ${p?` const captureScope = (): (() => void) => {
451
+ const requestScope = this.captureRequestScope();
452
+ return () => this.restoreRequestScope(requestScope);
441
453
  };
442
- ${k?` const isAction = contextKind === "action";
443
- `:""}${l}
444
- const installRun = (target: Record<string, unknown>, kind: typeof contextKind): void => {
445
- target.runAction = (reference: FunctionReference, fnArgs: Record<string, unknown>) => dispatchRun("action", reference.__lunoraRef, fnArgs, target, kind);
454
+
455
+ `:""} const installRun = (target: Record<string, unknown>, kind: typeof contextKind): void => {
456
+ target.runAction = (reference: FunctionReference, fnArgs: Record<string, unknown>) => dispatchRun("action", reference.__lunoraRef, fnArgs, target, kind${p?", undefined, captureScope":""});
446
457
  // The composed mutation runs under the SAME wrapper the top-level RPC
447
458
  // uses, so "do the transactional work in a mutation and call it from the
448
459
  // action" — the recipe the docs give for atomicity — actually is atomic.
449
- target.runMutation = (reference: FunctionReference, fnArgs: Record<string, unknown>) =>
450
- dispatchRun("mutation", reference.__lunoraRef, fnArgs, target, kind, async (work) => this.runMutationTransaction(target, work));
460
+ target.runMutation = (reference: FunctionReference, fnArgs: Record<string, unknown>) => {
461
+ // An action can start sibling mutations concurrently. Each owns its
462
+ // context and deferral queues; only calls from an admitted mutation
463
+ // inherit that mutation's transaction.
464
+ const mutationCtx: Record<string, unknown> = this.mutationContexts.has(target)
465
+ ? target
466
+ : (() => {
467
+ const mutationScheduler = withDeferredSchedules(schedulerBase, this.scheduleOutbox());
468
+ const mutationDatabase = makeDatabaseContext(mutationScheduler);
469
+
470
+ return Object.defineProperties({}, {
471
+ ...Object.getOwnPropertyDescriptors(target),
472
+ db: { configurable: true, enumerable: true, value: mutationDatabase.db, writable: true },${w}
473
+ scheduler: { configurable: true, enumerable: true, value: mutationScheduler, writable: true },
474
+ storage: { configurable: true, enumerable: true, value: withDeferredDeletes(storage), writable: true },
475
+ });
476
+ })();
477
+
478
+ if (mutationCtx !== target) {
479
+ installRun(mutationCtx, kind);
480
+ }
481
+
482
+ return dispatchRun("mutation", reference.__lunoraRef, fnArgs, mutationCtx, kind, async (work) => this.runMutationTransaction(mutationCtx, work)${p?", captureScope":""});
483
+ };
451
484
  // \`ctx.runQuery(ref, args, { untracked: true })\` runs the sub-query on
452
485
  // its OWN query context, built without the subscription's read-footprint
453
486
  // hooks — so its reads never enter this subscription's footprint and a
@@ -469,7 +502,9 @@ ${k?` const isAction = contextKind === "action";
469
502
  runOptions?.untracked === true
470
503
  ? this.buildCtx({ bookmarks: options.bookmarks, functionPath: options.functionPath, headroom: options.headroom, identity: caller, kind: "query", scope: options.scope })
471
504
  : queryContext(),
472
- kind,
505
+ kind,${p?`
506
+ undefined,
507
+ captureScope,`:""}
473
508
  );
474
509
  };
475
510
 
@@ -491,7 +526,7 @@ ${k?` const isAction = contextKind === "action";
491
526
 
492
527
  if (queryView === undefined) {
493
528
  const descriptors: PropertyDescriptorMap = Object.getOwnPropertyDescriptors(ctx);
494
- ${e.map(u=>` delete descriptors.${u};
529
+ ${e.map(R=>` delete descriptors.${R};
495
530
  `).join("")} // Writable and configurable, like the plain fields they replace.
496
531
  const field = (value: unknown): PropertyDescriptor => ({ configurable: true, enumerable: true, value, writable: true });
497
532
 
@@ -510,7 +545,7 @@ ${e.map(u=>` delete descriptors.${u};
510
545
  installRun(ctx, contextKind);
511
546
 
512
547
  return ctx;
513
- }`},nr=`// Bound in-process \`ctx.run*\` composition depth so a self- or cyclically-
548
+ }`},ie=`// Bound in-process \`ctx.run*\` composition depth so a self- or cyclically-
514
549
  // referencing call fails loudly with a clear error instead of overflowing the
515
550
  // stack. Tracked across the awaited handler chain (one DO invocation is
516
551
  // single-threaded), so the counter reflects true nesting depth.
@@ -576,8 +611,29 @@ const dispatchRun = async (
576
611
  } finally {
577
612
  runDepth -= 1;
578
613
  }
579
- };`,ar=` public override async handleRpc(functionPath: string, args: Record<string, unknown>, headroom?: TransactionHeadroomTracker, scope?: QueryReadScope, bookmarks?: DispatchBookmark): Promise<unknown> {
580
- const registered = LUNORA_FUNCTIONS[functionPath];
614
+ };`,ur=n=>n?ie.replace(" runTransactional?: (work: () => Promise<unknown>) => Promise<unknown>,",` runTransactional?: (work: () => Promise<unknown>) => Promise<unknown>,
615
+ captureScope?: () => () => void,`).replace(` try {
616
+ // A mutation composed from an action`,` try {
617
+ let loaded = getLoadedFunction(functionPath);
618
+
619
+ if (loaded === undefined) {
620
+ const restoreScope = captureScope?.();
621
+
622
+ try {
623
+ loaded = await loadFunction(functionPath);
624
+ } finally {
625
+ restoreScope?.();
626
+ }
627
+ }
628
+
629
+ if (!loaded) {
630
+ throw new Error(\`unknown function: \${functionPath}\`);
631
+ }
632
+
633
+ const loadedFunction = loaded;
634
+
635
+ // A mutation composed from an action`).replaceAll("registered.handler","loadedFunction.handler"):ie,hr=` public override async handleRpc(functionPath: string, args: Record<string, unknown>, headroom?: TransactionHeadroomTracker, scope?: QueryReadScope, bookmarks?: DispatchBookmark): Promise<unknown> {
636
+ __PREPARE_FUNCTION__ const registered = LUNORA_FUNCTIONS[functionPath];
581
637
 
582
638
  // Internal functions are reachable server-side only: via \`ctx.run*\`
583
639
  // composition, or a trusted system dispatch (scheduler/cron, marked by
@@ -631,14 +687,15 @@ const dispatchRun = async (
631
687
 
632
688
  const result = await registered.handler(ctx, args);
633
689
 
634
- // An action is not itself transactional, but \`ctx.runMutation\` runs its
635
- // submutations on THIS ctx, so anything they queued after their own
636
- // transaction settled lands here. A dispatch with nothing queued no-ops.
690
+ // Composed mutations settle their own delete queues. An action can
691
+ // also queue deletes outside those mutations; drain its own queue here.
637
692
  await this.deferPastResponse(flushDeferredDeletes(ctx));
638
693
 
639
694
  return result;
640
695
  }
641
696
 
697
+ private readonly mutationContexts = new WeakSet<object>();
698
+
642
699
  /**
643
700
  * Run one mutation handler with the atomicity every caller of a mutation is
644
701
  * promised: a BEGIN/COMMIT span (with the single-writer gate
@@ -659,11 +716,9 @@ const dispatchRun = async (
659
716
  * scheduler flush.
660
717
  *
661
718
  * Both deferral windows are opened here and settled against the SAME
662
- * outcome. The delete window is what keeps a composed mutation's queued
663
- * object deletes off the caller's flush when it rolls back: \`ctx\` is
664
- * shared, so without a window the keys are indistinguishable from the
665
- * action's own and the action's flush destroys objects whose rows the
666
- * rollback put back.
719
+ * outcome. True nested calls share their caller's context, so each window
720
+ * must discard its own failed delete and schedule intents even when the
721
+ * outer handler catches the error and commits.
667
722
  */
668
723
  private async runMutationTransaction<T>(ctx: unknown, work: () => Promise<T>): Promise<T> {
669
724
  const settleSchedules = beginDeferredSchedules(ctx as { scheduler?: unknown });
@@ -671,7 +726,7 @@ const dispatchRun = async (
671
726
  // settle first on every path and cannot mask the outcome.
672
727
  const settleDeletes = beginDeferredDeletes(ctx);
673
728
 
674
- if (this.isInTransaction()) {
729
+ if (this.mutationContexts.has(ctx as object)) {
675
730
  try {
676
731
  const nested = await work();
677
732
 
@@ -690,7 +745,15 @@ const dispatchRun = async (
690
745
  let result: T;
691
746
 
692
747
  try {
693
- result = await this.runInTransaction(work);
748
+ result = await this.runInTransaction(async () => {
749
+ this.mutationContexts.add(ctx as object);
750
+
751
+ try {
752
+ return await work();
753
+ } finally {
754
+ this.mutationContexts.delete(ctx as object);
755
+ }
756
+ }, { independent: true });
694
757
  } catch (error) {
695
758
  // The span rolled back, so the rows are gone and the jobs that were
696
759
  // to run "after I commit" must go with them. Dropping them is the
@@ -753,14 +816,14 @@ __COMMITTED_CATCH__ } finally {
753
816
  // \`ctx.scheduler\` call that reached the buffer in the first place.
754
817
  protected override scheduleOutboxScheduler(): SchedulerLike | undefined {
755
818
  return config.scheduler?.((this.env ?? {}) as Record<string, unknown>) as SchedulerLike | undefined;
756
- }`,sr=` protected override async executeSubscription(functionPath: string, args: Record<string, unknown>, identity?: SubscriptionIdentity): Promise<{ ranges?: Map<string, KeyRange[]>; result: unknown; tables: Set<string> } | null> {
819
+ }`,pr=` protected override async executeSubscription(functionPath: string, args: Record<string, unknown>, identity?: SubscriptionIdentity): Promise<{ ranges?: Map<string, KeyRange[]>; result: unknown; tables: Set<string> } | null> {
757
820
  const registered = LUNORA_FUNCTIONS[functionPath];
758
821
 
759
822
  if (!registered || registered.kind !== "query" || registered.visibility === "internal") {
760
823
  return null;
761
824
  }
762
825
 
763
- this.ensureMigrated();
826
+ __PREPARE_FUNCTION__ this.ensureMigrated();
764
827
 
765
828
  const footprint = createReadFootprint();
766
829
  // Identity is threaded EXPLICITLY from the (deferred/interleaved)
@@ -794,7 +857,7 @@ __COMMITTED_CATCH__ } finally {
794
857
  // \`ctx.auth\` stream as nobody — or as a concurrent RPC's caller.
795
858
  iterator: (signal) => (registered.handler as (context: unknown, args: Record<string, unknown>, signal: AbortSignal) => AsyncIterable<unknown>)(this.buildCtx({ functionPath, identity }), args, signal),
796
859
  };
797
- }`,or=` } catch (error) {
860
+ }`,mr=` } catch (error) {
798
861
  // The write committed before this failed. Mark the error so the caller can tell
799
862
  // a durable write from a rollback: the rethrow still reaches the caller unchanged.
800
863
  if (typeof error === "object" && error !== null) {
@@ -802,7 +865,24 @@ __COMMITTED_CATCH__ } finally {
802
865
  }
803
866
 
804
867
  throw error;
805
- `,ir=n=>ar.replace("__COMMITTED_CATCH__",n?or:""),dr=n=>{const e={};for(const t of n.tables){const a={};for(const[r,s]of Object.entries(t.shape)){const d=K(s);d.kind==="id"&&d.tableName!==void 0&&(a[r]=d.tableName)}Object.keys(a).length>0&&(e[t.name]=a)}return e},cr=n=>{const e={};for(const t of n.tables){const a=[];for(const[r,s]of Object.entries(t.shape))K(s).kind==="storage"&&a.push(r);a.length>0&&(e[t.name]=a)}return e},lr=n=>{const e={};for(const t of n.tables){const a=[...t.indexes.map(r=>({fields:[...r.fields],name:r.name,type:"index",...r.unique===!0?{unique:!0}:{}})),...t.searchIndexes.map(r=>({fields:[r.field,...r.filterFields??[]],name:r.name,type:"search"})),...(t.geoIndexes??[]).map(r=>({fields:[r.field],name:r.name,type:"geo"})),...t.rankIndexes.map(r=>({fields:r.sortBy.map(s=>s.field),name:r.name,type:"rank"})),...t.vectorIndexes.map(r=>({fields:r.field===void 0?[]:[r.field],name:r.name,type:"vector"}))];a.length>0&&(e[t.name]=a)}return e},hr=n=>{const e=[];for(const t of n.tables)!t.ttl||t.shardMode==="global"||e.push({...t.ttl.after===void 0?{}:{after:t.ttl.after},field:t.ttl.field,...t.softDelete?{softDeleteField:t.softDelete.field}:{},table:t.name});return e},ur=n=>{if(n.kind!=="union"||n.members===void 0||n.members.length===0)return;const e=[];for(const t of n.members){if(t.kind!=="literal"||t.literalValue===void 0)return;try{const a=JSON.parse(t.literalValue);if(typeof a!="string")return;e.push(a)}catch{return}}return e},pr=(n,e,t)=>{const a=K(e),r={name:n,optional:zt(e),type:a.kind};if(a.kind==="id"&&a.tableName!==void 0){r.ref=a.tableName;const d=t.get(n);d!==void 0&&(r.onDelete=d)}a.kind==="storage"&&(r.isStorage=!0,a.bucket!==void 0&&(r.bucket=a.bucket));const s=ur(a);return s!==void 0&&(r.enumValues=s),a.column?.notNull===!1&&(r.nullable=!0),r},mr=n=>{const e={};for(const t of n.tables){const a=[{name:"_id",optional:!1,pk:!0,type:"id"},{name:"_creationTime",optional:!1,type:"number"},...t.commitOrdered===!0?[{name:"_commitSeq",optional:!1,type:"number"}]:[]],r=new Map(t.relations.flatMap(s=>s.kind==="one"?[[s.field,s.onDelete]]:[]));for(const[s,d]of Object.entries(t.shape))a.push(pr(s,d,r));e[t.name]=a}return e},gr=({hasMutators:n,hasShapes:e,rlsData:t})=>{const a=e?`
868
+ `,gr=(n,e=!1)=>{const t=e?` const registeredBeforeLoad = LUNORA_FUNCTIONS[functionPath];
869
+
870
+ if (registeredBeforeLoad?.visibility === "internal" && !this.isSystemDispatch()) {
871
+ throw new LunoraError("FUNCTION_NOT_FOUND", "function not registered: " + functionPath);
872
+ }
873
+
874
+ `:"",a=e?` const requestScope = this.captureRequestScope();
875
+ const preparation = this.prepareFunction(functionPath, "rpc");
876
+
877
+ if (preparation !== undefined) {
878
+ try {
879
+ await preparation;
880
+ } finally {
881
+ this.restoreRequestScope(requestScope);
882
+ }
883
+ }
884
+
885
+ `:"";return hr.replace("__COMMITTED_CATCH__",n?mr:"").replace("__PREPARE_FUNCTION__",`${t}${a}`)},fr=n=>{const e={};for(const t of n.tables){const a={};for(const[r,s]of Object.entries(t.shape)){const d=J(s);d.kind==="id"&&d.tableName!==void 0&&(a[r]=d.tableName)}Object.keys(a).length>0&&(e[t.name]=a)}return e},br=n=>{const e={};for(const t of n.tables){const a=[];for(const[r,s]of Object.entries(t.shape))J(s).kind==="storage"&&a.push(r);a.length>0&&(e[t.name]=a)}return e},wr=n=>{const e={};for(const t of n.tables){const a=[...t.indexes.map(r=>({fields:[...r.fields],name:r.name,type:"index",...r.unique===!0?{unique:!0}:{}})),...t.searchIndexes.map(r=>({fields:[r.field,...r.filterFields??[]],name:r.name,type:"search"})),...(t.geoIndexes??[]).map(r=>({fields:[r.field],name:r.name,type:"geo"})),...t.rankIndexes.map(r=>({fields:r.sortBy.map(s=>s.field),name:r.name,type:"rank"})),...t.vectorIndexes.map(r=>({fields:r.field===void 0?[]:[r.field],name:r.name,type:"vector"}))];a.length>0&&(e[t.name]=a)}return e},yr=n=>{const e=[];for(const t of n.tables)!t.ttl||t.shardMode==="global"||e.push({...t.ttl.after===void 0?{}:{after:t.ttl.after},field:t.ttl.field,...t.softDelete?{softDeleteField:t.softDelete.field}:{},table:t.name});return e},vr=n=>{if(n.kind!=="union"||n.members===void 0||n.members.length===0)return;const e=[];for(const t of n.members){if(t.kind!=="literal"||t.literalValue===void 0)return;try{const a=JSON.parse(t.literalValue);if(typeof a!="string")return;e.push(a)}catch{return}}return e},kr=(n,e,t)=>{const a=J(e),r={name:n,optional:rr(e),type:a.kind};if(a.kind==="id"&&a.tableName!==void 0){r.ref=a.tableName;const d=t.get(n);d!==void 0&&(r.onDelete=d)}a.kind==="storage"&&(r.isStorage=!0,a.bucket!==void 0&&(r.bucket=a.bucket));const s=vr(a);return s!==void 0&&(r.enumValues=s),a.column?.notNull===!1&&(r.nullable=!0),r},Sr=n=>{const e={};for(const t of n.tables){const a=[{name:"_id",optional:!1,pk:!0,type:"id"},{name:"_creationTime",optional:!1,type:"number"},...t.commitOrdered===!0?[{name:"_commitSeq",optional:!1,type:"number"}]:[]],r=new Map(t.relations.flatMap(s=>s.kind==="one"?[[s.field,s.onDelete]]:[]));for(const[s,d]of Object.entries(t.shape))a.push(kr(s,d,r));e[t.name]=a}return e},Rr=({hasMutators:n,hasShapes:e,rlsData:t})=>{const a=e?`
806
886
  protected override resolveShape(name: string, args: Record<string, unknown>, identity?: SubscriptionIdentity): { columns?: readonly string[]; effectiveWhere?: WhereInput; global?: boolean; table: string } | undefined {
807
887
  const shape = LUNORA_SHAPES[name];
808
888
 
@@ -865,14 +945,14 @@ __COMMITTED_CATCH__ } finally {
865
945
 
866
946
  return { ...(shape.columns === undefined ? {} : { columns: shape.columns }), effectiveWhere, global: isGlobal, table: shape.table };
867
947
  }
868
- `:"",r=e?[...new Set(t.policies.filter(c=>c.on==="read"&&c.table!=="").map(c=>c.table))].toSorted((c,w)=>c.localeCompare(w)):[],s=r.length>0?`
948
+ `:"",r=e?[...new Set(t.policies.filter(c=>c.on==="read"&&c.table!=="").map(c=>c.table))].toSorted((c,l)=>c.localeCompare(l)):[],s=r.length>0?`
869
949
  /** Refuses to boot a shape that would replicate around the read policies its table is governed by (\`defineShape({ use })\` is how a shape opts in; \`use: []\` acknowledges an ungoverned one). */
870
950
  assertShapesDeclareReadPolicies(LUNORA_SHAPES, ${JSON.stringify(r)}, (schema as unknown as { rlsMode?: string }).rlsMode === "required");
871
951
  `:"";return{customMutatorOverride:n?`
872
952
  protected override isCustomMutator(functionPath: string): boolean {
873
953
  return LUNORA_MUTATOR_PATHS.has(functionPath);
874
954
  }
875
- `:"",shapeGuardImport:e?"assertShapeShardable, ":"",shapeReadPolicyAssertion:s,shapeReadPolicyImport:s===""?"":"assertShapesDeclareReadPolicies, ",shapeResolveOverride:a}},fr=(n,e)=>n?`
955
+ `:"",shapeGuardImport:e?"assertShapeShardable, ":"",shapeReadPolicyAssertion:s,shapeReadPolicyImport:s===""?"":"assertShapesDeclareReadPolicies, ",shapeResolveOverride:a}},xr=(n,e)=>n?`
876
956
  protected override async readGlobalShapeRows(resolved: { columns?: readonly string[]; effectiveWhere?: WhereInput; global?: boolean; table: string }, identity?: SubscriptionIdentity): Promise<Array<{ doc: Record<string, unknown>; id: string }>> {
877
957
  const env = this.env as Record<string, unknown>;
878
958
  // A shape read performs no writes, so the widened request only needs
@@ -938,7 +1018,7 @@ assertShapesDeclareReadPolicies(LUNORA_SHAPES, ${JSON.stringify(r)}, (schema as
938
1018
 
939
1019
  return globalDb.cdcChangedTables?.(sinceSeq, cursorOnly === undefined ? {} : { cursorOnly });
940
1020
  }
941
- `:"",br=n=>({externalSourceOverride:n?`
1021
+ `:"",Ar=n=>({externalSourceOverride:n?`
942
1022
  protected override async pollExternalSources(trace?: TraceRefLike): Promise<number | undefined> {
943
1023
  const env = (this.env ?? {}) as Record<string, unknown>;
944
1024
  const sourced = Object.entries((schema as unknown as SchemaLike).tables)
@@ -1091,8 +1171,8 @@ assertShapesDeclareReadPolicies(LUNORA_SHAPES, ${JSON.stringify(r)}, (schema as
1091
1171
  `:"",sourceClientCacheConst:n?`
1092
1172
  const sourceClientCache = new WeakMap<object, Map<string, SourceClientLike>>();
1093
1173
  const sourcePollAtCache = new WeakMap<object, Map<string, number>>();
1094
- `:""}),yr=(n,e)=>{const t=e.length>0,r=n?T("vectorsStub: VectorSearchLike","ctx.vectors: no vectors configured. Pass `vectors` to createShardDO().",["deleteByIds","getByIds","query","upsert","upsertMany","upsertNow"]):"",s=t?` const vectorShardKey = this.currentShardKey();
1095
- `:"",d=t?"namespace: vectorShardKey === ROOT_SHARD_NAME ? undefined : vectorShardKey, ":"",y=`, { ${["deferAfterCommit: (work) => this.deferAfterCommit(work)",...t?["namespace: vectorShardKey === ROOT_SHARD_NAME ? undefined : vectorShardKey",`shardedIndexNames: [${e.map(S=>JSON.stringify(S)).join(", ")}]`]:[]].join(", ")} }`,c=n?`
1174
+ `:""}),Or=(n,e)=>{const t=e.length>0,r=n?_("vectorsStub: VectorSearchLike","ctx.vectors: no vectors configured. Pass `vectors` to createShardDO().",["deleteByIds","getByIds","query","upsert","upsertMany","upsertNow"]):"",s=t?` const vectorShardKey = this.currentShardKey();
1175
+ `:"",d=t?"namespace: vectorShardKey === ROOT_SHARD_NAME ? undefined : vectorShardKey, ":"",v=`, { ${["deferAfterCommit: (work) => this.deferAfterCommit(work)",...t?["namespace: vectorShardKey === ROOT_SHARD_NAME ? undefined : vectorShardKey",`shardedIndexNames: [${e.map(p=>JSON.stringify(p)).join(", ")}]`]:[]].join(", ")} }`,c=n?`
1096
1176
  const vectorSync = this.vectorSync(env);
1097
1177
  // Vectorize lives outside this shard's SQLite, so a query whose result
1098
1178
  // depends on a similarity search cannot be proven current on reconnect —
@@ -1109,7 +1189,7 @@ const sourcePollAtCache = new WeakMap<object, Map<string, number>>();
1109
1189
  }
1110
1190
 
1111
1191
  const lunora = createVectors({ indexes: config.vectors(env) });
1112
- ${s} const vectors = createContextVectors(lunora${y});
1192
+ ${s} const vectors = createContextVectors(lunora${v});
1113
1193
 
1114
1194
  return {
1115
1195
  backfill: createVectorBackfillSync({ ${d}schema: schema as unknown as VectorSchemaLike, upsertMany: lunora.upsertMany, vectors }),
@@ -1135,14 +1215,14 @@ ${s} const vectors = createContextVectors(lunora${y});
1135
1215
  ordered: async (read, work) => this.runOrderedAfterWrites(read, work),
1136
1216
  });
1137
1217
  }
1138
- `:"",vectorsBuild:c,vectorsStub:r}},Lr=({advisories:n=[],advisorProcedures:e=[],agents:t=[],capabilities:a=new Set,containers:r=[],env:s,flagKeys:d=[],hasFlags:g=!1,hasNotify:y=!1,hasRooms:c=!1,hasVectors:w=!0,maskMetadata:S,mutators:E=[],queues:v=[],rlsMetadata:C,schema:i,schemaSnapshot:f,shapes:L=[],storageRules:_,studioFeatures:I,services:x=[],topics:M=[],useUmbrella:P=!1,workflows:k=[]})=>{const l=Jt(P),N=E.length>0,u=L.length>0,re=f===void 0?"":Ot(f),ne=f===void 0?"":`
1218
+ `:"",vectorsBuild:c,vectorsStub:r}},Fr=({advisories:n=[],advisorProcedures:e=[],agents:t=[],capabilities:a=new Set,containers:r=[],env:s,flagKeys:d=[],hasFlags:f=!1,hasNotify:v=!1,hasRooms:c=!1,lazyFunctions:l=!1,hasVectors:p=!0,maskMetadata:L,mutators:x=[],queues:k=[],rlsMetadata:I,schema:i,schemaSnapshot:b,shapes:P=[],storageRules:N,studioFeatures:M,services:O=[],topics:$=[],useUmbrella:q=!1,workflows:S=[]})=>{const u=ar(q),D=x.length>0,w=P.length>0,F=b===void 0?"":Pt(b),z=b===void 0?"":`
1139
1219
  /** Structural schema snapshot + its content hash, recorded in the shard's \`__lunora_schema_history\` ledger on cold start so the studio can show a schema-version timeline and diff any two versions. */
1140
- const LUNORA_SCHEMA_SNAPSHOT: { hash: string; json: string } = { hash: ${JSON.stringify(Dt(f))}, json: ${JSON.stringify(re)} };
1141
- `,ae=f===void 0?"":", schemaSnapshot: LUNORA_SCHEMA_SNAPSHOT",b=Lt(a),A=_t(g,l.flags),$=It(d,g,l.flags),q=Gt(y),F=Mt(s),{build:se,contextField:oe,importLines:ie,specs:de}=Pt(Yt(v)),{build:ce,contextField:le,importLines:he,specs:ue}=Nt(M,v),U=$t(x,l.server),{build:pe,contextField:me,importLines:ge,specs:fe}=qt(r,i.jurisdiction),{build:be,contextField:ye,importLines:we,specs:ve}=Ft(k),{build:ke,contextField:Se,importLines:Re,specs:xe}=Ut(t),{build:Ae,configField:Oe,contextField:De,imports:Te,stub:Ee}=Bt(a.has("payments")),Ce=n,{advisoryRules:Le,advisoryRows:_e}=Zt(Ce),Ie=e,G=C??{policies:[],roles:[]},Me=S??{columns:[]},Pe=_??{rules:[]},Ne=I??{analytics:!1,auth:!1,containers:!1,flags:!1,kv:!1,mail:!1,notifications:!1,payments:!1,privacy:!1,queues:!1,scheduler:!1,storage:!1,vectors:!1,workflows:!1},{constant:$e,override:qe}=Wt(k),{constant:Fe,override:Ue}=jt(v),p=w&&i.vectorIndexes.length>0,B=new Set(i.tables.filter(o=>Xt(o)).map(o=>o.name)),z=p&&i.vectorIndexes.some(o=>B.has(o.table)),R=i.tables.some(o=>o.shardMode==="global"),W=Ht(B),j=i.tables.some(o=>Tt(o)),Q=i.tables.some(o=>Et(o)),O=i.tables.some(o=>o.externalSource!==void 0),J=i.tables.some(o=>o.memory===!0),H=i.tables.some(o=>o.shardMode!=="global"&&o.searchIndexes.length>0);if(Q&&j)throw new At("INTERNAL",'lunora codegen: mixing `.global()` (D1) and `.global({ backend: "hyperdrive" })` tables in one app is not supported yet — use a single global backend.');const V=i.tables.length>0,Be=dr(i),We=lr(i),je=mr(i),He=cr(i),Y=hr(i),X=Vt(p,k.length>0,v.length>0,g,H);u&&X.push("WhereInput");const Z=Kt(R),{customMutatorOverride:Ve,shapeGuardImport:Ke,shapeReadPolicyAssertion:Ge,shapeReadPolicyImport:ze,shapeResolveOverride:Qe}=gr({hasMutators:N,hasShapes:u,rlsData:G}),D=[`import type { ${X.join(", ")} } from "${l.do}";`,`import { applyCdcChanges, createStableIdFactory, ${H?"backfillSearchIndexes, ":""}${p?"backfillVectorIndexes, ":""}buildReprojectionMigration, ${J?"clearMemoryTables, ":""}${Ke}createReadFootprint, createShardCtxDb, exportShardRows, importShardRows, ${O?"isSourceDue, pullExternalSourceIncrementalTick, pullExternalSourceTick, ":""}markUnvouchableReads, ${z?"ROOT_SHARD_NAME, ":""}runDataMigration, runShardMigrations, ${Z.importFragment}ShardDO as ShardDOBase } from "${l.do}";`,...O?[`import type { ExternalSourceLike, SourceClientLike, TraceRefLike } from "${l.do}";`]:[],u?`import { asBucketStorage, ${ze}beginDeferredDeletes, beginDeferredSchedules, composeShapeReadWhere, createSecrets, flushDeferredDeletes, LunoraError, withDeferredDeletes, withDeferredSchedules } from "${l.server}";`:`import { asBucketStorage, beginDeferredDeletes, beginDeferredSchedules, createSecrets, flushDeferredDeletes, LunoraError, withDeferredDeletes, withDeferredSchedules } from "${l.server}";`];V&&D.push(`import { bindOrm, bindTableFacade } from "${l.server}";`),p&&D.push('import type { SchemaLike as VectorSchemaLike, VectorBackfillSync, VectorizeIndexLike, VectorSearchLike } from "@lunora/bindings/vectors";','import { createContextVectors, createVectorBackfillSync, createVectors, createVectorSyncHook, vectorBackfillTargets } from "@lunora/bindings/vectors";'),D.push(...b.importLines,...A.importLines,...q.importLines,...F.importLines,...ge,...we,...ie,...he,...U.importLines,...Re,...Te,"",'import schema from "../schema.js";',`import { ${["LUNORA_FUNCTIONS","LUNORA_LIFECYCLE_HOOKS","LUNORA_MIGRATIONS",...N?["LUNORA_MUTATOR_PATHS"]:[],...c?["LUNORA_ROOMS"]:[],...u?["LUNORA_SHAPES"]:[]].join(", ")} } from "./functions.js";`);const Je=p?`
1142
- vectors?: (env: Record<string, unknown>) => Record<string, VectorizeIndexLike>;`:"",Ye=Q?`
1143
- d1?: (env: Record<string, unknown>, request?: { bookmark?: string; cdc?: boolean; cdcRetentionMs?: number; identity?: Record<string, unknown>; onBookmark?: (bookmark: string | undefined) => void; userId?: string }) => DatabaseWriterLike | undefined;`:"",Xe=j?`
1144
- hyperdriveGlobal?: (env: Record<string, unknown>, request?: { cdc?: boolean; cdcRetentionMs?: number; identity?: Record<string, unknown>; userId?: string }) => DatabaseWriterLike | undefined;`:"",Ze=O?`
1145
- sourceClient?: (env: Record<string, unknown>, binding: string) => { query: <Row = Record<string, unknown>>(text: string, params?: readonly unknown[]) => Promise<Row[]> } | undefined;`:"",et="ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().",tt="ctx.scheduler: no scheduler configured. Pass `scheduler` to createShardDO().",rt="ctx.storage: no storage configured. Pass `storage` to createShardDO().",nt=R?T("globalDbStub: DatabaseWriterLike",et,["aggregate","count","delete","explain","findFirst","findFirstOrThrow","findMany","get","groupBy","insert","normalizeId","patch","query","rank","rankPage","replace"],{sync:["normalizeId","query"]}):"",{vectorSyncMethod:at,vectorsBuild:st,vectorsStub:ot}=yr(p,z?i.vectorIndexes.filter(o=>B.has(o.table)).map(o=>o.name):[]),it=`{
1220
+ const LUNORA_SCHEMA_SNAPSHOT: { hash: string; json: string } = { hash: ${JSON.stringify(Nt(b))}, json: ${JSON.stringify(F)} };
1221
+ `,R=b===void 0?"":", schemaSnapshot: LUNORA_SCHEMA_SNAPSHOT",y=Ft(a),T=Ut(f,u.flags),U=Bt(d,f,u.flags),B=tr(v),j=jt(s),{build:de,contextField:ce,importLines:le,specs:ue}=Wt(sr(k)),{build:he,contextField:pe,importLines:me,specs:ge}=Ht($,k),W=Vt(O,u.server),{build:fe,contextField:be,importLines:we,specs:ye}=Kt(r,i.jurisdiction),{build:ve,contextField:ke,importLines:Se,specs:Re}=Gt(S),{build:xe,contextField:Ae,importLines:Oe,specs:De}=Qt(t),{build:Te,configField:Ce,contextField:Ee,imports:_e,stub:Le}=Jt(a.has("payments")),Ie=n,{advisoryRules:Pe,advisoryRows:Ne}=ir(Ie),Me=e,Y=I??{policies:[],roles:[]},$e=L??{columns:[]},qe=N??{rules:[]},Fe=M??{analytics:!1,auth:!1,containers:!1,flags:!1,kv:!1,mail:!1,notifications:!1,payments:!1,privacy:!1,queues:!1,scheduler:!1,storage:!1,vectors:!1,workflows:!1},{constant:Ue,override:Be}=zt(S),{constant:je,override:We}=Yt(k),m=p&&i.vectorIndexes.length>0,H=new Set(i.tables.filter(o=>or(o)).map(o=>o.name)),X=m&&i.vectorIndexes.some(o=>H.has(o.table)),A=i.tables.some(o=>o.shardMode==="global"),V=Xt(H),K=i.tables.some(o=>Mt(o)),Z=i.tables.some(o=>$t(o)),C=i.tables.some(o=>o.externalSource!==void 0),ee=i.tables.some(o=>o.memory===!0),G=i.tables.some(o=>o.shardMode!=="global"&&o.searchIndexes.length>0);if(Z&&K)throw new It("INTERNAL",'lunora codegen: mixing `.global()` (D1) and `.global({ backend: "hyperdrive" })` tables in one app is not supported yet — use a single global backend.');const Q=i.tables.length>0,He=fr(i),Ve=wr(i),Ke=Sr(i),Ge=br(i),te=yr(i),re=Zt(m,S.length>0,k.length>0,f,G);w&&re.push("WhereInput");const ne=er(A),{customMutatorOverride:Qe,shapeGuardImport:Je,shapeReadPolicyAssertion:ze,shapeReadPolicyImport:Ye,shapeResolveOverride:Xe}=Rr({hasMutators:D,hasShapes:w,rlsData:Y}),E=[`import type { ${re.join(", ")} } from "${u.do}";`,`import { applyCdcChanges, createStableIdFactory, ${G?"backfillSearchIndexes, ":""}${m?"backfillVectorIndexes, ":""}buildReprojectionMigration, ${ee?"clearMemoryTables, ":""}${Je}createReadFootprint, createShardCtxDb, exportShardRows, importShardRows, ${C?"isSourceDue, pullExternalSourceIncrementalTick, pullExternalSourceTick, ":""}markUnvouchableReads, ${X?"ROOT_SHARD_NAME, ":""}runDataMigration, runShardMigrations, ${ne.importFragment}ShardDO as ShardDOBase } from "${u.do}";`,...C?[`import type { ExternalSourceLike, SourceClientLike, TraceRefLike } from "${u.do}";`]:[],w?`import { asBucketStorage, ${Ye}beginDeferredDeletes, beginDeferredSchedules, composeShapeReadWhere, createSecrets, flushDeferredDeletes, LunoraError, withDeferredDeletes, withDeferredSchedules } from "${u.server}";`:`import { asBucketStorage, beginDeferredDeletes, beginDeferredSchedules, createSecrets, flushDeferredDeletes, LunoraError, withDeferredDeletes, withDeferredSchedules } from "${u.server}";`];Q&&E.push(`import { bindOrm, bindTableFacade } from "${u.server}";`),m&&E.push('import type { SchemaLike as VectorSchemaLike, VectorBackfillSync, VectorizeIndexLike, VectorSearchLike } from "@lunora/bindings/vectors";','import { createContextVectors, createVectorBackfillSync, createVectors, createVectorSyncHook, vectorBackfillTargets } from "@lunora/bindings/vectors";'),E.push(...y.importLines,...T.importLines,...B.importLines,...j.importLines,...we,...Se,...le,...me,...W.importLines,...Oe,..._e,"",'import schema from "../schema.js";',`import { ${["LUNORA_FUNCTIONS","LUNORA_LIFECYCLE_HOOKS","LUNORA_MIGRATIONS",...l?["getLoadedFunction","loadFunction"]:[],...D?["LUNORA_MUTATOR_PATHS"]:[],...c?["LUNORA_ROOMS"]:[],...w?["LUNORA_SHAPES"]:[]].join(", ")} } from "./functions.js";`);const Ze=m?`
1222
+ vectors?: (env: Record<string, unknown>) => Record<string, VectorizeIndexLike>;`:"",et=Z?`
1223
+ d1?: (env: Record<string, unknown>, request?: { bookmark?: string; cdc?: boolean; cdcRetentionMs?: number; identity?: Record<string, unknown>; onBookmark?: (bookmark: string | undefined) => void; userId?: string }) => DatabaseWriterLike | undefined;`:"",tt=K?`
1224
+ hyperdriveGlobal?: (env: Record<string, unknown>, request?: { cdc?: boolean; cdcRetentionMs?: number; identity?: Record<string, unknown>; userId?: string }) => DatabaseWriterLike | undefined;`:"",rt=C?`
1225
+ sourceClient?: (env: Record<string, unknown>, binding: string) => { query: <Row = Record<string, unknown>>(text: string, params?: readonly unknown[]) => Promise<Row[]> } | undefined;`:"",nt="ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().",at="ctx.scheduler: no scheduler configured. Pass `scheduler` to createShardDO().",st="ctx.storage: no storage configured. Pass `storage` to createShardDO().",ot=A?_("globalDbStub: DatabaseWriterLike",nt,["aggregate","count","delete","explain","findFirst","findFirstOrThrow","findMany","get","groupBy","insert","normalizeId","patch","query","rank","rankPage","replace"],{sync:["normalizeId","query"]}):"",{vectorSyncMethod:it,vectorsBuild:dt,vectorsStub:ct}=Or(m,X?i.vectorIndexes.filter(o=>H.has(o.table)).map(o=>o.name):[]),lt=`{
1146
1226
  ...this.ctxDbTuning(),
1147
1227
  auth: { identity: identity ?? null, userId: userId ?? null },
1148
1228
  broadcast: (delta) => {
@@ -1182,7 +1262,7 @@ const LUNORA_SCHEMA_SNAPSHOT: { hash: string; json: string } = { hash: ${JSON.st
1182
1262
  // fallback rather than reporting into a no-op.
1183
1263
  ...(options.onReadRange !== undefined
1184
1264
  ? { onReadRange: options.onReadRange }
1185
- : options.scope === undefined ? {} : { onReadRange: this.getCtxDbReadRangeHook(options.scope) }),${p?`
1265
+ : options.scope === undefined ? {} : { onReadRange: this.getCtxDbReadRangeHook(options.scope) }),${m?`
1186
1266
  // Vectorize is outside this shard's SQLite and cannot roll back, so
1187
1267
  // the sync is held until the mutation's transaction has COMMITTED
1188
1268
  // (\`deferAfterCommit\`) instead of running inline. Inline, a write
@@ -1194,11 +1274,11 @@ const LUNORA_SCHEMA_SNAPSHOT: { hash: string; json: string } = { hash: ${JSON.st
1194
1274
  scheduler,
1195
1275
  schema: schema as unknown as SchemaLike,
1196
1276
  sql: this.sql as SqlExec,
1197
- storage,${R?`
1277
+ storage,${A?`
1198
1278
  globalDb,`:""}
1199
- }`,dt=p?`
1200
- vectors,`:"",ct=V?`
1201
- orm: bindOrm(facade),`:"",ee=j?"config.hyperdriveGlobal":"config.d1",lt=R?` const bookmark = this.getInboundBookmark();
1279
+ }`,ut=m?`
1280
+ vectors,`:"",ht=Q?`
1281
+ orm: bindOrm(facade),`:"",ae=K?"config.hyperdriveGlobal":"config.d1",pt=A?` const bookmark = this.getInboundBookmark();
1202
1282
  const globalRequest = {
1203
1283
  ...this.globalCdcOptions(config.cdc ?? false),
1204
1284
  ...(bookmark === undefined ? {} : { bookmark }),
@@ -1206,23 +1286,23 @@ const LUNORA_SCHEMA_SNAPSHOT: { hash: string; json: string } = { hash: ${JSON.st
1206
1286
  onBookmark: (bookmarkValue: string | undefined) => { if (options.bookmarks !== undefined) { options.bookmarks.value = bookmarkValue; } },
1207
1287
  ...(userId === undefined ? {} : { userId }),
1208
1288
  };
1209
- const globalDb: DatabaseWriterLike = ${ee}?.(env, globalRequest) ?? globalDbStub;
1210
- `:"",ht=fr(u&&R,ee),ut=c?` protected override roomHandlerPath(topic: string): string | undefined {
1289
+ const globalDb: DatabaseWriterLike = ${ae}?.(env, globalRequest) ?? globalDbStub;
1290
+ `:"",mt=xr(w&&A,ae),gt=c?` protected override roomHandlerPath(topic: string): string | undefined {
1211
1291
  // Own properties only: a plain object would resolve \`toString\` and the like to inherited functions.
1212
1292
  return Object.hasOwn(LUNORA_ROOMS, topic) ? LUNORA_ROOMS[topic] : undefined;
1213
1293
  }
1214
- `:"",{externalSourceOverride:pt,sourceBootstrap:mt,sourceClientCacheConst:gt}=br(O),ft=`
1294
+ `:"",{externalSourceOverride:ft,sourceBootstrap:bt,sourceClientCacheConst:wt}=Ar(C),yt=`
1215
1295
  protected override async runShardInit(): Promise<void> {
1216
1296
  this.ensureMigrated();
1217
- ${J?` clearMemoryTables(this.sql as SqlExec, schema as unknown as SchemaLike);
1297
+ ${ee?` clearMemoryTables(this.sql as SqlExec, schema as unknown as SchemaLike);
1218
1298
  `:""}
1219
1299
  await this.dispatchShardInit();
1220
1300
  }
1221
- `,bt=Y.length>0?`
1301
+ `,vt=te.length>0?`
1222
1302
  if (LUNORA_TTL_SWEEPS.length > 0) {
1223
1303
  void this.scheduleTtlSweep();
1224
1304
  }
1225
- `:"",yt=`
1305
+ `:"",kt=`
1226
1306
  public constructor(state: ShardDOState, env: unknown) {
1227
1307
  super(state, env, {
1228
1308
  // Every writer this file builds spreads the ctxDbTuning() slice —
@@ -1239,7 +1319,7 @@ ${J?` clearMemoryTables(this.sql as SqlExec, schema as unknown as Sch
1239
1319
  // exists — a trigger that fails first still flushes and fuses.
1240
1320
  ...(config.observability === undefined ? {} : { telemetrySink: () => config.observability?.((env ?? {}) as Record<string, unknown>) }),
1241
1321
  });
1242
- ${mt}${bt} }
1322
+ ${bt}${vt} }
1243
1323
 
1244
1324
  protected override isCacheableQuery(functionPath: string): boolean {
1245
1325
  // NOT \`kind === "query"\` alone. A cache hit answers without running
@@ -1263,14 +1343,34 @@ ${mt}${bt} }
1263
1343
  protected override isPaidFunction(functionPath: string): boolean {
1264
1344
  return LUNORA_FUNCTIONS[functionPath]?.x402 !== undefined;
1265
1345
  }
1266
- `,wt=V?`
1346
+ `,se=l?`
1347
+ protected override prepareFunction(functionPath: string, reason: "rpc" | "subscription" | "stream" | "reactor"): Promise<void> | undefined {
1348
+ const registered = LUNORA_FUNCTIONS[functionPath];
1349
+ const allowsInternal = reason === "reactor" || (reason === "rpc" && this.isSystemDispatch());
1350
+
1351
+ if (registered?.visibility === "internal" && !allowsInternal) {
1352
+ return;
1353
+ }
1354
+
1355
+ if (getLoadedFunction(functionPath) !== undefined) {
1356
+ return;
1357
+ }
1358
+
1359
+ return loadFunction(functionPath).then(() => undefined);
1360
+ }
1361
+ `:"",St=se===""?`
1362
+
1363
+ `:`${se}
1364
+ `,Rt=ur(l),xt=l?` const preparation = this.prepareFunction(functionPath, "subscription");
1365
+ if (preparation !== undefined) await preparation;
1366
+ `:"",At=pr.replace("__PREPARE_FUNCTION__",xt),Ot=gr(c,l),Dt=Q?`
1267
1367
  const facade = db as unknown as Record<string, ReturnType<typeof bindTableFacade>>;
1268
1368
  ${i.tables.map(o=>` facade[${JSON.stringify(o.name)}] = bindTableFacade(db, ${JSON.stringify(o.name)});`).join(`
1269
1369
  `)}
1270
- `:"",vt=`${b.everyBuild}${A.build}${F.build}
1370
+ `:"",Tt=`${y.everyBuild}${T.build}${j.build}
1271
1371
  const secrets = createSecrets(env);
1272
- `,kt=`${b.everyFields}${A.contextField}${q.contextField}${F.contextField}
1273
- secrets,`,St=q.build,Rt=[...b.actionFields,...x.length>0?["services"]:[]],xt=`${b.actionBuild}${U.build}`;return`${Qt}${D.join(`
1372
+ `,Ct=`${y.everyFields}${T.contextField}${B.contextField}${j.contextField}
1373
+ secrets,`,Et=B.build,_t=[...y.actionFields,...O.length>0?["services"]:[]],Lt=`${y.actionBuild}${W.build}`;return`${nr}${E.join(`
1274
1374
  `)}
1275
1375
 
1276
1376
  type FunctionKind = "action" | "mutation" | "query";
@@ -1280,13 +1380,13 @@ interface FunctionReference {
1280
1380
  }
1281
1381
 
1282
1382
  /** Foreign-key columns per table (\`v.id("target")\` fields) for the data browser. */
1283
- const LUNORA_TABLE_REFS = ${h(Be,"Record<string, Record<string, string>>")};
1383
+ const LUNORA_TABLE_REFS = ${h(He,"Record<string, Record<string, string>>")};
1284
1384
 
1285
1385
  /** Declared indexes per table (secondary, search, geo, rank, vector) for the schema viewer. */
1286
- const LUNORA_TABLE_INDEXES = ${h(We,'Record<string, Array<{ fields: string[]; name: string; type: "geo" | "index" | "rank" | "search" | "vector"; unique?: boolean }>>')};
1386
+ const LUNORA_TABLE_INDEXES = ${h(Ve,'Record<string, Array<{ fields: string[]; name: string; type: "geo" | "index" | "rank" | "search" | "vector"; unique?: boolean }>>')};
1287
1387
 
1288
1388
  /** Columns per table (typed, with PK/FK markers) for the studio's schema diagram, served via \`__lunora_admin__:describeTable\`. */
1289
- const LUNORA_TABLE_COLUMNS = ${h(je,`Record<
1389
+ const LUNORA_TABLE_COLUMNS = ${h(Ke,`Record<
1290
1390
  string,
1291
1391
  Array<{
1292
1392
  bucket?: string;
@@ -1303,16 +1403,16 @@ const LUNORA_TABLE_COLUMNS = ${h(je,`Record<
1303
1403
  >`)};
1304
1404
 
1305
1405
  /** Storage-key columns per table (\`v.storage(...)\` fields) for the file browser's records↔files join. */
1306
- const LUNORA_STORAGE_COLUMNS = ${h(He,"Record<string, string[]>")};
1406
+ const LUNORA_STORAGE_COLUMNS = ${h(Ge,"Record<string, string[]>")};
1307
1407
 
1308
1408
  /** Declarative TTL policies (\`.ttl(field, { after? })\`) the DO alarm sweep auto-expires rows for. */
1309
- const LUNORA_TTL_SWEEPS = ${Ct(Y,"Array<{ after?: number; field: string; softDeleteField?: string; table: string }>")};
1409
+ const LUNORA_TTL_SWEEPS = ${qt(te,"Array<{ after?: number; field: string; softDeleteField?: string; table: string }>")};
1310
1410
 
1311
1411
  /** Static schema advisories (computed by @lunora/advisor at codegen time) served via \`__lunora_admin__:getAdvisories\`. */
1312
- const LUNORA_ADVISORY_RULES = ${h(Le,"Record<string, Partial<AdvisoryFinding>>")};
1412
+ const LUNORA_ADVISORY_RULES = ${h(Pe,"Record<string, Partial<AdvisoryFinding>>")};
1313
1413
 
1314
1414
  /** Per-finding rows; rule-level text lives once in \`LUNORA_ADVISORY_RULES\` and is merged back on first read. */
1315
- const LUNORA_ADVISORY_ROWS = ${h(_e,"Array<Partial<AdvisoryFinding> & { name: string }>")};
1415
+ const LUNORA_ADVISORY_ROWS = ${h(Ne,"Array<Partial<AdvisoryFinding> & { name: string }>")};
1316
1416
 
1317
1417
  const LUNORA_ADVISORIES = ((): (() => AdvisoryFinding[]) => {
1318
1418
  let cached: AdvisoryFinding[] | undefined;
@@ -1320,20 +1420,20 @@ const LUNORA_ADVISORIES = ((): (() => AdvisoryFinding[]) => {
1320
1420
  })();
1321
1421
 
1322
1422
  /** Every declared procedure (discovered by @lunora/codegen) served via \`__lunora_admin__:getAdvisorProcedures\` — the health map's denominator. */
1323
- const LUNORA_ADVISOR_PROCEDURES = ${h(Ie,"AdvisorProcedure[]")};
1423
+ const LUNORA_ADVISOR_PROCEDURES = ${h(Me,"AdvisorProcedure[]")};
1324
1424
 
1325
1425
  /** Read-only RLS metadata (policies + roles discovered from \`.use(rls(...))\` chains) served via \`__lunora_admin__:rlsPolicies\` for the studio's RLS inspector. */
1326
- const LUNORA_RLS_METADATA = ${h(G,"RlsPoliciesResult")};
1327
- ${Ge}
1426
+ const LUNORA_RLS_METADATA = ${h(Y,"RlsPoliciesResult")};
1427
+ ${ze}
1328
1428
  /** Read-only masking metadata (table + column + strategy discovered from \`.use(mask(...))\` chains) served via \`__lunora_admin__:maskPolicies\` for the studio's data-browser mask preview. */
1329
- const LUNORA_MASK_METADATA = ${h(Me,"MaskPoliciesResult")};
1429
+ const LUNORA_MASK_METADATA = ${h($e,"MaskPoliciesResult")};
1330
1430
 
1331
1431
  /** Read-only storage access-rule metadata (discovered from \`.use(storageRules(...))\` chains) served via \`__lunora_admin__:storageRules\` for the studio's access-rules view. */
1332
- const LUNORA_STORAGE_RULES = ${h(Pe,"StorageRulesResult")};
1432
+ const LUNORA_STORAGE_RULES = ${h(qe,"StorageRulesResult")};
1333
1433
 
1334
1434
  /** Which optional package-backed features this app wires up (discovered from imports / \`ctx.*\` reads / schema signals) served via \`__lunora_admin__:studioFeatures\` so the studio hides nav pages whose package isn't enabled. */
1335
- const LUNORA_STUDIO_FEATURES = ${h(Ne,"StudioFeaturesResult")};
1336
- ${ne}${W.constant}${$.constant}${$e}${Fe}${fe}${ve}${de}${ue}${U.specs}${xe}
1435
+ const LUNORA_STUDIO_FEATURES = ${h(Fe,"StudioFeaturesResult")};
1436
+ ${z}${V.constant}${U.constant}${Ue}${je}${ye}${Re}${ue}${ge}${W.specs}${De}
1337
1437
  export interface ShardDOConfig {
1338
1438
  /** Current authority for RPC and ordinary subscription deliveries; other live delivery modes are refused. */
1339
1439
  deliveryAuthorization?: (env: Record<string, unknown>) => DeliveryAuthorization;
@@ -1350,27 +1450,25 @@ export interface ShardDOConfig {
1350
1450
  /** \`unknown\` because \`@lunora/scheduler\`'s \`Scheduler\` is not assignable to \`SchedulerLike\`; the shard casts it. */
1351
1451
  scheduler?: (env: Record<string, unknown>) => unknown;
1352
1452
  /** \`origin\` is the origin the current \`/rpc\` request reached the worker on — the fallback base for signed object URLs when no \`publicBaseUrl\` is configured. \`undefined\` off the synchronous dispatch path. */
1353
- storage?: (env: Record<string, unknown>, origin?: string) => unknown;${Je}${b.configFields}${A.configField}${Oe}${Ye}${Xe}${Ze}${W.configField}
1453
+ storage?: (env: Record<string, unknown>, origin?: string) => unknown;${Ze}${y.configFields}${T.configField}${Ce}${et}${tt}${rt}${V.configField}
1354
1454
  }
1355
- ${T("schedulerStub",tt,["cancel","runAfter","runAt"])}${T("storageStub",rt,["createMultipartUpload","delete","download","generateUploadUrl","getMetadata","getPresignedUrl","getSignedUrl","getUrl","head","list","resumeMultipartUpload","store","upload"],{sync:["getUrl","resumeMultipartUpload"]})}${nt}${gt}${ot}${b.stubs}${Ee}
1356
- ${nr}
1455
+ ${_("schedulerStub",at,["cancel","runAfter","runAt"])}${_("storageStub",st,["createMultipartUpload","delete","download","generateUploadUrl","getMetadata","getPresignedUrl","getSignedUrl","getUrl","head","list","resumeMultipartUpload","store","upload"],{sync:["getUrl","resumeMultipartUpload"]})}${ot}${wt}${ct}${y.stubs}${Le}
1456
+ ${Rt}
1357
1457
 
1358
1458
  /**
1359
1459
  * Build the project's shard Durable Object. Export the result as \`ShardDO\`
1360
1460
  * from the worker entry so wrangler binds it by name.
1361
1461
  */
1362
1462
  export const createShardDO = (config: ShardDOConfig = {}): new (state: ShardDOState, env: unknown) => ShardDOBase =>
1363
- class extends ShardDOBase {${yt}
1364
- private migrated = false;
1365
-
1366
- ${ir(c)}
1367
- ${Z.override}
1368
- ${sr}
1369
- ${Ve}${Qe}${ht}${pt}
1463
+ class extends ShardDOBase {${kt}
1464
+ private migrated = false;${St}${Ot}
1465
+ ${ne.override}
1466
+ ${At}
1467
+ ${Qe}${Xe}${mt}${ft}
1370
1468
  protected override lifecycleHookPaths(event: "connect" | "disconnect" | "init" | "reactor" | "whisper"): readonly string[] {
1371
1469
  return LUNORA_LIFECYCLE_HOOKS[event];
1372
1470
  }
1373
- ${ut}${W.override}${ft}
1471
+ ${gt}${V.override}${yt}
1374
1472
  // One \`onQueryChange\` dispatch. Mirrors \`executeSubscription\` — the
1375
1473
  // socket-terminated half of the same reactivity — and differs only in who
1376
1474
  // consumes the result: the base's \`dispatchReactors\` stores the digest as
@@ -1391,7 +1489,18 @@ ${ut}${W.override}${ft}
1391
1489
  // would instead run an app's reactor as whichever user happened to write
1392
1490
  // last, which is worse than running it as nobody.
1393
1491
  protected override async runReactor(functionPath: string, previousDigest?: string): Promise<{ digest: string; ran: boolean; tables: readonly string[] } | undefined> {
1394
- const registered = LUNORA_FUNCTIONS[functionPath];
1492
+ ${l?` const requestScope = this.captureRequestScope();
1493
+ const preparation = this.prepareFunction(functionPath, "reactor");
1494
+
1495
+ if (preparation !== undefined) {
1496
+ try {
1497
+ await preparation;
1498
+ } finally {
1499
+ this.restoreRequestScope(requestScope);
1500
+ }
1501
+ }
1502
+
1503
+ `:""} const registered = LUNORA_FUNCTIONS[functionPath];
1395
1504
 
1396
1505
  if (!registered || registered.kind !== "mutation") {
1397
1506
  return undefined;
@@ -1458,7 +1567,7 @@ ${ut}${W.override}${ft}
1458
1567
  protected override studioFeatures(): StudioFeaturesResult {
1459
1568
  return LUNORA_STUDIO_FEATURES();
1460
1569
  }
1461
- ${$.evaluateOverride}${$.subscriptionOverride}${qe}${Ue}
1570
+ ${U.evaluateOverride}${U.subscriptionOverride}${Be}${We}
1462
1571
  protected override advisories(): AdvisoryFinding[] {
1463
1572
  return LUNORA_ADVISORIES();
1464
1573
  }
@@ -1467,17 +1576,17 @@ ${$.evaluateOverride}${$.subscriptionOverride}${qe}${Ue}
1467
1576
  return LUNORA_ADVISOR_PROCEDURES();
1468
1577
  }
1469
1578
 
1470
- ${tr}
1579
+ ${cr}
1471
1580
 
1472
1581
  protected override ensureMigrated(): void {
1473
1582
  if (this.migrated) {
1474
1583
  return;
1475
1584
  }
1476
1585
 
1477
- runShardMigrations(this.sql as SqlExec, schema as unknown as SchemaLike, { cdc: config.cdc ?? false${ae} });
1586
+ runShardMigrations(this.sql as SqlExec, schema as unknown as SchemaLike, { cdc: config.cdc ?? false${R} });
1478
1587
  this.migrated = true;
1479
1588
  }
1480
- ${H?`
1589
+ ${G?`
1481
1590
  protected override runShardSearchBackfill(options: { maxPages?: number }): SearchBackfillProgress {
1482
1591
  // Migrations create the fts5 companions; without them every backfill
1483
1592
  // statement would raise "no such table" on a shard that has never
@@ -1486,7 +1595,7 @@ ${H?`
1486
1595
 
1487
1596
  return backfillSearchIndexes(this.sql as SqlExec, schema as unknown as SchemaLike, options);
1488
1597
  }
1489
- `:""}${at}
1490
- ${rr({actionOnlyFields:Rt,agentsBuild:ke,agentsContextField:Se,containersBuild:pe,containersContextField:me,databaseOptions:it,everyContextBuild:vt,everyContextField:kt,facadeBlock:wt,globalDatabaseLine:lt,notifyBuild:St,ormContextField:ct,paymentsBuild:Ae,paymentsContextField:De,queuesBuild:se,queuesContextField:oe,topicsBuild:ce,topicsContextField:le,vectorsBuild:st,vectorsContextField:dt,workflowsBuild:be,workflowsContextField:ye,actionOnlyBuild:xt})}
1598
+ `:""}${it}
1599
+ ${lr({lazyFunctions:l,actionOnlyFields:_t,agentsBuild:xe,agentsContextField:Ae,containersBuild:fe,containersContextField:be,databaseOptions:lt,everyContextBuild:Tt,everyContextField:Ct,facadeBlock:Dt,globalDatabaseLine:pt,notifyBuild:Et,ormContextField:ht,paymentsBuild:Te,paymentsContextField:Ee,queuesBuild:de,queuesContextField:ce,topicsBuild:he,topicsContextField:pe,vectorsBuild:dt,vectorsContextField:ut,workflowsBuild:ve,workflowsContextField:ke,actionOnlyBuild:Lt})}
1491
1600
  };
1492
- `};export{cr as b,Lr as e};
1601
+ `};export{br as b,Fr as e};