@lunora/codegen 1.0.0-alpha.2 → 1.0.0-alpha.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/__assets__/package-og.svg +1 -1
  2. package/dist/index.d.mts +444 -16
  3. package/dist/index.d.ts +444 -16
  4. package/dist/index.mjs +28 -22
  5. package/dist/packem_shared/{CONTAINERS_FILENAME-0K-pjNb8.mjs → CONTAINERS_FILENAME-DlP6YM_Q.mjs} +1 -1
  6. package/dist/packem_shared/{CodegenDiagnosticError-54jWDxA9.mjs → CodegenDiagnosticError-DeblMkzO.mjs} +3 -2
  7. package/dist/packem_shared/FLAGS_FILENAME-B1vE0LIo.mjs +139 -0
  8. package/dist/packem_shared/{emitApi-hRVC-kE7.mjs → GENERATED_HEADER-CI272wRm.mjs} +873 -54
  9. package/dist/packem_shared/LUNORA_SOLUTION_RULES-BTejmZp-.mjs +131 -0
  10. package/dist/packem_shared/MUTATORS_FILENAME-BhqdPtKp.mjs +81 -0
  11. package/dist/packem_shared/{buildOpenRpcDocument-BZGY1-jT.mjs → OPENRPC_VERSION-t5pV2NIN.mjs} +1 -1
  12. package/dist/packem_shared/QUEUES_FILENAME-B5_eWCRe.mjs +119 -0
  13. package/dist/packem_shared/{createCodegenProject-DGJm0_Pk.mjs → SCHEMA_SNAPSHOT_FILENAME-BMez-jgr.mjs} +187 -43
  14. package/dist/packem_shared/{buildSchemaSnapshot-DzLDbWk3.mjs → SCHEMA_SNAPSHOT_VERSION-wWGP2_5E.mjs} +12 -0
  15. package/dist/packem_shared/SHAPES_FILENAME-ChV7MqgE.mjs +94 -0
  16. package/dist/packem_shared/{discoverWorkflows-DRDQdhfq.mjs → WORKFLOWS_FILENAME-CCisG0Vy.mjs} +42 -2
  17. package/dist/packem_shared/{buildOpenApiDocument-yHVN66Xd.mjs → buildOpenApiDocument-Dx5QftUn.mjs} +1 -1
  18. package/dist/packem_shared/{discoverAuthApiCalls-C35R6z0T.mjs → discoverAuthApiCalls-CoirYbg6.mjs} +1 -1
  19. package/dist/packem_shared/{discoverCrons-BL6iGuJ3.mjs → discoverCrons-Cev7RRAf.mjs} +20 -17
  20. package/dist/packem_shared/{discoverFunctions-DEgAcRuD.mjs → discoverFunctions-BWMczzBx.mjs} +7 -2
  21. package/dist/packem_shared/{discoverHttpRoutes-C978pBiG.mjs → discoverHttpRoutes-CfP6cMzt.mjs} +2 -2
  22. package/dist/packem_shared/{discoverInserts-CRQdXvHO.mjs → discoverInserts-C7zxXkUf.mjs} +24 -2
  23. package/dist/packem_shared/{discoverMaskProcedures-B64zA740.mjs → discoverMaskProcedures-Cm81kwrb.mjs} +1 -1
  24. package/dist/packem_shared/{discoverMigrations-Doj_-BAA.mjs → discoverMigrations-Bi5nJ0mJ.mjs} +10 -4
  25. package/dist/packem_shared/{discoverNondeterministicCalls-4KiPQxQU.mjs → discoverNondeterministicCalls-C4M8AXmQ.mjs} +1 -1
  26. package/dist/packem_shared/{discoverQueries-BkIi0dBD.mjs → discoverQueries-B0wGT-xe.mjs} +1 -1
  27. package/dist/packem_shared/discoverR2sqlCalls-BVNMd428.mjs +80 -0
  28. package/dist/packem_shared/{discoverRlsMetadata-DpRB1HMe.mjs → discoverRlsMetadata-BS9GOGC5.mjs} +1 -1
  29. package/dist/packem_shared/{discoverSchema-BBulgGbH.mjs → discoverSchema-KYq55qu3.mjs} +338 -16
  30. package/dist/packem_shared/{discoverStorageRulesMetadata-DAqJUxUv.mjs → discoverStorageRulesMetadata-Da8BKXcI.mjs} +1 -1
  31. package/dist/packem_shared/{emitApp-CzZ6GbrD.mjs → emitApp-cOSypPuO.mjs} +74 -8
  32. package/dist/packem_shared/{lintSchema-DicbOHvH.mjs → formatAdvisories-DdjK7sgh.mjs} +15 -2
  33. package/dist/packem_shared/{parse-validator-tuQtHrsr.mjs → parse-validator-Cabb60UV.mjs} +2 -1
  34. package/package.json +8 -7
package/dist/index.d.ts CHANGED
@@ -25,6 +25,15 @@ interface ValidatorIR {
25
25
  bucket?: string;
26
26
  /** Column modifiers (`.unique()`, `.default()`, `.nullable()`, …) when present. */
27
27
  column?: ColumnMetaIR;
28
+ /**
29
+ * `true` when this validator carries a `.check(...)` refinement. The predicate
30
+ * is a runtime closure the AST→IR step can't represent, so the node keeps its
31
+ * base `kind` but records the refinement's presence here. The AOT args-validator
32
+ * compiler declines any node with this flag (compiling it would silently skip
33
+ * the predicate). `.meta(...)` is pure metadata with no parse effect and does
34
+ * NOT set this.
35
+ */
36
+ hasRefinement?: boolean;
28
37
  /** For `v.optional(inner)` / `v.array(inner)`. */
29
38
  inner?: ValidatorIR;
30
39
  /** For `v.record(key, value)`. */
@@ -100,6 +109,36 @@ interface RelationIR {
100
109
  /** Target table name. */
101
110
  table: string;
102
111
  }
112
+ /**
113
+ * Statically-discovered `.source(...)` config (plan 077). Only the bits the
114
+ * advisor lints + DO wiring need are captured; `map`/`tenantBy` are functions and
115
+ * cannot be serialized, so their presence is recorded as `hasTenantBy` rather than
116
+ * the function itself.
117
+ */
118
+ interface ExternalSourceIR {
119
+ /** The wrangler Hyperdrive binding name. */
120
+ binding: string;
121
+ /** Whether a `columns` projection allow-list was given. */
122
+ columns?: ReadonlyArray<string>;
123
+ /** `true` when a `reconcileEveryMs` was given (the incremental-mode delete-visibility companion). */
124
+ hasReconcile?: boolean;
125
+ /** `true` when a `tenantBy` mapper was given — the tenant-isolation boundary the `external_source_unscoped` lint checks. */
126
+ hasTenantBy: boolean;
127
+ /** The `idColumn` literal, when given (defaults to `"id"` at runtime). */
128
+ idColumn?: string;
129
+ /** Delete-detection mode literal, when given (`"full-pull"` | `"incremental"`). */
130
+ mode?: string;
131
+ /** The membership query literal, when statically knowable. */
132
+ query?: string;
133
+ /**
134
+ * `true` when `.source(...)` was present but its argument was **not** a static
135
+ * object literal (e.g. `.source(buildConfig())`), so none of the fields above
136
+ * could be read. The source still exists — this flag lets `hasSourcedTables`
137
+ * (codegen) and the `external_source_*` lints treat it as a source that can't be
138
+ * verified, instead of mistaking it for no `.source()` at all.
139
+ */
140
+ unanalyzable?: boolean;
141
+ }
103
142
  interface TableIR {
104
143
  /**
105
144
  * `true` when the table chain carried `.externallyManaged()` — its rows are
@@ -109,6 +148,13 @@ interface TableIR {
109
148
  */
110
149
  externallyManaged?: boolean;
111
150
  /**
151
+ * Set when the chain carried `.source(...)` — the table is materialized from an
152
+ * external Hyperdrive-backed database by a system poll loop (plan 077). Carries
153
+ * the statically-knowable bits the advisor lints read; the functions (`map`,
154
+ * `tenantBy`) are not serialized, only their presence (`hasTenantBy`).
155
+ */
156
+ externalSource?: ExternalSourceIR;
157
+ /**
112
158
  * Storage backend for a `.global()` table: `"d1"` (default) or
113
159
  * `"hyperdrive"` (a Postgres/MySQL database via Cloudflare Hyperdrive). Only
114
160
  * meaningful when `shardMode === "global"`; absent for sharded/root tables.
@@ -126,10 +172,23 @@ interface TableIR {
126
172
  field: string;
127
173
  kind: "shardBy";
128
174
  };
175
+ /** Set when the chain carried `.softDelete()` — the marker column's name (default `deletedAt`). The column is injected into `shape` so `Doc_*` carries it. */
176
+ softDelete?: {
177
+ field: string;
178
+ };
129
179
  /** Vector indexes declared inline via `.vectorize()` (DSL Shape A). */
130
180
  vectorIndexes: ReadonlyArray<VectorIndexIR>;
131
181
  }
182
+ /** The Cloudflare DO data-residency jurisdictions the schema may declare. Canonical literal set for the codegen package. */
183
+ type JurisdictionIR = "eu" | "fedramp" | "us";
132
184
  interface SchemaIR {
185
+ /**
186
+ * Cloudflare data-residency jurisdiction declared via
187
+ * `defineSchema(...).jurisdiction("…")`. Emitted into the generated worker's
188
+ * `createWorker({ jurisdiction })` (and `ctx.scheduler` / `ctx.containers`).
189
+ * Absent ⇒ un-pinned.
190
+ */
191
+ jurisdiction?: JurisdictionIR;
133
192
  tables: ReadonlyArray<TableIR>;
134
193
  /** All vector indexes (inline Shape A hoisted + standalone Shape B), flattened. */
135
194
  vectorIndexes: ReadonlyArray<VectorIndexIR>;
@@ -179,6 +238,59 @@ interface MigrationIR {
179
238
  table: string;
180
239
  }
181
240
  /**
241
+ * A `defineShape({...})` declaration discovered in `lunora/shapes.ts`
242
+ * (local-first sync engine, Phase 7). The emitted `LUNORA_SHAPES` registry keys
243
+ * on {@link ShapeIR.exportName}; the generated DO's `resolveShape` override
244
+ * dispatches a `shape_subscribe` to the matching registered shape. Discovery is
245
+ * marker-driven (the `__lunoraShape` brand) — no field metadata is lifted here
246
+ * because the runtime object (`columns`/`compileWhere`) carries the authority.
247
+ */
248
+ interface ShapeIR {
249
+ /** Export binding name — the shape's registry key and import member. */
250
+ exportName: string;
251
+ /** Path relative to `&lt;projectRoot>/lunora/` without extension — always `"shapes"`. */
252
+ filePath: string;
253
+ /**
254
+ * The `table` string literal from the `defineShape({ table })` call, lifted
255
+ * only for static advisor lints (the runtime object stays authoritative).
256
+ * `undefined` when `table` is not a plain string literal — lints skip those.
257
+ */
258
+ table?: string;
259
+ }
260
+ /**
261
+ * A `defineMutator({...})` declaration discovered in `lunora/mutators.ts`
262
+ * (local-first sync engine, Phase 7). The emitted registry registers the
263
+ * authoritative `server` impl into the DO's `LUNORA_FUNCTIONS` table (so
264
+ * `handleRpc` transaction-wraps it) and records its path in
265
+ * `LUNORA_MUTATOR_PATHS` so the DO's `isCustomMutator` override routes the
266
+ * client-watermark push protocol. The client `client` impl is split into the
267
+ * browser bundle separately — only the path crosses to the server side.
268
+ */
269
+ interface MutatorIR {
270
+ /** Export binding name — the mutator's registry key and import member. */
271
+ exportName: string;
272
+ /** Path relative to `&lt;projectRoot>/lunora/` without extension — always `"mutators"`. */
273
+ filePath: string;
274
+ }
275
+ /**
276
+ * A whole-row `ctx.db.replace(id, document)` write discovered inside a custom
277
+ * mutator's inline `server` impl (`lunora/mutators.ts`) — the input the
278
+ * `mutator_full_row_replace` advisor lint consumes. A `replace` overwrites the
279
+ * entire row, so a concurrent edit to a different column on a synced table is
280
+ * clobbered; `ctx.db.patch(id, { field })` merges at the column level instead.
281
+ * Structurally identical to `AdvisorMutatorWrite` so it passes straight through
282
+ * to the advisor without conversion, exactly as `InsertWriteIR` does for
283
+ * `AdvisorInsertWrite`.
284
+ */
285
+ interface MutatorWriteIR {
286
+ /** The mutator export whose `server` impl performs the replace, e.g. `renameChannel`. */
287
+ exportName: string;
288
+ /** Openable source path the replace appears in — always `lunora/mutators.ts`. */
289
+ file: string;
290
+ /** 1-based line of the `replace(...)` call. */
291
+ line: number;
292
+ }
293
+ /**
182
294
  * A single cron job lifted from a `cronJobs()` builder in `lunora/crons.ts`.
183
295
  * Mirrors `@lunora/scheduler`'s `CronJob`: {@link CronJobIR.cron} is the compiled
184
296
  * standard cron expression, {@link CronJobIR.functionPath} is the target
@@ -288,6 +400,79 @@ interface WorkflowIR {
288
400
  * definition overrides it.
289
401
  */
290
402
  name: string;
403
+ /**
404
+ * Durable step labels lifted from the handler body — the first string-literal
405
+ * argument of every `ctx.step.do` / `.sleep` / `.sleepUntil` / `.waitForEvent`
406
+ * call. Feeds the duplicate-step-name lint, which flags a name used twice
407
+ * (Cloudflare memoizes by name, so the second call silently returns the
408
+ * first's cached result). Calls with a non-literal name are omitted (not
409
+ * statically comparable).
410
+ */
411
+ steps: ReadonlyArray<WorkflowStepIR>;
412
+ }
413
+ /** One durable step call lifted from a workflow handler body (the use side of {@link WorkflowIR.steps}). */
414
+ interface WorkflowStepIR {
415
+ /** 1-based line of the durable step call. */
416
+ line: number;
417
+ /** The native step method invoked: `do` / `sleep` / `sleepUntil` / `waitForEvent`. */
418
+ method: string;
419
+ /** The step's static label (the first string-literal argument). */
420
+ name: string;
421
+ }
422
+ /**
423
+ * A queue lifted from a `defineQueue()` export in `lunora/queues.ts`. Carries
424
+ * what the emitters and the config layer need to wire the typed `ctx.queues`
425
+ * producer, the generated worker `queue()` dispatch, and the wrangler
426
+ * `queues.producers[]` / `queues.consumers[]` entries. Like workflows, a queue
427
+ * is NOT a Durable Object — wrangler gets only `queues.*` entries. Names are
428
+ * derived via `@lunora/queue`'s shared helpers so codegen and the config layer
429
+ * can never disagree.
430
+ */
431
+ interface QueueIR {
432
+ /** The Cloudflare `Queue` producer binding name, e.g. `QUEUE_EMAIL`. */
433
+ bindingName: string;
434
+ /** The `lunora/queues.ts` export name, e.g. `emailQueue`. */
435
+ exportName: string;
436
+ /** How the queue is consumed: `"push"` (a worker `queue()` handler) or `"pull"` (external HTTP). */
437
+ mode: "pull" | "push";
438
+ /**
439
+ * The stable wrangler queue name (`queues.producers[].queue`). Defaults to
440
+ * the kebab-cased export name (`emailQueue` → `email-queue`); a static
441
+ * `name:` literal in the definition overrides it.
442
+ */
443
+ name: string;
444
+ /** Push-consumer batch/retry tuning, mirrored onto the wrangler `queues.consumers[]` entry. */
445
+ tuning: {
446
+ deadLetterQueue?: string;
447
+ maxBatchSize?: number;
448
+ maxBatchTimeout?: number;
449
+ maxRetries?: number;
450
+ retryDelay?: number;
451
+ };
452
+ }
453
+ /**
454
+ * The feature-flag provider declared by the default export of `lunora/flags.ts`
455
+ * (`defineFlags({ provider, … })`). Discovery is **metadata-only** — codegen
456
+ * imports the real module at runtime for the provider value; this IR exists so
457
+ * the config layer can reconcile/validate the wrangler `flagship` binding when
458
+ * the app uses Flagship in binding mode. A `custom` provider (any other
459
+ * OpenFeature factory) carries no binding to reconcile.
460
+ */
461
+ interface FlagsIR {
462
+ /**
463
+ * The wrangler `flagship[].binding` name — set **only** for a flagship
464
+ * `provider` in binding mode (`flagshipProvider({ binding: "FLAGS" })`). The
465
+ * config layer hints/validates a matching `flagship` binding from this.
466
+ */
467
+ bindingName?: string;
468
+ /**
469
+ * Flagship operating mode — `"binding"` (wrangler binding, needs a
470
+ * `flagship` entry) or `"http"` (no binding); `undefined` for a `custom`
471
+ * provider or when the mode can't be read statically.
472
+ */
473
+ mode?: "binding" | "http";
474
+ /** `"flagship"` when the provider is `flagshipProvider(...)`, else `"custom"` (any other OpenFeature provider factory). */
475
+ provider: "custom" | "flagship";
291
476
  }
292
477
  /**
293
478
  * A `ctx.workflows.get("name")…` call discovered in a function body — the
@@ -384,6 +569,26 @@ interface NondeterministicCallIR {
384
569
  line: number;
385
570
  }
386
571
  /**
572
+ * One `ctx.r2sql` access lexically inside a `query`/`mutation` handler — the
573
+ * `r2sql_outside_action` advisor lint input. Structurally identical to the
574
+ * advisor's `AdvisorR2sqlCall` (same field set) so values pass straight through
575
+ * `lintSchema` without conversion, exactly as `NondeterministicCallIR` does.
576
+ * Only `query`/`mutation` handlers are recorded; `action(...)` is the intended
577
+ * home for `ctx.r2sql` and is skipped.
578
+ */
579
+ interface R2sqlCallIR {
580
+ /** The accessed `ctx.r2sql` surface, e.g. `ctx.r2sql.query` / `ctx.r2sql.from`. */
581
+ callee: string;
582
+ /** Export binding name of the function performing the access. */
583
+ exportName: string;
584
+ /** Source file relative to the lunora dir, without extension (the api namespace). */
585
+ file: string;
586
+ /** Which procedure kind the access lives in — only `query`/`mutation` handlers are recorded. */
587
+ kind: "mutation" | "query";
588
+ /** 1-based line of the access, or `0` when unknown. */
589
+ line: number;
590
+ }
591
+ /**
387
592
  * Per-procedure RLS usage snapshot, produced by `discoverRlsProcedures` for the
388
593
  * `rls_uncovered_table` advisor lint. Structurally identical to
389
594
  * `AdvisorRlsProcedure` (they share the same field set) so values pass straight
@@ -678,15 +883,16 @@ interface ProjectIR {
678
883
  * feed `table_without_insert`, authApi calls feed `auth_api_call_without_headers`,
679
884
  * rls procedure snapshots feed `rls_uncovered_table`, and mask procedure
680
885
  * snapshots feed `mask_uncovered_pii_column`; declared containers
681
- * feed the `container_*` lints; declared workflows + `ctx.workflows.get(...)` call
682
- * sites feed the `workflow_unused` / `workflow_unknown_target` lints; non-deterministic
886
+ * feed the `container_*` lints; declared workflows (with their durable step labels)
887
+ * + `ctx.workflows.get(...)` call sites feed the `workflow_unused` /
888
+ * `workflow_unknown_target` / duplicate-step-name lints; non-deterministic
683
889
  * calls inside query/mutation handlers feed the `nondeterministic_query_mutation` lint
684
890
  * (all default empty for callers that don't analyze functions/containers/workflows).
685
891
  * The IR types are structurally identical to the advisor's evidence types so they
686
892
  * pass straight through without conversion. Returns the findings; surfacing them
687
893
  * (console, error overlay, studio Advisors table) is the caller's choice.
688
894
  */
689
- declare const lintSchema: (schema: SchemaIR, queries?: ReadonlyArray<QueryReadIR>, inserts?: ReadonlyArray<InsertWriteIR>, authApiCalls?: ReadonlyArray<AuthApiCallIR>, rlsProcedures?: ReadonlyArray<RlsProcedureIR>, containers?: ReadonlyArray<ContainerIR>, workflows?: ReadonlyArray<WorkflowIR>, workflowCalls?: ReadonlyArray<WorkflowCallIR>, maskProcedures?: ReadonlyArray<MaskProcedureIR>, nondeterministicCalls?: ReadonlyArray<NondeterministicCallIR>, procedureProtections?: ReadonlyArray<ProcedureMiddlewareIR>, argumentValidators?: ReadonlyArray<ArgumentValidatorIR>, secretLiterals?: ReadonlyArray<SecretLiteralIR>, sqlInterpolations?: ReadonlyArray<SqlInterpolationIR>, adminRoutes?: ReadonlyArray<AdminRouteIR>) => Finding[];
895
+ declare const lintSchema: (schema: SchemaIR, queries?: ReadonlyArray<QueryReadIR>, inserts?: ReadonlyArray<InsertWriteIR>, authApiCalls?: ReadonlyArray<AuthApiCallIR>, rlsProcedures?: ReadonlyArray<RlsProcedureIR>, containers?: ReadonlyArray<ContainerIR>, workflows?: ReadonlyArray<WorkflowIR>, workflowCalls?: ReadonlyArray<WorkflowCallIR>, maskProcedures?: ReadonlyArray<MaskProcedureIR>, nondeterministicCalls?: ReadonlyArray<NondeterministicCallIR>, procedureProtections?: ReadonlyArray<ProcedureMiddlewareIR>, argumentValidators?: ReadonlyArray<ArgumentValidatorIR>, secretLiterals?: ReadonlyArray<SecretLiteralIR>, sqlInterpolations?: ReadonlyArray<SqlInterpolationIR>, adminRoutes?: ReadonlyArray<AdminRouteIR>, r2sqlCalls?: ReadonlyArray<R2sqlCallIR>, shapes?: ReadonlyArray<ShapeIR>, mutatorWrites?: ReadonlyArray<MutatorWriteIR>) => Finding[];
690
896
  /**
691
897
  * Render advisor findings as a single multi-line string for console surfacing:
692
898
  * a one-line summary header followed by one `[LEVEL] name: detail` line per
@@ -711,8 +917,14 @@ declare class CodegenDiagnosticError extends Error {
711
917
  * ts-morph `Node`'s position in its source file.
712
918
  *
713
919
  * Message format: `@lunora/codegen: &lt;detail> (&lt;file>:&lt;line>:&lt;column>)`
920
+ *
921
+ * `meta` is merged onto the returned error for callers that also carry the
922
+ * project-wide `LunoraError` envelope (`code`/`name`/`status`) — it never
923
+ * touches `file`/`line`/`column`, and the error stays an instance of
924
+ * {@link CodegenDiagnosticError} so the Vite overlay's `instanceof` location
925
+ * lookup is unaffected.
714
926
  */
715
- declare const diagnosticAt: (node: Node, detail: string) => CodegenDiagnosticError;
927
+ declare const diagnosticAt: (node: Node, detail: string, meta?: Record<string, unknown>) => CodegenDiagnosticError;
716
928
  /**
717
929
  * Discover `ctx.authApi.&lt;method>(...)` (and bare `authApi.&lt;method>(...)`) calls
718
930
  * under the lunora source directory and attribute each to the exported function
@@ -738,6 +950,21 @@ declare const discoverContainers: (project: Project, lunoraDirectory: string) =>
738
950
  * workflow start. Names must be unique across the project.
739
951
  */
740
952
  declare const discoverCrons: (project: Project, lunoraDirectory: string, workflows?: ReadonlyArray<WorkflowIR>) => CronJobIR[];
953
+ /** The only file a feature-flag provider may be declared in — mirrors `lunora/queues.ts`. */
954
+ declare const FLAGS_FILENAME = "flags.ts";
955
+ /** One statically-discovered flag read: the key plus the value type its `ctx.flags.&lt;type>` call implies. */
956
+
957
+ /**
958
+ * Discover the feature-flag provider a project declares in `lunora/flags.ts`.
959
+ * Returns `undefined` when the file doesn't exist (the app has no flags). The
960
+ * read is metadata-only and lenient: codegen wires `ctx.flags` purely from the
961
+ * file's *existence* (`run-codegen.ts`) and imports the real module for the
962
+ * provider value — this IR exists solely so the config layer can reconcile the
963
+ * wrangler `flagship` binding for the Flagship binding-mode provider. Anything
964
+ * it can't read statically degrades to a `custom` provider (no binding), never
965
+ * a thrown error.
966
+ */
967
+ declare const discoverFlags: (project: Project, lunoraDirectory: string) => FlagsIR | undefined;
741
968
  /**
742
969
  * Scan all .ts files under `lunoraDir` (skipping `_generated/` and `schema.ts`)
743
970
  * for top-level `export const x = query/mutation/action({...})` registrations.
@@ -780,6 +1007,23 @@ declare const discoverMaskProcedures: (project: Project, lunoraDirectory: string
780
1007
  * key); `table` is best-effort and left `""` when not a literal.
781
1008
  */
782
1009
  declare const discoverMigrations: (project: Project, lunoraDirectory: string) => MigrationIR[];
1010
+ /** The only file custom mutators may be declared in — mirrors `lunora/queues.ts`. */
1011
+ declare const MUTATORS_FILENAME = "mutators.ts";
1012
+ /**
1013
+ * Decide whether a call's callee is `defineMutator` — either the bare imported
1014
+ * identifier (`defineMutator(...)`) or a namespace member access
1015
+ * (`server.defineMutator(...)`). Both are valid ES module syntax, so discovery
1016
+ * must see mutators declared either way.
1017
+ */
1018
+
1019
+ /**
1020
+ * Discover every custom mutator the project declares: exported
1021
+ * `defineMutator()` calls in `lunora/mutators.ts`. Returns `[]` when the file
1022
+ * doesn't exist. Only the export binding is lifted — the runtime object carries
1023
+ * the authoritative `server` impl + `handler`, so codegen never evaluates the
1024
+ * body. The client `client` impl is split into the browser bundle separately.
1025
+ */
1026
+ declare const discoverMutators: (project: Project, lunoraDirectory: string) => MutatorIR[];
783
1027
  /**
784
1028
  * Discover non-deterministic API calls (`Date.now`, `new Date()`, `Date()`,
785
1029
  * `Math.random`, `crypto.randomUUID`, `crypto.getRandomValues` — including
@@ -803,6 +1047,28 @@ declare const discoverNondeterministicCalls: (project: Project, lunoraDirectory:
803
1047
  * dropping the rest keeps the lint input small.
804
1048
  */
805
1049
  declare const discoverQueries: (project: Project, lunoraDirectory: string) => QueryReadIR[];
1050
+ /** The only file queues may be declared in — mirrors `lunora/workflows.ts`. */
1051
+ declare const QUEUES_FILENAME = "queues.ts";
1052
+ /**
1053
+ * Discover every queue the project declares: exported `defineQueue()` calls in
1054
+ * `lunora/queues.ts`. Returns `[]` when the file doesn't exist. Only the
1055
+ * wrangler-relevant literals (`name`/`mode`/batch tuning) are read; the handler
1056
+ * body is runtime-only, so codegen never evaluates it.
1057
+ */
1058
+ declare const discoverQueues: (project: Project, lunoraDirectory: string) => QueueIR[];
1059
+ /**
1060
+ * Discover `ctx.r2sql` accesses lexically inside the handler body of every
1061
+ * exported `query(...)` / `mutation(...)` registration under the lunora source
1062
+ * directory — the `r2sql_outside_action` lint input. `action(...)` (and
1063
+ * `stream(...)`) registrations are intentionally skipped: R2 SQL is the
1064
+ * external, non-reactive surface that belongs in actions.
1065
+ *
1066
+ * Traversal is scoped to the handler node (not the whole declaration), mirroring
1067
+ * `discoverNondeterministicCalls` — so a `ctx.r2sql` touch in a sibling helper
1068
+ * outside the handler is not attributed to the query/mutation. One
1069
+ * {@link R2sqlCallIR} is produced per access site.
1070
+ */
1071
+ declare const discoverR2sqlCalls: (project: Project, lunoraDirectory: string) => R2sqlCallIR[];
806
1072
  declare const discoverRlsProcedures: (project: Project, lunoraDirectory: string) => RlsProcedureIR[];
807
1073
  /**
808
1074
  * Aggregate the schema-wide RLS metadata the studio's read-only inspector reads:
@@ -822,7 +1088,17 @@ declare const discoverRlsMetadata: (project: Project, lunoraDirectory: string) =
822
1088
  * Load `&lt;projectRoot>/lunora/schema.ts`, find `defineSchema({...})`, and
823
1089
  * return a structural IR. Throws if the file or call cannot be found.
824
1090
  */
825
- declare const discoverSchema: (project: Project, schemaPath: string) => SchemaIR;
1091
+ declare const discoverSchema: (project: Project, schemaPath: string, projectRoot?: string) => SchemaIR;
1092
+ /** The only file shapes may be declared in — mirrors `lunora/queues.ts`. */
1093
+ declare const SHAPES_FILENAME = "shapes.ts";
1094
+ /**
1095
+ * Discover every replication shape the project declares: exported
1096
+ * `defineShape()` calls in `lunora/shapes.ts`. Returns `[]` when the file
1097
+ * doesn't exist. Only the export binding is lifted — the runtime object carries
1098
+ * the authoritative `table`/`columns`/`compileWhere`, so codegen never
1099
+ * evaluates the predicate.
1100
+ */
1101
+ declare const discoverShapes: (project: Project, lunoraDirectory: string) => ShapeIR[];
826
1102
  /**
827
1103
  * Aggregate the schema-wide storage-rule metadata the studio's inspector reads:
828
1104
  * every statically-discovered `(bucket, on, prefix, procedure)` entry across all
@@ -861,22 +1137,51 @@ declare const emitApi: (functions: ReadonlyArray<FunctionIR>, workflows?: Readon
861
1137
  * Returns `""` when `@lunora/seed` is not a declared dependency, so projects
862
1138
  * that don't use it keep a clean `_generated/` and never import the package.
863
1139
  */
1140
+
1141
+ /**
1142
+ * Emit `_generated/collections.ts` — one TanStack DB collection factory per
1143
+ * `defineShape` in `lunora/shapes.ts` (the local-first partial-replication
1144
+ * surface). Each factory builds a live collection that syncs its shape's rowset
1145
+ * through the client's poke protocol (`subscribeShape`), so an app feeds the
1146
+ * result straight to `useLiveQuery`.
1147
+ *
1148
+ * Returns `""` (so `writeIfPresent` skips the file) unless the project both
1149
+ * declares shapes AND installs `@lunora/db` — the add-on that ships
1150
+ * `lunoraCollectionOptions`. `@lunora/db` stays a scoped install even under the
1151
+ * `lunorash` umbrella (an opt-in add-on, like `@lunora/auth`), so its import is
1152
+ * always `@lunora/db/collections`; only the in-umbrella `@lunora/client` import
1153
+ * is remapped to `lunorash/client`.
1154
+ */
1155
+ declare const emitCollections: (shapes: ReadonlyArray<ShapeIR>, hasDatabase: boolean, useUmbrella?: boolean) => string;
864
1156
  interface EmitServerOptions {
865
1157
  containers?: ReadonlyArray<ContainerIR>;
1158
+ /**
1159
+ * A `lunora/` source reads `ctx.access` — wires the verified Cloudflare Access
1160
+ * facade (`@lunora/cloudflare-access/context`) onto every ctx. Distinct from
1161
+ * `emitApp`'s `hasAccess` (which gates the worker's `.access()` resolveIdentity
1162
+ * method); this one gates the per-request `ctx.access` read surface.
1163
+ */
1164
+ hasAccessFacade?: boolean;
866
1165
  hasAi?: boolean;
867
- /** A `lunora/` source uses `@lunora/analytics` / `ctx.analytics` — wires the write helper onto every ctx. */
1166
+ /** A `lunora/` source uses `@lunora/bindings/analytics` / `ctx.analytics` — wires the write helper onto every ctx. */
868
1167
  hasAnalytics?: boolean;
869
1168
  /** A `lunora/` source uses `@lunora/browser` / `ctx.browser` — wires `ctx.browser` onto ActionCtx only. */
870
1169
  hasBrowser?: boolean;
1170
+ /** The project declares `lunora/flags.ts` — wires `ctx.flags` (OpenFeature) onto every ctx. */
1171
+ hasFlags?: boolean;
871
1172
  /** A `lunora/` source uses `@lunora/hyperdrive` / `ctx.sql` — wires `ctx.sql` onto ActionCtx only. */
872
1173
  hasHyperdrive?: boolean;
873
- /** A `lunora/` source uses `@lunora/images` / `ctx.images` — wires `ctx.images` onto ActionCtx only. */
1174
+ /** A `lunora/` source uses `@lunora/bindings/images` / `ctx.images` — wires `ctx.images` onto ActionCtx only. */
874
1175
  hasImages?: boolean;
875
- /** A `lunora/` source uses `@lunora/kv` / `ctx.kv` — wires `ctx.kv` onto every ctx. */
1176
+ /** A `lunora/` source uses `@lunora/bindings/kv` / `ctx.kv` — wires `ctx.kv` onto every ctx. */
876
1177
  hasKv?: boolean;
877
1178
  hasPayments?: boolean;
878
- /** A `lunora/` source uses `@lunora/pipelines` / `ctx.pipelines` — wires `ctx.pipelines` onto ActionCtx only. */
1179
+ /** A `lunora/` source uses `@lunora/bindings/pipelines` / `ctx.pipelines` — wires `ctx.pipelines` onto ActionCtx only. */
879
1180
  hasPipelines?: boolean;
1181
+ /** A `lunora/` source uses `@lunora/bindings/r2sql` / `ctx.r2sql` — wires `ctx.r2sql` onto ActionCtx only. */
1182
+ hasR2sql?: boolean;
1183
+ /** Queues declared via `defineQueue` exports — wires the typed `ctx.queues` producers onto Mutation/Action contexts. */
1184
+ queues?: ReadonlyArray<QueueIR>;
880
1185
  schema?: SchemaIR;
881
1186
  storageRuleBuckets?: ReadonlyArray<string>;
882
1187
  /** The project depends on the `lunora` umbrella — import base packages via its subpaths. */
@@ -885,20 +1190,24 @@ interface EmitServerOptions {
885
1190
  }
886
1191
  declare const emitServer: ({
887
1192
  containers,
1193
+ hasAccessFacade,
888
1194
  hasAi,
889
1195
  hasAnalytics,
890
1196
  hasBrowser,
1197
+ hasFlags,
891
1198
  hasHyperdrive,
892
1199
  hasImages,
893
1200
  hasKv,
894
1201
  hasPayments,
895
1202
  hasPipelines,
1203
+ hasR2sql,
1204
+ queues,
896
1205
  schema,
897
1206
  storageRuleBuckets,
898
1207
  useUmbrella,
899
1208
  workflows
900
1209
  }?: EmitServerOptions) => string;
901
- declare const emitFunctions: (functions: ReadonlyArray<FunctionIR>, migrations?: ReadonlyArray<MigrationIR>) => string;
1210
+ declare const emitFunctions: (functions: ReadonlyArray<FunctionIR>, migrations?: ReadonlyArray<MigrationIR>, useUmbrella?: boolean, mutators?: ReadonlyArray<MutatorIR>, shapes?: ReadonlyArray<ShapeIR>) => string;
902
1211
  /**
903
1212
  * Storage-column map per table for the file browser: `{ table: [field, …] }` for
904
1213
  * every field declared `v.storage(...)` (unwrapping `v.optional(...)`). The
@@ -916,7 +1225,7 @@ declare const emitFunctions: (functions: ReadonlyArray<FunctionIR>, migrations?:
916
1225
  * `containers[].class_name` to be exported by the deployed worker. Returns ""
917
1226
  * when the project declares no containers (the file is not written then).
918
1227
  */
919
- declare const emitContainers: (containers: ReadonlyArray<ContainerIR>) => string;
1228
+ declare const emitContainers: (containers: ReadonlyArray<ContainerIR>, jurisdiction?: JurisdictionIR) => string;
920
1229
  /**
921
1230
  * Emit `_generated/workflows.ts` — one `WorkflowEntrypoint` class per
922
1231
  * `defineWorkflow` export, each a thin subclass of `LunoraWorkflow`
@@ -926,14 +1235,31 @@ declare const emitContainers: (containers: ReadonlyArray<ContainerIR>) => string
926
1235
  * when the project declares no workflows (the file is not written then).
927
1236
  */
928
1237
  declare const emitWorkflows: (workflows: ReadonlyArray<WorkflowIR>) => string;
1238
+ /**
1239
+ * Emit `_generated/queues.ts` — the push-consumer registry the worker `queue()`
1240
+ * handler dispatches through. Maps each push queue's stable wrangler name (which
1241
+ * `batch.queue` carries) to its `defineQueue` definition + export name. Pull
1242
+ * queues are consumed by an external worker, so they carry no handler and are
1243
+ * omitted here. Returns "" (and the file is not written) when no push queues are
1244
+ * declared — a pull-only or queue-free app keeps a clean `_generated/`.
1245
+ */
929
1246
  interface EmitShardOptions {
930
1247
  advisories?: ReadonlyArray<Finding>;
931
1248
  containers?: ReadonlyArray<ContainerIR>;
1249
+ /** Statically-discovered `ctx.flags.&lt;type>("key")` reads — the studio Flags page + reactive evaluation iterate these. */
1250
+ flagKeys?: ReadonlyArray<{
1251
+ key: string;
1252
+ type: "boolean" | "number" | "object" | "string";
1253
+ }>;
1254
+ /** A `lunora/` source reads `ctx.access` — wires the verified Cloudflare Access facade onto every ctx. */
1255
+ hasAccessFacade?: boolean;
932
1256
  hasAi?: boolean;
933
1257
  /** A `lunora/` source reads `ctx.analytics` — wires the Analytics Engine write helper onto every ctx. */
934
1258
  hasAnalytics?: boolean;
935
1259
  /** A `lunora/` source reads `ctx.browser` — wires `ctx.browser` onto the ActionCtx only. */
936
1260
  hasBrowser?: boolean;
1261
+ /** The project declares `lunora/flags.ts` — wires `ctx.flags` (OpenFeature) onto every ctx. */
1262
+ hasFlags?: boolean;
937
1263
  /** A `lunora/` source reads `ctx.sql` (Hyperdrive) — wires `ctx.sql` onto the ActionCtx only. */
938
1264
  hasHyperdrive?: boolean;
939
1265
  /** A `lunora/` source reads `ctx.images` — wires `ctx.images` onto the ActionCtx only. */
@@ -941,9 +1267,19 @@ interface EmitShardOptions {
941
1267
  /** A `lunora/` source reads `ctx.kv` — wires `ctx.kv` onto every ctx. */
942
1268
  hasKv?: boolean;
943
1269
  hasPayments?: boolean;
1270
+ /** A `lunora/` source reads `ctx.pipelines` — wires `ctx.pipelines` onto the ActionCtx only. */
1271
+ hasPipelines?: boolean;
1272
+ /** A `lunora/` source reads `ctx.r2sql` (R2 SQL) — wires `ctx.r2sql` onto the ActionCtx only. */
1273
+ hasR2sql?: boolean;
944
1274
  maskMetadata?: MaskMetadataIR;
1275
+ /** Custom mutators declared via `defineMutator` in `lunora/mutators.ts` — wires the `isCustomMutator` push-protocol override. */
1276
+ mutators?: ReadonlyArray<MutatorIR>;
1277
+ /** Queues declared via `defineQueue` exports in `lunora/queues.ts` — wires the typed `ctx.queues` producers. */
1278
+ queues?: ReadonlyArray<QueueIR>;
945
1279
  rlsMetadata?: RlsMetadataIR;
946
1280
  schema: SchemaIR;
1281
+ /** Replication shapes declared via `defineShape` in `lunora/shapes.ts` — wires the `resolveShape` subscription override. */
1282
+ shapes?: ReadonlyArray<ShapeIR>;
947
1283
  storageRules?: StorageRulesMetadataIR;
948
1284
  studioFeatures?: StudioFeaturesResult;
949
1285
  /** The project depends on the `lunora` umbrella — import base packages via its subpaths. */
@@ -953,16 +1289,24 @@ interface EmitShardOptions {
953
1289
  declare const emitShard: ({
954
1290
  advisories,
955
1291
  containers,
1292
+ flagKeys,
1293
+ hasAccessFacade,
956
1294
  hasAi,
957
1295
  hasAnalytics,
958
1296
  hasBrowser,
1297
+ hasFlags,
959
1298
  hasHyperdrive,
960
1299
  hasImages,
961
1300
  hasKv,
962
1301
  hasPayments,
1302
+ hasPipelines,
1303
+ hasR2sql,
963
1304
  maskMetadata,
1305
+ mutators,
1306
+ queues,
964
1307
  rlsMetadata,
965
1308
  schema,
1309
+ shapes,
966
1310
  storageRules,
967
1311
  studioFeatures,
968
1312
  useUmbrella,
@@ -1027,9 +1371,11 @@ declare const emitVectors: (vectorIndexes: ReadonlyArray<VectorIndexIR>) => stri
1027
1371
  declare const emitWranglerCronTriggers: (crons: ReadonlyArray<CronJobIR>) => string[];
1028
1372
  /** Which capability methods the generated `defineApp` builder exposes — one flag per package-backed feature the app actually uses. */
1029
1373
  interface EmitAppOptions {
1374
+ /** App depends on `@lunora/cloudflare-access` → emit `.access()` (wire the Cloudflare Access `resolveIdentity`, composed ahead of `@lunora/auth` when both are present). */
1375
+ hasAccess: boolean;
1030
1376
  /** App uses `@lunora/ai` / `ctx.ai` → emit `.ai()` (override the Workers AI binding backing `ctx.ai`). */
1031
1377
  hasAi: boolean;
1032
- /** App uses `@lunora/analytics` / `ctx.analytics` → emit `.analytics()` (override the dataset backing `ctx.analytics`). */
1378
+ /** App uses `@lunora/bindings/analytics` / `ctx.analytics` → emit `.analytics()` (override the dataset backing `ctx.analytics`). */
1033
1379
  hasAnalytics: boolean;
1034
1380
  /** App depends on `@lunora/auth` → emit `.auth()` + the lazy build/migrate dance. */
1035
1381
  hasAuth: boolean;
@@ -1043,12 +1389,16 @@ interface EmitAppOptions {
1043
1389
  hasHyperdrive: boolean;
1044
1390
  /** Schema declares **Hyperdrive-backed** `.global({ backend: "hyperdrive" })` tables → emit `.hyperdriveGlobal()` (reactive Postgres/MySQL ctx-db over Hyperdrive). */
1045
1391
  hasHyperdriveGlobal: boolean;
1046
- /** App uses `@lunora/images` / `ctx.images` → emit `.images()`. */
1392
+ /** App uses `@lunora/bindings/images` / `ctx.images` → emit `.images()`. */
1047
1393
  hasImages: boolean;
1048
- /** App uses `@lunora/kv` / `ctx.kv` → emit `.kv()`. */
1394
+ /** App uses `@lunora/bindings/kv` / `ctx.kv` → emit `.kv()`. */
1049
1395
  hasKv: boolean;
1050
1396
  /** App uses `@lunora/payment` / `ctx.payments` → emit `.payment()`. */
1051
1397
  hasPayments: boolean;
1398
+ /** App declares push queues (`defineQueue`) → wire `LUNORA_QUEUE_REGISTRY` into the worker's `queue()` consumer entry. */
1399
+ hasQueue: boolean;
1400
+ /** App uses `@lunora/bindings/r2sql` / `ctx.r2sql` → emit `.r2sql()`. */
1401
+ hasR2sql: boolean;
1052
1402
  /** App imports `@lunora/scheduler` / declares crons → emit `.scheduler()`. */
1053
1403
  hasScheduler: boolean;
1054
1404
  /** App uses `@lunora/storage` → emit `.storage()` (DO `ctx.storage` + studio file browser). */
@@ -1057,6 +1407,8 @@ interface EmitAppOptions {
1057
1407
  hasVectors: boolean;
1058
1408
  /** App declares Cloudflare Workflows (`defineWorkflow`) → wire `options.workflowsClient` so the studio's workflow-instance proxy can reach the CF REST API. */
1059
1409
  hasWorkflow: boolean;
1410
+ /** Schema declares `.jurisdiction("…")` → pin every DO the worker reaches (shards, fan-out, scheduler, containers) to the Cloudflare data-residency jurisdiction. */
1411
+ jurisdiction?: JurisdictionIR;
1060
1412
  /** Project depends on the unscoped `lunorash` umbrella → import the runtime via `lunorash/runtime` instead of `@lunora/runtime`. */
1061
1413
  useUmbrella: boolean;
1062
1414
  /** An OpenAPI spec is emitted (`openapi.ts`) → wire `openApiSpec` into the worker. */
@@ -1201,6 +1553,19 @@ interface TableSnapshot {
1201
1553
  }
1202
1554
  /** The committed baseline — a deterministic structural view of the whole schema. */
1203
1555
  interface SchemaSnapshot {
1556
+ /**
1557
+ * Cloudflare DO data-residency jurisdiction declared via `.jurisdiction("…")`,
1558
+ * or absent. Tracked because changing it strands all existing Durable Object
1559
+ * data (a DO name maps to a different ID per jurisdiction). Optional, so old
1560
+ * baselines written before this field parse cleanly (absent ⇒ undefined).
1561
+ *
1562
+ * Typed as a plain `string` (not the authoring union) on purpose: this is
1563
+ * STORED data that a newer Lunora may have written with a jurisdiction this
1564
+ * version doesn't yet know. Preserving the raw value keeps the breaking
1565
+ * `changedJurisdiction` diff correct under a downgrade — coercing an unknown
1566
+ * value to `undefined` would fail OPEN and hide the most destructive change.
1567
+ */
1568
+ jurisdiction?: string;
1204
1569
  /** Sorted list of every declared `defineMigration` id at capture time. */
1205
1570
  migrationIds: ReadonlyArray<string>;
1206
1571
  /** Table name → {@link TableSnapshot}, keys sorted for stable serialization. */
@@ -1214,7 +1579,7 @@ interface DriftChange {
1214
1579
  /** Human-readable, actionable description (used in the gate message). */
1215
1580
  summary: string;
1216
1581
  /** A machine-readable change discriminator. */
1217
- type: "addedIndex" | "addedOptionalField" | "addedRelation" | "addedRequiredField" | "addedTable" | "changedFieldKind" | "changedIndex" | "changedShardMode" | "fieldOptionalToRequired" | "fieldRequiredToOptional" | "removedField" | "removedIndex" | "removedRelation" | "removedTable";
1582
+ type: "addedIndex" | "addedOptionalField" | "addedRelation" | "addedRequiredField" | "addedTable" | "changedJurisdiction" | "changedFieldKind" | "changedIndex" | "changedShardMode" | "fieldOptionalToRequired" | "fieldRequiredToOptional" | "removedField" | "removedIndex" | "removedRelation" | "removedTable";
1218
1583
  }
1219
1584
  /** The result of diffing two snapshots: every classified change. */
1220
1585
  interface SchemaDrift {
@@ -1316,6 +1681,11 @@ declare const refreshCodegenProject: (project: Project, lunoraDirectory: string)
1316
1681
  * Top-level codegen entry. Parses `&lt;projectRoot>/lunora/schema.ts` and every
1317
1682
  * function file under `&lt;projectRoot>/lunora/`, then writes
1318
1683
  * `_generated/{api,server,dataModel}.ts` next to them.
1684
+ *
1685
+ * When `LUNORA_CODEGEN_TIMING` is set (truthy), a single diagnostic summary
1686
+ * line is written to stderr with the total wall time and the discovery-vs-emit
1687
+ * split — opt-in instrumentation that is otherwise zero-cost and side-effect-free
1688
+ * on the returned {@link CodegenResult}.
1319
1689
  */
1320
1690
  declare const runCodegen: (options: CodegenOptions) => CodegenResult;
1321
1691
  interface CodegenOptions {
@@ -1392,6 +1762,8 @@ interface CodegenResult {
1392
1762
  generated: {
1393
1763
  api: string; /** Fluent worker-composition builder (`_generated/app.ts`) — `defineApp()`. Always written. */
1394
1764
  app: string;
1765
+ /** Partial-replication collection factories (`_generated/collections.ts`); `""` (and not written) unless the project declares shapes and installs `@lunora/db`. */
1766
+ collections: string;
1395
1767
  /** Container DO classes (`_generated/containers.ts`); `""` (and not written) when no containers are declared. */
1396
1768
  containers: string;
1397
1769
  crons: string;
@@ -1416,6 +1788,8 @@ interface CodegenResult {
1416
1788
  * `apiSpec` includes `openrpc`.
1417
1789
  */
1418
1790
  openRpcModule: string;
1791
+ /** Push-consumer queue registry (`_generated/queues.ts`); `""` (and not written) when no push queues are declared. */
1792
+ queues: string;
1419
1793
  /** Project-bound seed client (`_generated/seed.ts`); `""` (and not written) when `@lunora/seed` is not a declared dependency. */
1420
1794
  seed: string;
1421
1795
  server: string;
@@ -1426,6 +1800,13 @@ interface CodegenResult {
1426
1800
  };
1427
1801
  outputDirectory: string;
1428
1802
  /**
1803
+ * Queues discovered from `defineQueue` exports in `lunora/queues.ts` — the
1804
+ * list the config layer reconciles into wrangler's `queues.producers[]` /
1805
+ * `queues.consumers[]`. Queues are NOT Durable Objects, so this adds no
1806
+ * binding or migration. Empty when the project declares no queues.
1807
+ */
1808
+ queues: ReadonlyArray<QueueIR>;
1809
+ /**
1429
1810
  * The CURRENT structural schema snapshot computed this run (tables + field
1430
1811
  * kinds/optionality + indexes/relations/shard mode + declared migration ids).
1431
1812
  * The pre-deploy drift gate diffs this against the committed baseline read
@@ -1469,5 +1850,52 @@ declare const validatorIrToJsonSchema: (validator: ValidatorIR) => JsonSchema;
1469
1850
  * the contract; clients switch on `error.code`. Kept sorted for stable output.
1470
1851
  */
1471
1852
  declare const LUNORA_ERROR_CODES: ReadonlyArray<string>;
1853
+ /**
1854
+ * Lunora-specific error→solution hints. A small rule table mapping the exact
1855
+ * messages Lunora throws — codegen/schema diagnostics, worker-entry export gaps,
1856
+ * and the runtime data-layer conflicts — to an actionable fix.
1857
+ *
1858
+ * This table is the single source of truth shared by every consumer that wants
1859
+ * to turn a raw Lunora error into a fix hint: the Vite error overlay
1860
+ * (`@lunora/vite`) renders the Markdown in the browser, and the standalone
1861
+ * `lunora dev` CLI prints it to the terminal. It lives in `@lunora/codegen`
1862
+ * because codegen owns most of the throw sites, so the hints stay next to the
1863
+ * code that produces the messages.
1864
+ *
1865
+ * Matching is on the **message text**. By the time a diagnostic reaches a
1866
+ * consumer it has often been flattened to a plain `{ message }` (the overlay
1867
+ * pushes codegen errors through `server.hot.send` with `name === "Error"`), so
1868
+ * the class identity is gone and the message is the only stable signal.
1869
+ *
1870
+ * Bodies are Markdown — the overlay renders them; the CLI prints them (lightly
1871
+ * de-marked) as-is.
1872
+ */
1873
+ /** A resolved hint for a recognized Lunora error. */
1874
+ interface LunoraSolution {
1875
+ /** Markdown body shown under the header. */
1876
+ body: string;
1877
+ /** Short header for the solution. */
1878
+ header: string;
1879
+ /** Stable id (used in DEBUG logs and tests). */
1880
+ id: string;
1881
+ }
1882
+ /** A single error→solution rule: a {@link LunoraSolution} plus its matcher. */
1883
+ interface LunoraSolutionRule extends LunoraSolution {
1884
+ /** True when this rule recognizes the error message. */
1885
+ test: (message: string) => boolean;
1886
+ }
1887
+ /**
1888
+ * The rules, ordered most- to least-specific: the dev-time codegen/schema rules
1889
+ * come first because they're the errors a developer hits while editing
1890
+ * `lunora/`, then the runtime data-layer conflicts that surface from the worker.
1891
+ * The first matching rule (in array order) wins.
1892
+ */
1893
+ declare const LUNORA_SOLUTION_RULES: ReadonlyArray<LunoraSolutionRule>;
1894
+ /**
1895
+ * Find the first Lunora solution whose rule matches `message`, or `undefined`
1896
+ * if none recognize it. Consumers turn the returned Markdown into their own
1897
+ * presentation (overlay panel, terminal hint, …).
1898
+ */
1899
+ declare const findLunoraSolution: (message: string) => LunoraSolution | undefined;
1472
1900
  declare const VERSION = "0.0.0";
1473
- export { type AuthApiCallIR, CONTAINERS_FILENAME, CodegenDiagnosticError, type CodegenOptions, type CodegenResult, type ContainerIR, type CronJobIR, type DriftChange, type EmitAppOptions, type FieldSnapshot, type FunctionIR, GENERATED_HEADER, type HttpRouteIR, type IndexIR, type IndexSnapshot, type InsertWriteIR, LUNORA_ERROR_CODES, type MaskProcedureIR, type MigrationIR, OPENRPC_VERSION, type OpenApiEmitInput, type OpenRpcEmitInput, type ProjectIR, type QueryReadIR, type RelationSnapshot, type RlsMetadataIR, type RlsPolicyIR, type RlsProcedureIR, type RlsRoleIR, SCHEMA_SNAPSHOT_FILENAME, SCHEMA_SNAPSHOT_VERSION, type SchemaDrift, type SchemaDriftDecision, type SchemaIR, type SchemaSnapshot, SchemaSnapshotParseError, type StorageRuleIR, type StorageRulesMetadataIR, type TableIR, type TableSnapshot, VERSION, type ValidatorIR, type VectorIndexIR, WORKFLOWS_FILENAME, type WorkflowIR, buildOpenApiDocument, buildOpenRpcDocument, buildSchemaSnapshot, createCodegenProject, diagnosticAt, diffSchemaSnapshots, discoverAuthApiCalls, discoverContainers, discoverCrons, discoverFunctions, discoverHttpRoutes, discoverInserts, discoverMaskProcedures, discoverMigrations, discoverNondeterministicCalls, discoverQueries, discoverRlsMetadata, discoverRlsProcedures, discoverSchema, discoverStorageRulesMetadata, discoverWorkflows, emitApi, emitApp, emitContainers, emitCrons, emitDataModel, emitDrizzleSchema, emitFunctions, emitOpenApi, emitOpenApiModule, emitOpenRpc, emitOpenRpcModule, emitServer, emitShard, emitVectors, emitWorkflows, emitWranglerCronTriggers, evaluateSchemaDrift, formatAdvisories, lintSchema, parseSchemaSnapshot, refreshCodegenProject, runCodegen, schemaFromIr, serializeSchemaSnapshot, validatorIrToJsonSchema };
1901
+ export { type AuthApiCallIR, CONTAINERS_FILENAME, CodegenDiagnosticError, type CodegenOptions, type CodegenResult, type ContainerIR, type CronJobIR, type DriftChange, type EmitAppOptions, FLAGS_FILENAME, type FieldSnapshot, type FlagsIR, type FunctionIR, GENERATED_HEADER, type HttpRouteIR, type IndexIR, type IndexSnapshot, type InsertWriteIR, LUNORA_ERROR_CODES, LUNORA_SOLUTION_RULES, type LunoraSolution, type LunoraSolutionRule, MUTATORS_FILENAME, type MaskProcedureIR, type MigrationIR, type MutatorIR, OPENRPC_VERSION, type OpenApiEmitInput, type OpenRpcEmitInput, type ProjectIR, QUEUES_FILENAME, type QueryReadIR, type QueueIR, type R2sqlCallIR, type RelationSnapshot, type RlsMetadataIR, type RlsPolicyIR, type RlsProcedureIR, type RlsRoleIR, SCHEMA_SNAPSHOT_FILENAME, SCHEMA_SNAPSHOT_VERSION, SHAPES_FILENAME, type SchemaDrift, type SchemaDriftDecision, type SchemaIR, type SchemaSnapshot, SchemaSnapshotParseError, type ShapeIR, type StorageRuleIR, type StorageRulesMetadataIR, type TableIR, type TableSnapshot, VERSION, type ValidatorIR, type VectorIndexIR, WORKFLOWS_FILENAME, type WorkflowIR, buildOpenApiDocument, buildOpenRpcDocument, buildSchemaSnapshot, createCodegenProject, diagnosticAt, diffSchemaSnapshots, discoverAuthApiCalls, discoverContainers, discoverCrons, discoverFlags, discoverFunctions, discoverHttpRoutes, discoverInserts, discoverMaskProcedures, discoverMigrations, discoverMutators, discoverNondeterministicCalls, discoverQueries, discoverQueues, discoverR2sqlCalls, discoverRlsMetadata, discoverRlsProcedures, discoverSchema, discoverShapes, discoverStorageRulesMetadata, discoverWorkflows, emitApi, emitApp, emitCollections, emitContainers, emitCrons, emitDataModel, emitDrizzleSchema, emitFunctions, emitOpenApi, emitOpenApiModule, emitOpenRpc, emitOpenRpcModule, emitServer, emitShard, emitVectors, emitWorkflows, emitWranglerCronTriggers, evaluateSchemaDrift, findLunoraSolution, formatAdvisories, lintSchema, parseSchemaSnapshot, refreshCodegenProject, runCodegen, schemaFromIr, serializeSchemaSnapshot, validatorIrToJsonSchema };