@lunora/codegen 1.0.0-alpha.146 → 1.0.0-alpha.148

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -9,12 +9,50 @@ import { JsonSchema } from '@lunora/values';
9
9
  import { LanguageName } from 'quicktype-core';
10
10
  /** Current snapshot format version. Bumped if the structural shape below changes. */
11
11
  declare const SCHEMA_SNAPSHOT_VERSION: 1;
12
- /** A single field's structural shape: its value kind and whether it is optional. */
12
+ /**
13
+ * A single field's structural shape.
14
+ *
15
+ * `kind` + `optional` were once the whole record, which made every change INSIDE
16
+ * a validator invisible to the diff, to the serialized baseline, and to the
17
+ * content hash — `v.id("users")` → `v.id("orgs")`, `v.array(v.string())` →
18
+ * `v.array(v.bigint())` (which changes the storage projection), a swapped union
19
+ * member, an added `.unique()`. Zero drift, byte-identical snapshot, same hash,
20
+ * so `recordSchemaVersion` did not even append a ledger row.
21
+ *
22
+ * Everything past `optional` is therefore recorded too. All of it is declared
23
+ * OPTIONAL so a baseline written before the deepening still parses (no
24
+ * {@link SCHEMA_SNAPSHOT_VERSION} bump, which `parseSnapshotJson` would turn into
25
+ * a hard reject with no upgrade path) — see {@link recordsFieldDetail} for how the
26
+ * differ tells "this baseline predates the detail" from "this field has none".
27
+ */
13
28
  interface FieldSnapshot {
29
+ /** `v.object({…})` member shapes, key-sorted. */
30
+ fields?: Record<string, FieldSnapshot>;
31
+ /** `v.record(key, …)` key shape. */
32
+ key?: FieldSnapshot;
14
33
  /** The validator kind (`string`, `number`, `id`, `object`, …) after unwrapping `v.optional`. */
15
34
  kind: string;
35
+ /** `v.literal(value)` — the literal as source text. */
36
+ literal?: string;
37
+ /** `v.union(…)` members, in canonical (not declaration) order — a union is a set. */
38
+ members?: ReadonlyArray<FieldSnapshot>;
39
+ /** `.nullable()` — the column accepts SQL NULL. Always written by a current snapshot. */
40
+ nullable?: boolean;
41
+ /** `v.array(inner)` element / `v.record(…, value)` value shape. */
42
+ of?: FieldSnapshot;
16
43
  /** True when declared `v.optional(...)` — accepts `undefined` / absent on insert. */
17
44
  optional: boolean;
45
+ /** `v.id("table")` — the referenced table. */
46
+ ref?: string;
47
+ /**
48
+ * A `.check()`/`.max()`/`.email()`/… predicate is declared on the column. Only
49
+ * its PRESENCE is knowable — the IR cannot represent the closure — so
50
+ * `.max(200)` → `.max(500)` stays invisible; adding the first refinement to a
51
+ * populated column does not.
52
+ */
53
+ refined?: boolean;
54
+ /** `.unique()`. Always written by a current snapshot — see {@link recordsFieldDetail}. */
55
+ unique?: boolean;
18
56
  }
19
57
  /** A single secondary index's structural shape. */
20
58
  interface IndexSnapshot {
@@ -113,7 +151,7 @@ interface DriftChange {
113
151
  /** The table this change belongs to. Always set when `scope` is `"table"`. */
114
152
  table?: string;
115
153
  /** A machine-readable change discriminator. */
116
- type: "addedIndex" | "addedOptionalField" | "addedRelation" | "addedRequiredField" | "addedTable" | "changedFieldKind" | "changedIndex" | "changedJurisdiction" | "changedShardMode" | "fieldOptionalToRequired" | "fieldRequiredToOptional" | "removedField" | "removedIndex" | "removedRelation" | "removedTable";
154
+ type: "addedFieldConstraint" | "addedIndex" | "addedOptionalField" | "addedRelation" | "addedRequiredField" | "addedTable" | "changedFieldKind" | "changedFieldShape" | "changedIndex" | "changedJurisdiction" | "changedShardMode" | "fieldOptionalToRequired" | "fieldRequiredToOptional" | "relaxedFieldConstraint" | "removedField" | "removedIndex" | "removedRelation" | "removedTable" | "widenedFieldShape";
117
155
  }
118
156
  /** The result of diffing two snapshots: every classified change. */
119
157
  interface SchemaDrift {
@@ -3381,9 +3419,8 @@ declare const emitOpenRpcModule: (document_: Record<string, unknown>) => string;
3381
3419
  * churn) — see `sortKeys` in `shared/schema-snapshot.ts` for why that ordering
3382
3420
  * must not be locale-aware.
3383
3421
  *
3384
- * Field / index / relation keys are deliberately NOT sorted: they are emitted in
3385
- * declaration order from the schema source, which is already deterministic for a
3386
- * given source file and keeps the snapshot readable next to the schema it mirrors.
3422
+ * Field / index / relation keys are sorted the same way, by `tableSnapshotOf` —
3423
+ * see there for why declaration order was the wrong default for a hashed file.
3387
3424
  */
3388
3425
  declare const buildSchemaSnapshot: (schema: SchemaIR, migrationIds: ReadonlyArray<string>) => SchemaSnapshot;
3389
3426
  /**
package/dist/index.d.ts CHANGED
@@ -9,12 +9,50 @@ import { JsonSchema } from '@lunora/values';
9
9
  import { LanguageName } from 'quicktype-core';
10
10
  /** Current snapshot format version. Bumped if the structural shape below changes. */
11
11
  declare const SCHEMA_SNAPSHOT_VERSION: 1;
12
- /** A single field's structural shape: its value kind and whether it is optional. */
12
+ /**
13
+ * A single field's structural shape.
14
+ *
15
+ * `kind` + `optional` were once the whole record, which made every change INSIDE
16
+ * a validator invisible to the diff, to the serialized baseline, and to the
17
+ * content hash — `v.id("users")` → `v.id("orgs")`, `v.array(v.string())` →
18
+ * `v.array(v.bigint())` (which changes the storage projection), a swapped union
19
+ * member, an added `.unique()`. Zero drift, byte-identical snapshot, same hash,
20
+ * so `recordSchemaVersion` did not even append a ledger row.
21
+ *
22
+ * Everything past `optional` is therefore recorded too. All of it is declared
23
+ * OPTIONAL so a baseline written before the deepening still parses (no
24
+ * {@link SCHEMA_SNAPSHOT_VERSION} bump, which `parseSnapshotJson` would turn into
25
+ * a hard reject with no upgrade path) — see {@link recordsFieldDetail} for how the
26
+ * differ tells "this baseline predates the detail" from "this field has none".
27
+ */
13
28
  interface FieldSnapshot {
29
+ /** `v.object({…})` member shapes, key-sorted. */
30
+ fields?: Record<string, FieldSnapshot>;
31
+ /** `v.record(key, …)` key shape. */
32
+ key?: FieldSnapshot;
14
33
  /** The validator kind (`string`, `number`, `id`, `object`, …) after unwrapping `v.optional`. */
15
34
  kind: string;
35
+ /** `v.literal(value)` — the literal as source text. */
36
+ literal?: string;
37
+ /** `v.union(…)` members, in canonical (not declaration) order — a union is a set. */
38
+ members?: ReadonlyArray<FieldSnapshot>;
39
+ /** `.nullable()` — the column accepts SQL NULL. Always written by a current snapshot. */
40
+ nullable?: boolean;
41
+ /** `v.array(inner)` element / `v.record(…, value)` value shape. */
42
+ of?: FieldSnapshot;
16
43
  /** True when declared `v.optional(...)` — accepts `undefined` / absent on insert. */
17
44
  optional: boolean;
45
+ /** `v.id("table")` — the referenced table. */
46
+ ref?: string;
47
+ /**
48
+ * A `.check()`/`.max()`/`.email()`/… predicate is declared on the column. Only
49
+ * its PRESENCE is knowable — the IR cannot represent the closure — so
50
+ * `.max(200)` → `.max(500)` stays invisible; adding the first refinement to a
51
+ * populated column does not.
52
+ */
53
+ refined?: boolean;
54
+ /** `.unique()`. Always written by a current snapshot — see {@link recordsFieldDetail}. */
55
+ unique?: boolean;
18
56
  }
19
57
  /** A single secondary index's structural shape. */
20
58
  interface IndexSnapshot {
@@ -113,7 +151,7 @@ interface DriftChange {
113
151
  /** The table this change belongs to. Always set when `scope` is `"table"`. */
114
152
  table?: string;
115
153
  /** A machine-readable change discriminator. */
116
- type: "addedIndex" | "addedOptionalField" | "addedRelation" | "addedRequiredField" | "addedTable" | "changedFieldKind" | "changedIndex" | "changedJurisdiction" | "changedShardMode" | "fieldOptionalToRequired" | "fieldRequiredToOptional" | "removedField" | "removedIndex" | "removedRelation" | "removedTable";
154
+ type: "addedFieldConstraint" | "addedIndex" | "addedOptionalField" | "addedRelation" | "addedRequiredField" | "addedTable" | "changedFieldKind" | "changedFieldShape" | "changedIndex" | "changedJurisdiction" | "changedShardMode" | "fieldOptionalToRequired" | "fieldRequiredToOptional" | "relaxedFieldConstraint" | "removedField" | "removedIndex" | "removedRelation" | "removedTable" | "widenedFieldShape";
117
155
  }
118
156
  /** The result of diffing two snapshots: every classified change. */
119
157
  interface SchemaDrift {
@@ -3381,9 +3419,8 @@ declare const emitOpenRpcModule: (document_: Record<string, unknown>) => string;
3381
3419
  * churn) — see `sortKeys` in `shared/schema-snapshot.ts` for why that ordering
3382
3420
  * must not be locale-aware.
3383
3421
  *
3384
- * Field / index / relation keys are deliberately NOT sorted: they are emitted in
3385
- * declaration order from the schema source, which is already deterministic for a
3386
- * given source file and keeps the snapshot readable next to the schema it mirrors.
3422
+ * Field / index / relation keys are sorted the same way, by `tableSnapshotOf` —
3423
+ * see there for why declaration order was the wrong default for a hashed file.
3387
3424
  */
3388
3425
  declare const buildSchemaSnapshot: (schema: SchemaIR, migrationIds: ReadonlyArray<string>) => SchemaSnapshot;
3389
3426
  /**
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{SCHEMA_SNAPSHOT_VERSION as t,diffSchemaSnapshots as s,serializeSchemaSnapshot as a}from"./packem_shared/SCHEMA_SNAPSHOT_VERSION-CTWRkAF5.mjs";import{formatAdvisories as m,lintSchema as d,toAdvisorContext as f}from"./packem_shared/formatAdvisories-CkEu1eye.mjs";import{describeErrorLevelFindings as c,errorAdvisoryNames as n,errorPlatformDiagnosticNames as l}from"./packem_shared/describeErrorLevelFindings-D23VSkFP.mjs";import{CodegenDiagnosticError as x,diagnosticAt as E}from"./packem_shared/CodegenDiagnosticError-BUXlG3P-.mjs";import{AGENTS_FILENAME as u,discoverAgents as v}from"./packem_shared/AGENTS_FILENAME-B1Abt3Gl.mjs";import{default as g}from"./packem_shared/discoverAuthApiCalls-DoNQSgso.mjs";import{CONTAINERS_FILENAME as R,discoverContainers as C}from"./packem_shared/CONTAINERS_FILENAME-CtcysaKS.mjs";import{default as h}from"./packem_shared/discoverCrons-DCxl4hty.mjs";import{FLAGS_FILENAME as T,discoverFlags as I}from"./packem_shared/FLAGS_FILENAME-B3VZ6vTw.mjs";import{default as F}from"./packem_shared/discoverFunctions-C29Tvxas.mjs";import{default as P}from"./packem_shared/discoverHttpRoutes-CFIXlUy4.mjs";import{default as G}from"./packem_shared/discoverHyperdriveCalls-DTq4PKT5.mjs";import{default as b}from"./packem_shared/discoverInserts-qU5F4W4g.mjs";import{d as y}from"./packem_shared/index-xGhyK9J_.mjs";import{default as j}from"./packem_shared/discoverMigrations-BFkJQ8Sy.mjs";import{MUTATORS_FILENAME as V,discoverMutators as z}from"./packem_shared/MUTATORS_FILENAME-BKSzaCkq.mjs";import{default as w}from"./packem_shared/discoverNondeterministicCalls-B-NNzzPW.mjs";import{NOTIFY_FILENAME as B,discoverNotifyCalls as J,discoverNotifyConfig as Y}from"./packem_shared/NOTIFY_FILENAME-CKO5gtGe.mjs";import{default as Z}from"./packem_shared/readPackageDependencies-C6h6FZuP.mjs";import{d as ee}from"./packem_shared/queries-Ddvo5dCs.mjs";import{QUEUES_FILENAME as oe,discoverQueues as te}from"./packem_shared/QUEUES_FILENAME-C-pzLGy4.mjs";import{default as ae}from"./packem_shared/discoverR2sqlCalls-C2GtrFnl.mjs";import{default as me}from"./packem_shared/discoverRlsProcedures-fAhxiIyD.mjs";import{default as fe}from"./packem_shared/discoverRlsMetadata-BKcUnSNr.mjs";import{discoverSandboxUsage as ce}from"./packem_shared/discoverSandboxUsage-CJhnKA0_.mjs";import{default as le}from"./packem_shared/discoverSchema-CubSTjtY.mjs";import{SHAPES_FILENAME as xe,discoverShapes as Ee}from"./packem_shared/SHAPES_FILENAME-D3N7xcEk.mjs";import{default as ue}from"./packem_shared/discoverStorageRulesMetadata-C7XmORWp.mjs";import{WORKFLOWS_FILENAME as Ne,discoverWorkflows as ge}from"./packem_shared/WORKFLOWS_FILENAME-BfvqsG9Z.mjs";import{G as Re,e as Ce,a as Me,b as he,c as _e,d as Te,f as Ie,g as Le,h as Fe,i as De,j as Pe,k as Ue,l as Ge,m as He}from"./packem_shared/emit-BcAkLUfn.mjs";import{emitApp as ke}from"./packem_shared/emitApp-DoR55vKV.mjs";import{buildOpenApiDocument as We,emitOpenApi as je,emitOpenApiModule as Ke}from"./packem_shared/buildOpenApiDocument-D40ZeYsu.mjs";import{OPENRPC_VERSION as ze,buildOpenRpcDocument as Qe,emitOpenRpc as we,emitOpenRpcModule as qe}from"./packem_shared/OPENRPC_VERSION-CdKqq_QT.mjs";import{DEFAULT_TARGET as Je,platformMatrixIds as Ye,readProjectTarget as Xe,resolveCodegenTarget as Ze}from"./packem_shared/DEFAULT_TARGET-BvzxeWRZ.mjs";import{SCHEMA_SNAPSHOT_FILENAME as er,createCodegenProject as rr,findTsconfig as or,refreshCodegenProject as tr,runCodegen as sr}from"./packem_shared/SCHEMA_SNAPSHOT_FILENAME-CeOctEWC.mjs";import{SchemaSnapshotParseError as ir,buildSchemaSnapshot as mr,evaluateSchemaDrift as dr,parseSchemaSnapshot as fr}from"./packem_shared/SchemaSnapshotParseError-qXCOA7dD.mjs";import{schemaFromIr as cr}from"./packem_shared/schemaFromIr-BWFnvCVg.mjs";import{LUNORA_ERROR_CODES as lr,validatorIrToJsonSchema as Sr}from"./packem_shared/LUNORA_ERROR_CODES-BYg8Lpgb.mjs";import{SDK_LANGUAGES as Er,SDK_TARGETS as Ar,generateSdk as ur}from"./packem_shared/SDK_LANGUAGES-CFyux-74.mjs";import{redact as Nr,secretKindOf as gr}from"./packem_shared/redact-Cy14LEnc.mjs";import{MESSAGE_SOLUTIONS as Rr,findSolutionByMessage as Cr}from"@lunora/errors";import{isTypedSchema as hr}from"./packem_shared/isTypedSchema-B_qlBbE-.mjs";const e="0.0.0";export{u as AGENTS_FILENAME,R as CONTAINERS_FILENAME,x as CodegenDiagnosticError,Je as DEFAULT_TARGET,T as FLAGS_FILENAME,Re as GENERATED_HEADER,lr as LUNORA_ERROR_CODES,Rr as LUNORA_SOLUTION_RULES,V as MUTATORS_FILENAME,B as NOTIFY_FILENAME,ze as OPENRPC_VERSION,oe as QUEUES_FILENAME,er as SCHEMA_SNAPSHOT_FILENAME,t as SCHEMA_SNAPSHOT_VERSION,Er as SDK_LANGUAGES,Ar as SDK_TARGETS,xe as SHAPES_FILENAME,ir as SchemaSnapshotParseError,e as VERSION,Ne as WORKFLOWS_FILENAME,We as buildOpenApiDocument,Qe as buildOpenRpcDocument,mr as buildSchemaSnapshot,rr as createCodegenProject,c as describeErrorLevelFindings,E as diagnosticAt,s as diffSchemaSnapshots,v as discoverAgents,g as discoverAuthApiCalls,C as discoverContainers,h as discoverCrons,I as discoverFlags,F as discoverFunctions,P as discoverHttpRoutes,G as discoverHyperdriveCalls,b as discoverInserts,y as discoverMaskProcedures,j as discoverMigrations,z as discoverMutators,w as discoverNondeterministicCalls,J as discoverNotifyCalls,Y as discoverNotifyConfig,ee as discoverQueries,te as discoverQueues,ae as discoverR2sqlCalls,fe as discoverRlsMetadata,me as discoverRlsProcedures,ce as discoverSandboxUsage,le as discoverSchema,Ee as discoverShapes,ue as discoverStorageRulesMetadata,ge as discoverWorkflows,Ce as emitAgents,Me as emitApi,ke as emitApp,he as emitCollections,_e as emitContainers,Te as emitCrons,Ie as emitDataModel,Le as emitDrizzleSchema,Fe as emitFunctions,je as emitOpenApi,Ke as emitOpenApiModule,we as emitOpenRpc,qe as emitOpenRpcModule,De as emitServer,Pe as emitShard,Ue as emitVectors,Ge as emitWorkflows,He as emitWranglerCronTriggers,n as errorAdvisoryNames,l as errorPlatformDiagnosticNames,dr as evaluateSchemaDrift,Cr as findLunoraSolution,or as findTsconfig,m as formatAdvisories,ur as generateSdk,hr as isTypedSchema,d as lintSchema,fr as parseSchemaSnapshot,Ye as platformMatrixIds,Z as readPackageDependencies,Xe as readProjectTarget,Nr as redact,tr as refreshCodegenProject,Ze as resolveCodegenTarget,sr as runCodegen,cr as schemaFromIr,gr as secretKindOf,a as serializeSchemaSnapshot,f as toAdvisorContext,Sr as validatorIrToJsonSchema};
1
+ import{SCHEMA_SNAPSHOT_VERSION as t,diffSchemaSnapshots as s,serializeSchemaSnapshot as a}from"./packem_shared/SCHEMA_SNAPSHOT_VERSION-B1BUjuG5.mjs";import{formatAdvisories as m,lintSchema as d,toAdvisorContext as f}from"./packem_shared/formatAdvisories-CkEu1eye.mjs";import{describeErrorLevelFindings as c,errorAdvisoryNames as n,errorPlatformDiagnosticNames as l}from"./packem_shared/describeErrorLevelFindings-D23VSkFP.mjs";import{CodegenDiagnosticError as x,diagnosticAt as E}from"./packem_shared/CodegenDiagnosticError-BUXlG3P-.mjs";import{AGENTS_FILENAME as u,discoverAgents as v}from"./packem_shared/AGENTS_FILENAME-B1Abt3Gl.mjs";import{default as g}from"./packem_shared/discoverAuthApiCalls-DoNQSgso.mjs";import{CONTAINERS_FILENAME as R,discoverContainers as C}from"./packem_shared/CONTAINERS_FILENAME-CtcysaKS.mjs";import{default as h}from"./packem_shared/discoverCrons-DCxl4hty.mjs";import{FLAGS_FILENAME as T,discoverFlags as I}from"./packem_shared/FLAGS_FILENAME-B3VZ6vTw.mjs";import{default as F}from"./packem_shared/discoverFunctions-C29Tvxas.mjs";import{default as P}from"./packem_shared/discoverHttpRoutes-CFIXlUy4.mjs";import{default as G}from"./packem_shared/discoverHyperdriveCalls-DTq4PKT5.mjs";import{default as b}from"./packem_shared/discoverInserts-qU5F4W4g.mjs";import{d as y}from"./packem_shared/index-xGhyK9J_.mjs";import{default as j}from"./packem_shared/discoverMigrations-BFkJQ8Sy.mjs";import{MUTATORS_FILENAME as V,discoverMutators as z}from"./packem_shared/MUTATORS_FILENAME-BKSzaCkq.mjs";import{default as w}from"./packem_shared/discoverNondeterministicCalls-B-NNzzPW.mjs";import{NOTIFY_FILENAME as B,discoverNotifyCalls as J,discoverNotifyConfig as Y}from"./packem_shared/NOTIFY_FILENAME-CKO5gtGe.mjs";import{default as Z}from"./packem_shared/readPackageDependencies-C6h6FZuP.mjs";import{d as ee}from"./packem_shared/queries-Ddvo5dCs.mjs";import{QUEUES_FILENAME as oe,discoverQueues as te}from"./packem_shared/QUEUES_FILENAME-C-pzLGy4.mjs";import{default as ae}from"./packem_shared/discoverR2sqlCalls-C2GtrFnl.mjs";import{default as me}from"./packem_shared/discoverRlsProcedures-fAhxiIyD.mjs";import{default as fe}from"./packem_shared/discoverRlsMetadata-BKcUnSNr.mjs";import{discoverSandboxUsage as ce}from"./packem_shared/discoverSandboxUsage-CJhnKA0_.mjs";import{default as le}from"./packem_shared/discoverSchema-CubSTjtY.mjs";import{SHAPES_FILENAME as xe,discoverShapes as Ee}from"./packem_shared/SHAPES_FILENAME-D3N7xcEk.mjs";import{default as ue}from"./packem_shared/discoverStorageRulesMetadata-C7XmORWp.mjs";import{WORKFLOWS_FILENAME as Ne,discoverWorkflows as ge}from"./packem_shared/WORKFLOWS_FILENAME-BfvqsG9Z.mjs";import{G as Re,e as Ce,a as Me,b as he,c as _e,d as Te,f as Ie,g as Le,h as Fe,i as De,j as Pe,k as Ue,l as Ge,m as He}from"./packem_shared/emit-DHDqyZ_P.mjs";import{emitApp as ke}from"./packem_shared/emitApp-B1pTKVES.mjs";import{buildOpenApiDocument as We,emitOpenApi as je,emitOpenApiModule as Ke}from"./packem_shared/buildOpenApiDocument-CyoTgJNE.mjs";import{OPENRPC_VERSION as ze,buildOpenRpcDocument as Qe,emitOpenRpc as we,emitOpenRpcModule as qe}from"./packem_shared/OPENRPC_VERSION-C6usyZYe.mjs";import{DEFAULT_TARGET as Je,platformMatrixIds as Ye,readProjectTarget as Xe,resolveCodegenTarget as Ze}from"./packem_shared/DEFAULT_TARGET-BvzxeWRZ.mjs";import{SCHEMA_SNAPSHOT_FILENAME as er,createCodegenProject as rr,findTsconfig as or,refreshCodegenProject as tr,runCodegen as sr}from"./packem_shared/SCHEMA_SNAPSHOT_FILENAME-BOb60wCS.mjs";import{SchemaSnapshotParseError as ir,buildSchemaSnapshot as mr,evaluateSchemaDrift as dr,parseSchemaSnapshot as fr}from"./packem_shared/SchemaSnapshotParseError-BA80Pxar.mjs";import{schemaFromIr as cr}from"./packem_shared/schemaFromIr-BWFnvCVg.mjs";import{LUNORA_ERROR_CODES as lr,validatorIrToJsonSchema as Sr}from"./packem_shared/LUNORA_ERROR_CODES-BYg8Lpgb.mjs";import{SDK_LANGUAGES as Er,SDK_TARGETS as Ar,generateSdk as ur}from"./packem_shared/SDK_LANGUAGES-CFyux-74.mjs";import{redact as Nr,secretKindOf as gr}from"./packem_shared/redact-Cy14LEnc.mjs";import{MESSAGE_SOLUTIONS as Rr,findSolutionByMessage as Cr}from"@lunora/errors";import{isTypedSchema as hr}from"./packem_shared/isTypedSchema-B_qlBbE-.mjs";const e="0.0.0";export{u as AGENTS_FILENAME,R as CONTAINERS_FILENAME,x as CodegenDiagnosticError,Je as DEFAULT_TARGET,T as FLAGS_FILENAME,Re as GENERATED_HEADER,lr as LUNORA_ERROR_CODES,Rr as LUNORA_SOLUTION_RULES,V as MUTATORS_FILENAME,B as NOTIFY_FILENAME,ze as OPENRPC_VERSION,oe as QUEUES_FILENAME,er as SCHEMA_SNAPSHOT_FILENAME,t as SCHEMA_SNAPSHOT_VERSION,Er as SDK_LANGUAGES,Ar as SDK_TARGETS,xe as SHAPES_FILENAME,ir as SchemaSnapshotParseError,e as VERSION,Ne as WORKFLOWS_FILENAME,We as buildOpenApiDocument,Qe as buildOpenRpcDocument,mr as buildSchemaSnapshot,rr as createCodegenProject,c as describeErrorLevelFindings,E as diagnosticAt,s as diffSchemaSnapshots,v as discoverAgents,g as discoverAuthApiCalls,C as discoverContainers,h as discoverCrons,I as discoverFlags,F as discoverFunctions,P as discoverHttpRoutes,G as discoverHyperdriveCalls,b as discoverInserts,y as discoverMaskProcedures,j as discoverMigrations,z as discoverMutators,w as discoverNondeterministicCalls,J as discoverNotifyCalls,Y as discoverNotifyConfig,ee as discoverQueries,te as discoverQueues,ae as discoverR2sqlCalls,fe as discoverRlsMetadata,me as discoverRlsProcedures,ce as discoverSandboxUsage,le as discoverSchema,Ee as discoverShapes,ue as discoverStorageRulesMetadata,ge as discoverWorkflows,Ce as emitAgents,Me as emitApi,ke as emitApp,he as emitCollections,_e as emitContainers,Te as emitCrons,Ie as emitDataModel,Le as emitDrizzleSchema,Fe as emitFunctions,je as emitOpenApi,Ke as emitOpenApiModule,we as emitOpenRpc,qe as emitOpenRpcModule,De as emitServer,Pe as emitShard,Ue as emitVectors,Ge as emitWorkflows,He as emitWranglerCronTriggers,n as errorAdvisoryNames,l as errorPlatformDiagnosticNames,dr as evaluateSchemaDrift,Cr as findLunoraSolution,or as findTsconfig,m as formatAdvisories,ur as generateSdk,hr as isTypedSchema,d as lintSchema,fr as parseSchemaSnapshot,Ye as platformMatrixIds,Z as readPackageDependencies,Xe as readProjectTarget,Nr as redact,tr as refreshCodegenProject,Ze as resolveCodegenTarget,sr as runCodegen,cr as schemaFromIr,gr as secretKindOf,a as serializeSchemaSnapshot,f as toAdvisorContext,Sr as validatorIrToJsonSchema};
@@ -1 +1 @@
1
- import"./SCHEMA_SNAPSHOT_VERSION-CTWRkAF5.mjs";import{G as t,U as m,n as r,e as o,a as n,b as l,c as A,d as E,f as S,g,h as C,o as c,p as d,i as p,j as u,k as D,l as f,m as h}from"./emit-BcAkLUfn.mjs";import"./paths-C-9fwEgQ.mjs";export{t as GENERATED_HEADER,m as UMBRELLA_BASE_PACKAGES,r as buildStorageColumns,o as emitAgents,n as emitApi,l as emitCollections,A as emitContainers,E as emitCrons,S as emitDataModel,g as emitDrizzleSchema,C as emitFunctions,c as emitQueues,d as emitSeed,p as emitServer,u as emitShard,D as emitVectors,f as emitWorkflows,h as emitWranglerCronTriggers};
1
+ import"./SCHEMA_SNAPSHOT_VERSION-B1BUjuG5.mjs";import{G as t,U as m,n as r,e as o,a as n,b as l,c as A,d as E,f as S,g,h as C,o as c,p as d,i as p,j as u,k as D,l as f,m as h}from"./emit-DHDqyZ_P.mjs";import"./paths-C-9fwEgQ.mjs";export{t as GENERATED_HEADER,m as UMBRELLA_BASE_PACKAGES,r as buildStorageColumns,o as emitAgents,n as emitApi,l as emitCollections,A as emitContainers,E as emitCrons,S as emitDataModel,g as emitDrizzleSchema,C as emitFunctions,c as emitQueues,d as emitSeed,p as emitServer,u as emitShard,D as emitVectors,f as emitWorkflows,h as emitWranglerCronTriggers};
@@ -1,3 +1,3 @@
1
- import{G as c}from"./emit-BcAkLUfn.mjs";import{s as u}from"./paths-C-9fwEgQ.mjs";import{validatorIrToJsonSchema as m,objectSchema as p,LUNORA_ERROR_CODES as i}from"./LUNORA_ERROR_CODES-BYg8Lpgb.mjs";const l="1.3.2",d={description:"Result is TS-inferred from the function's return type (no `.output()` declared); best-effort — any JSON."},R=e=>{const n=u(e.filePath),o=`${n}:${e.exportName}`;return{description:`Invoke the \`${e.kind}\` \`${o}\` over the Lunora RPC envelope (POST /_lunora/rpc, body \`{ "functionPath": "${o}", "args": { … } }\`).`,errors:i.map((r,s)=>({code:-32e3-s,data:{code:r},message:r})),name:o,params:[{description:"The function's argument object (the RPC envelope's `args`).",name:"args",required:Object.keys(e.args).length>0,schema:p(e.args)}],result:{name:"result",schema:e.output?m(e.output):d},summary:`${e.kind}: ${o}`,"x-lunora-function-kind":e.kind,"x-tags":[{name:n}]}},g=e=>{const n=e.version??"0.0.0",r=e.functions.filter(t=>t.visibility!=="internal"&&t.kind!=="stream").map(t=>R(t)).toSorted((t,a)=>t.name.localeCompare(a.name));return{info:{description:"Auto-generated from @lunora/values-typed functions by @lunora/codegen. Do not edit — run `lunora codegen` to regenerate.",title:"Lunora RPC",version:n},methods:r,openrpc:l}},S=e=>`${JSON.stringify(g(e),void 0,2)}
1
+ import{G as c}from"./emit-DHDqyZ_P.mjs";import{s as u}from"./paths-C-9fwEgQ.mjs";import{validatorIrToJsonSchema as m,objectSchema as p,LUNORA_ERROR_CODES as i}from"./LUNORA_ERROR_CODES-BYg8Lpgb.mjs";const l="1.3.2",d={description:"Result is TS-inferred from the function's return type (no `.output()` declared); best-effort — any JSON."},R=e=>{const n=u(e.filePath),o=`${n}:${e.exportName}`;return{description:`Invoke the \`${e.kind}\` \`${o}\` over the Lunora RPC envelope (POST /_lunora/rpc, body \`{ "functionPath": "${o}", "args": { … } }\`).`,errors:i.map((r,s)=>({code:-32e3-s,data:{code:r},message:r})),name:o,params:[{description:"The function's argument object (the RPC envelope's `args`).",name:"args",required:Object.keys(e.args).length>0,schema:p(e.args)}],result:{name:"result",schema:e.output?m(e.output):d},summary:`${e.kind}: ${o}`,"x-lunora-function-kind":e.kind,"x-tags":[{name:n}]}},g=e=>{const n=e.version??"0.0.0",r=e.functions.filter(t=>t.visibility!=="internal"&&t.kind!=="stream").map(t=>R(t)).toSorted((t,a)=>t.name.localeCompare(a.name));return{info:{description:"Auto-generated from @lunora/values-typed functions by @lunora/codegen. Do not edit — run `lunora codegen` to regenerate.",title:"Lunora RPC",version:n},methods:r,openrpc:l}},S=e=>`${JSON.stringify(g(e),void 0,2)}
2
2
  `,v=e=>`${c}export const openRpcSpec: Record<string, unknown> = ${JSON.stringify(e,void 0,4)};
3
3
  `;export{l as OPENRPC_VERSION,g as buildOpenRpcDocument,S as emitOpenRpc,v as emitOpenRpcModule};
@@ -1,4 +1,4 @@
1
- import{existsSync as b,mkdirSync as ns,readFileSync as At,writeFileSync as rs,rmSync as is}from"node:fs";import{join as f,dirname as pe}from"node:path";import{performance as ge}from"node:perf_hooks";import{runAdvisor as os}from"@lunora/advisor";import{LunoraError as L}from"@lunora/errors";import{SyntaxKind as l,Node as o,Project as Xe}from"ts-morph";import{serializeSchemaSnapshot as as}from"./SCHEMA_SNAPSHOT_VERSION-CTWRkAF5.mjs";import{toAdvisorContext as cs}from"./formatAdvisories-CkEu1eye.mjs";import{s as ls}from"./paths-C-9fwEgQ.mjs";import{discoverAgents as us}from"./AGENTS_FILENAME-B1Abt3Gl.mjs";import{discoverContainers as ds}from"./CONTAINERS_FILENAME-CtcysaKS.mjs";import{diagnosticAt as ne}from"./CodegenDiagnosticError-BUXlG3P-.mjs";import{b as re}from"./module-specifiers-WF8iAydP.mjs";import{C as me,i as fs,f as ps,n as gs,j as ms,b as hs,c as xs,l as Es,e as vs,o as Ss,d as As,k as ys,g as Ns,p as bs,m as Ps,a as Is,h as ws}from"./emit-BcAkLUfn.mjs";import{l as g,a as v,f as P,p as N,g as yt,j as Nt,k as ve,h as Ts,i as D,b as Ze,r as bt,e as Cs}from"./ast-BYoSZlae.mjs";import Fs from"./readPackageDependencies-C6h6FZuP.mjs";import{discoverQueues as Os}from"./QUEUES_FILENAME-C-pzLGy4.mjs";import{discoverSandboxUsage as Rs}from"./discoverSandboxUsage-CJhnKA0_.mjs";import Ls from"./discoverStorageRulesMetadata-C7XmORWp.mjs";import{discoverWorkflows as Ds}from"./WORKFLOWS_FILENAME-BfvqsG9Z.mjs";import{gatePlatformFeatures as ks,resolveCodegenTarget as Ms}from"./DEFAULT_TARGET-BvzxeWRZ.mjs";import{i as F,a as K,e as E,r as Ks,b as _s,s as ie,c as zs,f as Us,d as Bs}from"./queries-Ddvo5dCs.mjs";import{a as A,c as _,d as Pt,e as qs}from"./classify-procedure-call-Ib2EMtFH.mjs";import $s from"./discoverAuthApiCalls-DoNQSgso.mjs";import js from"./discoverCrons-DCxl4hty.mjs";import Je from"./discoverFunctions-C29Tvxas.mjs";import{i as Vs,r as Ws,e as Hs}from"./unwrap-handler-return-CmIWbykC.mjs";import et from"./discoverHttpRoutes-CFIXlUy4.mjs";import Gs from"./discoverHyperdriveCalls-DTq4PKT5.mjs";import Ys from"./discoverInserts-qU5F4W4g.mjs";import{m as ye,a as Z,s as It,d as Qs}from"./index-xGhyK9J_.mjs";import{e as wt}from"./exported-procedure-chains-M40rbSYM.mjs";import Xs from"./discoverMigrations-BFkJQ8Sy.mjs";import{MUTATORS_FILENAME as Zs,isDefineMutatorCallee as Js,discoverMutators as tt}from"./MUTATORS_FILENAME-BKSzaCkq.mjs";import en from"./discoverNondeterministicCalls-B-NNzzPW.mjs";import{discoverNotifyConfig as tn,discoverNotifyCalls as sn}from"./NOTIFY_FILENAME-CKO5gtGe.mjs";import nn from"./discoverR2sqlCalls-C2GtrFnl.mjs";import rn from"./discoverRlsProcedures-fAhxiIyD.mjs";import on from"./discoverRlsMetadata-BKcUnSNr.mjs";import an from"./discoverSchema-CubSTjtY.mjs";import{secretKindOf as cn,redact as ln,isHeuristicSecretKind as un,isSecretishName as dn}from"./redact-Cy14LEnc.mjs";import{discoverShapes as fn}from"./SHAPES_FILENAME-D3N7xcEk.mjs";import{emitApp as pn}from"./emitApp-DoR55vKV.mjs";import{buildOpenApiDocument as gn,emitOpenApiModule as mn}from"./buildOpenApiDocument-D40ZeYsu.mjs";import{buildOpenRpcDocument as hn,emitOpenRpcModule as xn}from"./OPENRPC_VERSION-CdKqq_QT.mjs";import{s as En}from"./parse-validator-Q58kladC.mjs";import{buildSchemaSnapshot as vn}from"./SchemaSnapshotParseError-qXCOA7dD.mjs";const Sn=e=>{const t=new Map;for(const s of e){const n=ls(s),i=t.get(n);if(i===void 0){t.set(n,s);continue}if(i!==s)throw new L("INTERNAL",`@lunora/codegen: "${i}" and "${s}" both map to the api namespace "${n}" — the generated api.ts would declare "${n}" twice and the dispatch key "${n}:<fn>" would be ambiguous. Rename one file so the two differ by more than a non-identifier character (\`-\`, \`.\`, \`/\` and \`_\` all sanitize to \`_\`).`,{status:500})}},An=e=>{const t=[],s=e.tables.filter(n=>n.shardMode==="global");return s.some(n=>n.globalBackend!=="hyperdrive")&&t.push({name:"@lunora/d1",reason:"`.global()` tables are D1-backed, so `_generated/app.ts` imports the D1 `ctx.db` adapter"}),s.some(n=>n.globalBackend==="hyperdrive")&&t.push({name:"@lunora/hyperdrive",reason:'`.global({ backend: "hyperdrive" })` tables route through `@lunora/hyperdrive/global`'}),e.vectorIndexes.length>0&&t.push({name:"@lunora/bindings",reason:"`.vectorize()` indexes make `_generated/vectors.ts` import `@lunora/bindings/vectors`"}),t},yn=(e,t)=>{if(t===void 0)return;const s=An(e).filter(i=>!t.has(i.name));if(s.length===0)return;const n=s.map(i=>` - ${i.name} — ${i.reason}`).join(`
1
+ import{existsSync as b,mkdirSync as ns,readFileSync as At,writeFileSync as rs,rmSync as is}from"node:fs";import{join as f,dirname as pe}from"node:path";import{performance as ge}from"node:perf_hooks";import{runAdvisor as os}from"@lunora/advisor";import{LunoraError as L}from"@lunora/errors";import{SyntaxKind as l,Node as o,Project as Xe}from"ts-morph";import{serializeSchemaSnapshot as as}from"./SCHEMA_SNAPSHOT_VERSION-B1BUjuG5.mjs";import{toAdvisorContext as cs}from"./formatAdvisories-CkEu1eye.mjs";import{s as ls}from"./paths-C-9fwEgQ.mjs";import{discoverAgents as us}from"./AGENTS_FILENAME-B1Abt3Gl.mjs";import{discoverContainers as ds}from"./CONTAINERS_FILENAME-CtcysaKS.mjs";import{diagnosticAt as ne}from"./CodegenDiagnosticError-BUXlG3P-.mjs";import{b as re}from"./module-specifiers-WF8iAydP.mjs";import{C as me,i as fs,f as ps,n as gs,j as ms,b as hs,c as xs,l as Es,e as vs,o as Ss,d as As,k as ys,g as Ns,p as bs,m as Ps,a as Is,h as ws}from"./emit-DHDqyZ_P.mjs";import{l as g,a as v,f as P,p as N,g as yt,j as Nt,k as ve,h as Ts,i as D,b as Ze,r as bt,e as Cs}from"./ast-BYoSZlae.mjs";import Fs from"./readPackageDependencies-C6h6FZuP.mjs";import{discoverQueues as Os}from"./QUEUES_FILENAME-C-pzLGy4.mjs";import{discoverSandboxUsage as Rs}from"./discoverSandboxUsage-CJhnKA0_.mjs";import Ls from"./discoverStorageRulesMetadata-C7XmORWp.mjs";import{discoverWorkflows as Ds}from"./WORKFLOWS_FILENAME-BfvqsG9Z.mjs";import{gatePlatformFeatures as ks,resolveCodegenTarget as Ms}from"./DEFAULT_TARGET-BvzxeWRZ.mjs";import{i as F,a as K,e as E,r as Ks,b as _s,s as ie,c as zs,f as Us,d as Bs}from"./queries-Ddvo5dCs.mjs";import{a as A,c as _,d as Pt,e as qs}from"./classify-procedure-call-Ib2EMtFH.mjs";import $s from"./discoverAuthApiCalls-DoNQSgso.mjs";import js from"./discoverCrons-DCxl4hty.mjs";import Je from"./discoverFunctions-C29Tvxas.mjs";import{i as Vs,r as Ws,e as Hs}from"./unwrap-handler-return-CmIWbykC.mjs";import et from"./discoverHttpRoutes-CFIXlUy4.mjs";import Gs from"./discoverHyperdriveCalls-DTq4PKT5.mjs";import Ys from"./discoverInserts-qU5F4W4g.mjs";import{m as ye,a as Z,s as It,d as Qs}from"./index-xGhyK9J_.mjs";import{e as wt}from"./exported-procedure-chains-M40rbSYM.mjs";import Xs from"./discoverMigrations-BFkJQ8Sy.mjs";import{MUTATORS_FILENAME as Zs,isDefineMutatorCallee as Js,discoverMutators as tt}from"./MUTATORS_FILENAME-BKSzaCkq.mjs";import en from"./discoverNondeterministicCalls-B-NNzzPW.mjs";import{discoverNotifyConfig as tn,discoverNotifyCalls as sn}from"./NOTIFY_FILENAME-CKO5gtGe.mjs";import nn from"./discoverR2sqlCalls-C2GtrFnl.mjs";import rn from"./discoverRlsProcedures-fAhxiIyD.mjs";import on from"./discoverRlsMetadata-BKcUnSNr.mjs";import an from"./discoverSchema-CubSTjtY.mjs";import{secretKindOf as cn,redact as ln,isHeuristicSecretKind as un,isSecretishName as dn}from"./redact-Cy14LEnc.mjs";import{discoverShapes as fn}from"./SHAPES_FILENAME-D3N7xcEk.mjs";import{emitApp as pn}from"./emitApp-B1pTKVES.mjs";import{buildOpenApiDocument as gn,emitOpenApiModule as mn}from"./buildOpenApiDocument-CyoTgJNE.mjs";import{buildOpenRpcDocument as hn,emitOpenRpcModule as xn}from"./OPENRPC_VERSION-C6usyZYe.mjs";import{s as En}from"./parse-validator-Q58kladC.mjs";import{buildSchemaSnapshot as vn}from"./SchemaSnapshotParseError-BA80Pxar.mjs";const Sn=e=>{const t=new Map;for(const s of e){const n=ls(s),i=t.get(n);if(i===void 0){t.set(n,s);continue}if(i!==s)throw new L("INTERNAL",`@lunora/codegen: "${i}" and "${s}" both map to the api namespace "${n}" — the generated api.ts would declare "${n}" twice and the dispatch key "${n}:<fn>" would be ambiguous. Rename one file so the two differ by more than a non-identifier character (\`-\`, \`.\`, \`/\` and \`_\` all sanitize to \`_\`).`,{status:500})}},An=e=>{const t=[],s=e.tables.filter(n=>n.shardMode==="global");return s.some(n=>n.globalBackend!=="hyperdrive")&&t.push({name:"@lunora/d1",reason:"`.global()` tables are D1-backed, so `_generated/app.ts` imports the D1 `ctx.db` adapter"}),s.some(n=>n.globalBackend==="hyperdrive")&&t.push({name:"@lunora/hyperdrive",reason:'`.global({ backend: "hyperdrive" })` tables route through `@lunora/hyperdrive/global`'}),e.vectorIndexes.length>0&&t.push({name:"@lunora/bindings",reason:"`.vectorize()` indexes make `_generated/vectors.ts` import `@lunora/bindings/vectors`"}),t},yn=(e,t)=>{if(t===void 0)return;const s=An(e).filter(i=>!t.has(i.name));if(s.length===0)return;const n=s.map(i=>` - ${i.name} — ${i.reason}`).join(`
2
2
  `);throw new L("INTERNAL",`@lunora/codegen: this schema's generated code imports packages the project does not declare:
3
3
  ${n}
4
4
 
@@ -0,0 +1,2 @@
1
+ const h=(e,i=2166136261)=>{let t=i;for(let n=0;n<e.length;n+=1)t^=e.codePointAt(n)??0,t=Math.imul(t,16777619);return(t>>>0).toString(16).padStart(8,"0")},y=e=>`${h(e,2166136261)}${h(e,16777619)}`,E=1;function m(e){const i={},t=Object.keys(e);t.sort();for(const n of t)i[n]=e[n];return i}const g=e=>`${JSON.stringify(e,void 0,2)}
2
+ `,I=e=>y(g(e)),a=e=>typeof e=="object"&&e!==null,v=e=>a(e)&&a(e.fields)&&a(e.indexes)&&a(e.relations)&&typeof e.shardMode=="string",q=e=>{if(e===void 0||e.trim()==="")return{status:"absent"};let i;try{i=JSON.parse(e)}catch(n){return{error:`baseline is not valid JSON: ${n instanceof Error?n.message:String(n)}`,status:"invalid"}}if(!a(i)||i.version!==1||!a(i.tables))return{error:`baseline is malformed or written by an incompatible version (expected version ${String(1)})`,status:"invalid"};for(const[n,o]of Object.entries(i.tables))if(!v(o))return{error:`baseline table "${n}" has an invalid structure`,status:"invalid"};return{snapshot:{jurisdiction:typeof i.jurisdiction=="string"?i.jurisdiction:void 0,migrationIds:Array.isArray(i.migrationIds)?i.migrationIds:[],tables:i.tables,version:1},status:"ok"}},$=(e,i)=>e.unique===i.unique&&e.fields.length===i.fields.length&&e.fields.every((t,n)=>t===i.fields[n]),p=e=>e.unique!==void 0,u=({nullable:e,optional:i,refined:t,unique:n,...o})=>JSON.stringify(m(o)),f=e=>e.kind==="union"&&e.members?e.members.map(i=>u(i)):[u(e)],b=(e,i)=>{if(i.kind!=="union")return!1;const t=new Set(f(i));return f(e).every(n=>t.has(n))},d=e=>{switch(e.kind){case"array":return`array(${e.of?d(e.of):"?"})`;case"id":return`id(${e.ref??"?"})`;case"literal":return`literal(${e.literal??"?"})`;case"object":return`object({ ${Object.keys(e.fields??{}).join(", ")} })`;case"record":return`record(${e.key?d(e.key):"?"}, ${e.of?d(e.of):"?"})`;case"union":return(e.members??[]).map(i=>d(i)).join(" | ");default:return e.kind}},c=(e,i,t)=>({remediation:"backfill",scope:"table",severity:"breaking",summary:t,table:e,type:i}),l=(e,i,t)=>({remediation:"none",scope:"table",severity:"safe",summary:t,table:e,type:i}),S=(e,i,t,n,o)=>{if(!(t.kind===n.kind&&(!o||u(t)===u(n))))return o&&b(t,n)?l(e,"widenedFieldShape",`field ${e}.${i} widened: ${d(t)} → ${d(n)} — every stored value stays valid`):t.kind!==n.kind?c(e,"changedFieldKind",`field ${e}.${i} changed type: ${t.kind} → ${n.kind} — add a data migration to convert existing values`):c(e,"changedFieldShape",`field ${e}.${i} changed shape: ${d(t)} → ${d(n)} — stored values were written against the old shape; add a data migration to convert them`)},k=(e,i,t,n)=>{const o=[];return t.unique!==n.unique&&o.push(n.unique===!0?c(e,"addedFieldConstraint",`field ${e}.${i} became unique — existing duplicates would violate it; add a data migration to de-duplicate first`):l(e,"relaxedFieldConstraint",`field ${e}.${i} is no longer unique`)),t.nullable!==n.nullable&&o.push(n.nullable===!0?l(e,"relaxedFieldConstraint",`field ${e}.${i} became nullable`):c(e,"addedFieldConstraint",`field ${e}.${i} is no longer nullable — rows holding NULL would be invalid; add a data migration to backfill them`)),t.refined!==n.refined&&o.push(n.refined===!0?c(e,"addedFieldConstraint",`field ${e}.${i} gained a validation refinement — stored values were never checked against it; add a data migration if any could fail`):l(e,"relaxedFieldConstraint",`field ${e}.${i} dropped its validation refinement`)),o},F=(e,i,t,n)=>{const o=[],s=p(t)&&p(n),r=S(e,i,t,n,s);return r&&o.push(r),s&&o.push(...k(e,i,t,n)),t.optional&&!n.optional?o.push({remediation:"backfill",severity:"breaking",summary:`field ${e}.${i} became required — rows missing it would be invalid; add a data migration to backfill it`,table:e,scope:"table",type:"fieldOptionalToRequired"}):!t.optional&&n.optional&&o.push({remediation:"none",scope:"table",severity:"safe",summary:`field ${e}.${i} became optional`,table:e,type:"fieldRequiredToOptional"}),o},O=(e,i,t)=>t.optional?{remediation:"none",scope:"table",severity:"safe",summary:`added optional field ${e}.${i}`,table:e,type:"addedOptionalField"}:{remediation:"backfill",severity:"breaking",summary:`added required field ${e}.${i} — existing rows have no value; add a data migration to backfill it`,table:e,scope:"table",type:"addedRequiredField"},x=(e,i,t,n)=>{for(const[o,s]of Object.entries(t.fields)){const r=i.fields[o];r===void 0?n.push(O(e,o,s)):n.push(...F(e,o,r,s))}for(const o of Object.keys(i.fields))t.fields[o]===void 0&&n.push({remediation:"backfill",severity:"breaking",summary:`removed field ${e}.${o} — add a data migration if stored data must be cleaned up`,table:e,scope:"table",type:"removedField"})},j=(e,i,t,n)=>{for(const[o,s]of Object.entries(t.indexes)){const r=i.indexes[o];if(r===void 0){n.push({remediation:"none",scope:"table",severity:"safe",summary:`added index ${o} on ${e}`,table:e,type:"addedIndex"});continue}$(r,s)||n.push({remediation:"code",severity:"breaking",summary:`index ${o} on ${e} changed shape — a query may have relied on the old index`,table:e,scope:"table",type:"changedIndex"})}for(const o of Object.keys(i.indexes))t.indexes[o]===void 0&&n.push({remediation:"code",severity:"breaking",summary:`removed index ${o} on ${e} — a query that used \`.withIndex("${o}")\` would break`,table:e,scope:"table",type:"removedIndex"})},w=(e,i,t,n)=>{for(const o of Object.keys(t.relations))i.relations[o]===void 0&&n.push({remediation:"none",scope:"schema",severity:"safe",summary:`added relation ${e}.${o}`,table:e,type:"addedRelation"});for(const o of Object.keys(i.relations))t.relations[o]===void 0&&n.push({remediation:"code",scope:"schema",severity:"breaking",summary:`removed relation ${e}.${o}`,table:e,type:"removedRelation"})},A=(e,i,t,n)=>{i.shardMode!==t.shardMode&&n.push({remediation:"rehome",severity:"breaking",summary:`table ${e} changed shard mode: ${i.shardMode} → ${t.shardMode} — its physical storage moves, and existing rows do NOT follow the schema; re-home them with an export/import round trip (https://lunora.sh/docs/concepts/sharding#migrating-a-populated-table)`,table:e,scope:"table",type:"changedShardMode"}),x(e,i,t,n),j(e,i,t,n),w(e,i,t,n)},_=(e,i)=>{const t=[],n=e?.tables??{};for(const[o,s]of Object.entries(i.tables)){const r=n[o];if(r===void 0){t.push({remediation:"none",scope:"table",severity:"safe",summary:`added table ${o}`,table:o,type:"addedTable"});continue}A(o,r,s,t)}for(const o of Object.keys(n))i.tables[o]===void 0&&t.push({remediation:"rehome",scope:"table",severity:"breaking",summary:`removed table ${o} — its rows stay in each shard's SQLite, unreachable through the schema; export the shard first if the data must be kept`,table:o,type:"removedTable"});if(e!==void 0&&e.jurisdiction!==i.jurisdiction){const o=e.jurisdiction??"(none)",s=i.jurisdiction??"(none)";t.push({remediation:"rehome",scope:"schema",severity:"breaking",summary:`Durable Object jurisdiction changed from ${o} to ${s} — this re-homes every DO and strands all existing shard, scheduler, and session-DO data in the old region (no in-place migration; export then import to move it). Revert the change, or override the gate to proceed intentionally.`,type:"changedJurisdiction"})}return{changes:t}};export{E as SCHEMA_SNAPSHOT_VERSION,d as describeShape,F as diffExistingField,_ as diffSchemaSnapshots,I as hashSchemaSnapshot,v as isValidTableSnapshot,q as parseSnapshotJson,g as serializeSchemaSnapshot,m as sortKeys};
@@ -0,0 +1,18 @@
1
+ import{LunoraError as E}from"@lunora/errors";import{SCHEMA_SNAPSHOT_VERSION as I,sortKeys as f,diffSchemaSnapshots as A,parseSnapshotJson as L}from"./SCHEMA_SNAPSHOT_VERSION-B1BUjuG5.mjs";import{serializeSchemaSnapshot as V}from"./SCHEMA_SNAPSHOT_VERSION-B1BUjuG5.mjs";const _=e=>e==="global"||e==="root"?e:`shardBy:${e.field}`,N=(e,n)=>{const s=JSON.stringify(e),i=JSON.stringify(n);return s===i?0:s<i?-1:1},l=e=>{const n=e.kind==="optional",s=n?e.inner:void 0,i=s??e,t={kind:n?s?.kind??"unknown":e.kind,nullable:i.column?.notNull===!1||e.column?.notNull===!1,optional:n,unique:i.column?.unique===!0||e.column?.unique===!0,...v[i.kind]?.(i)};return(i.hasRefinement===!0||e.hasRefinement===!0)&&(t.refined=!0),t},j=e=>{const n={};for(const[s,i]of Object.entries(e))n[s]=l(i);return f(n)},v={array:e=>e.inner?{of:l(e.inner)}:{},id:e=>e.tableName===void 0?{}:{ref:e.tableName},literal:e=>e.literalValue===void 0?{}:{literal:e.literalValue},object:e=>e.shape?{fields:j(e.shape)}:{},record:e=>({...e.keyType?{key:l(e.keyType)}:{},...e.valueType?{of:l(e.valueType)}:{}}),union:e=>e.members?{members:e.members.map(n=>l(n)).toSorted(N)}:{}},O=e=>{const n={};for(const[t,a]of Object.entries(e.shape))n[t]=l(a);const s={};for(const t of e.indexes)s[t.name]={fields:[...t.fields],unique:t.unique??!1};const i={};for(const t of e.relations)i[t.name]={field:t.field,kind:t.kind,table:t.table};return{fields:f(n),indexes:f(s),relations:f(i),shardMode:_(e.shardMode)}},U=(e,n)=>{const s={};for(const t of e.tables)s[t.name]=O(t);const i=[...n].sort();return{jurisdiction:e.jurisdiction,migrationIds:i,tables:f(s),version:I}};class D extends E{constructor(n){super("SCHEMA_SNAPSHOT_PARSE",n,{name:"SchemaSnapshotParseError"})}}const C=e=>{const n=L(e);if(n.status==="invalid")throw new D(n.error);return n.status==="ok"?n.snapshot:void 0},R={deploy:{allowDrift:!0,updateBaseline:!0},prepare:{allowDrift:!0,updateBaseline:!0},verify:{allowDrift:!0,updateBaseline:!1}},y=" • For backward-compatible changes (e.g. adding an optional field): pass `--allow-schema-drift` to skip the block.",k=" • To accept the new shape without a migration (you know data is compatible): pass `--update-schema-baseline`.",M=e=>{const n=e===void 0?void 0:R[e];if(e===void 0||n===void 0)return`${y}
2
+ ${k}
3
+ `;const s=n.updateBaseline?k:` • To accept the new shape without a migration, run \`lunora prepare --update-schema-baseline\` — \`lunora ${e}\` does not take that flag.`;return`${y}
4
+ ${s}
5
+ `},m=e=>e.map(n=>` - ${n.summary}`).join(`
6
+ `),w=e=>e.remediation==="backfill"&&e.table!==void 0,x=/^[A-Za-z_]\w*$/u,B=e=>` lunora migrate create backfill_${e} --table ${e}`,F=(e,n,s)=>{const i=[...new Set(e.filter(a=>w(a)).map(a=>a.table))],t=[];if(i.length>0){t.push(" • Add a `defineMigration({ id, table, up })` in lunora/ for each affected table, then re-run this command — the baseline is re-blessed on a successful deploy, not by `lunora migrate` itself.\n");const a=i.filter(r=>x.test(r));a.length>0&&t.push(`
7
+ Scaffold the missing migration(s) — the generated \`up\` is an identity placeholder you must fill in:
8
+ ${a.map(r=>B(r)).join(`
9
+ `)}
10
+
11
+ `)}return n.length>0&&t.push(` • Migration(s) ${n.join(", ")} declare a non-literal \`table\`, so codegen cannot tell which table they visit and they cover nothing. Use a string literal.
12
+ `),t.push(M(s)),[`deploy blocked: ${String(e.length)} unresolved breaking schema change(s) since the last blessed schema baseline:`,m(e),"",`To fix:
13
+ ${t.join("")}Docs: https://lunora.dev/docs/migrations`].join(`
14
+ `)},H=e=>{const{allowDrift:n=!1,baseline:s,command:i,current:t,migrations:a}=e,r=A(s,t),u=r.changes.filter(o=>o.severity==="breaking"),b=t.migrationIds.filter(o=>!(s?.migrationIds??[]).includes(o)),p=a.filter(o=>b.includes(o.id)),c=(o,h)=>({blocked:o,changes:r.changes,newMigrationIds:b,reason:h}),T=new Set(p.filter(o=>o.table!=="").map(o=>o.table)),$=p.filter(o=>o.table==="").map(o=>o.id);if(r.changes.length===0||s===void 0)return c(!1,"");if(u.length===0)return c(!1,`schema drift detected (all additive/safe):
15
+ ${m(r.changes)}`);const g=u.filter(o=>!w(o)||!T.has(o.table));if(g.length===0){const o=new Set(u.map(d=>d.table)),h=p.filter(d=>o.has(d.table)).map(d=>d.id);return c(!1,`breaking schema drift detected, covered by ${String(h.length)} new migration(s) (${h.join(", ")}):
16
+ ${m(u)}`)}const S=F(g,$,i);return n?c(!1,`${S}
17
+
18
+ (overridden by --allow-schema-drift)`):c(!0,S)};export{I as SCHEMA_SNAPSHOT_VERSION,D as SchemaSnapshotParseError,U as buildSchemaSnapshot,A as diffSchemaSnapshots,H as evaluateSchemaDrift,C as parseSchemaSnapshot,V as serializeSchemaSnapshot};
@@ -1,3 +1,3 @@
1
- import{G as S}from"./emit-BcAkLUfn.mjs";import{s as p}from"./paths-C-9fwEgQ.mjs";import{LUNORA_ERROR_CODES as O,objectSchema as h,validatorIrToJsonSchema as u}from"./LUNORA_ERROR_CODES-BYg8Lpgb.mjs";const E="/_lunora/rest",A=["authorization","cf-access-jwt-assertion","cookie","x-payment"],f=["x-d1-bookmark","x-lunora-shard-key"],P=e=>[...A,...(e.credentialHeaders??[]).map(t=>t.toLowerCase())],g=e=>Number.isFinite(e)?Math.max(0,Math.floor(e)):0,y=(...e)=>{const t=[];for(const r of e)for(const o of r?.split(",")??[]){const s=o.trim().toLowerCase();s!==""&&!t.includes(s)&&t.push(s)}return t.length===0?void 0:t.join(", ")},T=(e,t)=>{const r=[t,`max-age=${String(g(e.maxAge))}`];return e.staleWhileRevalidate!==void 0&&r.push(`stale-while-revalidate=${String(g(e.staleWhileRevalidate))}`),r.join(", ")},b=e=>e.scope==="public"?y(e.vary,...P(e),...f):y(e.vary,...f),x=e=>{const t=e.indexOf(":");if(!(t<=0||t>=e.length-1||e.indexOf(":",t+1)!==-1))return{name:e.slice(t+1),namespace:e.slice(0,t)}},N=e=>{const t=x(e);if(t!==void 0)return`${E}/${t.namespace}/${t.name}`},k=e=>e==="query"?"GET":"POST",m="#/components/responses/LunoraError",v=/:([A-Za-z_$][\w$]*)/gu,q=e=>[...e.matchAll(v)].map(t=>t[1]),_=e=>e.replaceAll(v,"{$1}"),l=e=>e.kind==="optional"?e.inner??e:e,j=e=>{const t=new Set(q(e.path)),r=[];for(const[o,s]of Object.entries(e.searchParams)){const c=l(s);r.push({description:`Query parameter \`${o}\``,in:"query",name:o,required:s.kind!=="optional",schema:u(c)})}for(const[o,s]of Object.entries(e.params)){const c=l(s);r.push({description:`Path parameter \`${o}\``,in:t.has(o)?"path":"query",name:o,required:t.has(o)?!0:s.kind!=="optional",schema:u(c)})}return r},$=e=>e?{content:{"application/json":{schema:u(e)}},description:"Successful response."}:{content:{"application/json":{schema:{description:"Return shape is TS-inferred (no `.output()` declared); best-effort — any JSON."}}},description:"Successful response. The return shape is TypeScript-inferred and not declared via `.output()`, so it is documented best-effort."},C=e=>{const t=p(e.filePath),r=j(e),o={description:`${e.stream?"Streaming (SSE) ":""}HTTP route handler \`${e.exportName}\` (${e.method} ${e.path}).`,operationId:`${e.method.toLowerCase()}_${p(e.path)}`,responses:{200:$(e.output),204:{description:"No content (handler returned `undefined`)."},default:{$ref:m}},summary:`${e.method} ${e.path}`,tags:[t]};return r.length>0&&(o.parameters=r),Object.keys(e.body).length>0&&(o.requestBody={content:{"application/json":{schema:h(e.body)}},required:!0}),e.stream&&(o["x-lunora-stream"]="text/event-stream"),o},w=e=>{const t=p(e.filePath),r=`${t}:${e.exportName}`,o={additionalProperties:!1,properties:{args:h(e.args),functionPath:{const:r,type:"string"},shardKey:{description:"Optional shard key; omitted routes to the default shard.",type:"string"}},required:["functionPath"],type:"object"};return{operation:{description:`Invoke the \`${e.kind}\` \`${r}\` over the Lunora RPC envelope (POST /_lunora/rpc).`,operationId:r,requestBody:{content:{"application/json":{schema:o}},required:!0},responses:{200:$(e.output),default:{$ref:m}},summary:`${e.kind}: ${r}`,tags:[t],"x-lunora-function-kind":e.kind},pathKey:`/_lunora/rpc#${r}`}},D=(e,t)=>{if(e===void 0||t!=="get"||e.scope===void 0||e.maxAge===void 0)return{};const r={maxAge:e.maxAge,scope:e.scope,...e.staleWhileRevalidate===void 0?{}:{staleWhileRevalidate:e.staleWhileRevalidate},...e.tag===void 0?{}:{tag:e.tag},...e.vary===void 0?{}:{vary:e.vary}},o={"Cache-Control":{description:r.scope==="public"?"Caching policy. `public` applies only to an uncredentialed request — a request carrying `Authorization` or `Cookie` is always answered `private`.":"Caching policy. Restricted to the caller's own cache; never stored by a shared/edge cache.",schema:{example:T(r,r.scope),type:"string"}}};r.tag!==void 0&&(o["Cache-Tag"]={description:"Purge tag for `ctx.cache.purge({ tags: [...] })`.",schema:{example:r.tag,type:"string"}});const s=b(r);return s!==void 0&&(o.Vary={description:"Request headers this response varies by. The endpoint's own negotiated headers are merged in at runtime.",schema:{example:s,type:"string"}}),{headers:o}},L=e=>{const t=p(e.filePath),r=`${t}:${e.exportName}`,o=N(r);if(o===void 0)return;const s=k(e.kind),c=s==="GET",d={description:`Public REST endpoint for the \`${e.kind}\` \`${r}\` (opt-in via \`.expose({ rest: true })\`). Routed through the procedure, so auth / RLS / validators are enforced.`,operationId:`rest_${p(o)}`,responses:{200:{content:{"application/json":{schema:{description:"Procedure result. The shape is TS-inferred from the return type; best-effort — any JSON."}}},description:"Successful result (TypeScript-inferred return shape, documented best-effort).",...D(e.expose?.cache,c?"get":"post")},default:{$ref:m}},summary:`${s} ${o}`,tags:[t],"x-lunora-function-kind":e.kind};if(c){const n=Object.entries(e.args).map(([a,i])=>{const R=l(i);return{description:`Argument \`${a}\` (JSON-encoded for non-string values).`,in:"query",name:a,required:i.kind!=="optional",schema:u(R)}});return n.length>0&&(d.parameters=n),{method:"get",operation:d,path:o}}return d.requestBody={content:{"application/json":{schema:h(e.args)}},required:Object.keys(e.args).length>0},{method:"post",operation:d,path:o}},I=e=>{const t=e.version??"0.0.0",r={},o=new Set;for(const n of e.httpRoutes){const a=_(n.path),i=r[a]??{};i[n.method.toLowerCase()]=C(n),r[a]=i,o.add(p(n.filePath))}const s=e.functions.filter(n=>n.visibility!=="internal"&&n.kind!=="stream");for(const n of s){const{operation:a,pathKey:i}=w(n);r[i]={post:a},o.add(p(n.filePath))}for(const n of s){if(n.expose?.rest!==!0)continue;const a=L(n);if(a===void 0)continue;const i=r[a.path]??{};i[a.method]=a.operation,r[a.path]=i}const c=[...o].toSorted((n,a)=>n.localeCompare(a)).map(n=>({description:`Operations declared in \`lunora/${n}\`.`,name:n}));return{components:{responses:{LunoraError:{content:{"application/json":{schema:{additionalProperties:!1,description:"Standard Lunora error envelope.",properties:{error:{additionalProperties:!1,properties:{code:{description:"Machine-readable error code. Clients switch on this value.",enum:O,type:"string"},message:{description:"Human-readable error message (never echoes internal details).",type:"string"}},required:["code","message"],type:"object"}},required:["error"],type:"object"}}},description:"A Lunora error response. The HTTP status reflects the error code (e.g. BAD_REQUEST→400, UNAUTHORIZED→401, FORBIDDEN→403, NOT_FOUND→404)."}}},info:{description:"Auto-generated from @lunora/values-typed functions by @lunora/codegen. Do not edit — run `lunora codegen` to regenerate.",title:"Lunora API",version:t},openapi:"3.1.0",paths:r,tags:c}},J=e=>`${JSON.stringify(I(e),void 0,2)}
1
+ import{G as S}from"./emit-DHDqyZ_P.mjs";import{s as p}from"./paths-C-9fwEgQ.mjs";import{LUNORA_ERROR_CODES as O,objectSchema as h,validatorIrToJsonSchema as u}from"./LUNORA_ERROR_CODES-BYg8Lpgb.mjs";const E="/_lunora/rest",A=["authorization","cf-access-jwt-assertion","cookie","x-payment"],f=["x-d1-bookmark","x-lunora-shard-key"],P=e=>[...A,...(e.credentialHeaders??[]).map(t=>t.toLowerCase())],g=e=>Number.isFinite(e)?Math.max(0,Math.floor(e)):0,y=(...e)=>{const t=[];for(const r of e)for(const o of r?.split(",")??[]){const s=o.trim().toLowerCase();s!==""&&!t.includes(s)&&t.push(s)}return t.length===0?void 0:t.join(", ")},T=(e,t)=>{const r=[t,`max-age=${String(g(e.maxAge))}`];return e.staleWhileRevalidate!==void 0&&r.push(`stale-while-revalidate=${String(g(e.staleWhileRevalidate))}`),r.join(", ")},b=e=>e.scope==="public"?y(e.vary,...P(e),...f):y(e.vary,...f),x=e=>{const t=e.indexOf(":");if(!(t<=0||t>=e.length-1||e.indexOf(":",t+1)!==-1))return{name:e.slice(t+1),namespace:e.slice(0,t)}},N=e=>{const t=x(e);if(t!==void 0)return`${E}/${t.namespace}/${t.name}`},k=e=>e==="query"?"GET":"POST",m="#/components/responses/LunoraError",v=/:([A-Za-z_$][\w$]*)/gu,q=e=>[...e.matchAll(v)].map(t=>t[1]),_=e=>e.replaceAll(v,"{$1}"),l=e=>e.kind==="optional"?e.inner??e:e,j=e=>{const t=new Set(q(e.path)),r=[];for(const[o,s]of Object.entries(e.searchParams)){const c=l(s);r.push({description:`Query parameter \`${o}\``,in:"query",name:o,required:s.kind!=="optional",schema:u(c)})}for(const[o,s]of Object.entries(e.params)){const c=l(s);r.push({description:`Path parameter \`${o}\``,in:t.has(o)?"path":"query",name:o,required:t.has(o)?!0:s.kind!=="optional",schema:u(c)})}return r},$=e=>e?{content:{"application/json":{schema:u(e)}},description:"Successful response."}:{content:{"application/json":{schema:{description:"Return shape is TS-inferred (no `.output()` declared); best-effort — any JSON."}}},description:"Successful response. The return shape is TypeScript-inferred and not declared via `.output()`, so it is documented best-effort."},C=e=>{const t=p(e.filePath),r=j(e),o={description:`${e.stream?"Streaming (SSE) ":""}HTTP route handler \`${e.exportName}\` (${e.method} ${e.path}).`,operationId:`${e.method.toLowerCase()}_${p(e.path)}`,responses:{200:$(e.output),204:{description:"No content (handler returned `undefined`)."},default:{$ref:m}},summary:`${e.method} ${e.path}`,tags:[t]};return r.length>0&&(o.parameters=r),Object.keys(e.body).length>0&&(o.requestBody={content:{"application/json":{schema:h(e.body)}},required:!0}),e.stream&&(o["x-lunora-stream"]="text/event-stream"),o},w=e=>{const t=p(e.filePath),r=`${t}:${e.exportName}`,o={additionalProperties:!1,properties:{args:h(e.args),functionPath:{const:r,type:"string"},shardKey:{description:"Optional shard key; omitted routes to the default shard.",type:"string"}},required:["functionPath"],type:"object"};return{operation:{description:`Invoke the \`${e.kind}\` \`${r}\` over the Lunora RPC envelope (POST /_lunora/rpc).`,operationId:r,requestBody:{content:{"application/json":{schema:o}},required:!0},responses:{200:$(e.output),default:{$ref:m}},summary:`${e.kind}: ${r}`,tags:[t],"x-lunora-function-kind":e.kind},pathKey:`/_lunora/rpc#${r}`}},D=(e,t)=>{if(e===void 0||t!=="get"||e.scope===void 0||e.maxAge===void 0)return{};const r={maxAge:e.maxAge,scope:e.scope,...e.staleWhileRevalidate===void 0?{}:{staleWhileRevalidate:e.staleWhileRevalidate},...e.tag===void 0?{}:{tag:e.tag},...e.vary===void 0?{}:{vary:e.vary}},o={"Cache-Control":{description:r.scope==="public"?"Caching policy. `public` applies only to an uncredentialed request — a request carrying `Authorization` or `Cookie` is always answered `private`.":"Caching policy. Restricted to the caller's own cache; never stored by a shared/edge cache.",schema:{example:T(r,r.scope),type:"string"}}};r.tag!==void 0&&(o["Cache-Tag"]={description:"Purge tag for `ctx.cache.purge({ tags: [...] })`.",schema:{example:r.tag,type:"string"}});const s=b(r);return s!==void 0&&(o.Vary={description:"Request headers this response varies by. The endpoint's own negotiated headers are merged in at runtime.",schema:{example:s,type:"string"}}),{headers:o}},L=e=>{const t=p(e.filePath),r=`${t}:${e.exportName}`,o=N(r);if(o===void 0)return;const s=k(e.kind),c=s==="GET",d={description:`Public REST endpoint for the \`${e.kind}\` \`${r}\` (opt-in via \`.expose({ rest: true })\`). Routed through the procedure, so auth / RLS / validators are enforced.`,operationId:`rest_${p(o)}`,responses:{200:{content:{"application/json":{schema:{description:"Procedure result. The shape is TS-inferred from the return type; best-effort — any JSON."}}},description:"Successful result (TypeScript-inferred return shape, documented best-effort).",...D(e.expose?.cache,c?"get":"post")},default:{$ref:m}},summary:`${s} ${o}`,tags:[t],"x-lunora-function-kind":e.kind};if(c){const n=Object.entries(e.args).map(([a,i])=>{const R=l(i);return{description:`Argument \`${a}\` (JSON-encoded for non-string values).`,in:"query",name:a,required:i.kind!=="optional",schema:u(R)}});return n.length>0&&(d.parameters=n),{method:"get",operation:d,path:o}}return d.requestBody={content:{"application/json":{schema:h(e.args)}},required:Object.keys(e.args).length>0},{method:"post",operation:d,path:o}},I=e=>{const t=e.version??"0.0.0",r={},o=new Set;for(const n of e.httpRoutes){const a=_(n.path),i=r[a]??{};i[n.method.toLowerCase()]=C(n),r[a]=i,o.add(p(n.filePath))}const s=e.functions.filter(n=>n.visibility!=="internal"&&n.kind!=="stream");for(const n of s){const{operation:a,pathKey:i}=w(n);r[i]={post:a},o.add(p(n.filePath))}for(const n of s){if(n.expose?.rest!==!0)continue;const a=L(n);if(a===void 0)continue;const i=r[a.path]??{};i[a.method]=a.operation,r[a.path]=i}const c=[...o].toSorted((n,a)=>n.localeCompare(a)).map(n=>({description:`Operations declared in \`lunora/${n}\`.`,name:n}));return{components:{responses:{LunoraError:{content:{"application/json":{schema:{additionalProperties:!1,description:"Standard Lunora error envelope.",properties:{error:{additionalProperties:!1,properties:{code:{description:"Machine-readable error code. Clients switch on this value.",enum:O,type:"string"},message:{description:"Human-readable error message (never echoes internal details).",type:"string"}},required:["code","message"],type:"object"}},required:["error"],type:"object"}}},description:"A Lunora error response. The HTTP status reflects the error code (e.g. BAD_REQUEST→400, UNAUTHORIZED→401, FORBIDDEN→403, NOT_FOUND→404)."}}},info:{description:"Auto-generated from @lunora/values-typed functions by @lunora/codegen. Do not edit — run `lunora codegen` to regenerate.",title:"Lunora API",version:t},openapi:"3.1.0",paths:r,tags:c}},J=e=>`${JSON.stringify(I(e),void 0,2)}
2
2
  `,U=e=>`${S}export const openApiSpec: Record<string, unknown> = ${JSON.stringify(e,void 0,4)};
3
3
  `;export{I as buildOpenApiDocument,J as emitOpenApi,U as emitOpenApiModule};
@@ -1,4 +1,4 @@
1
- import{agentComponent as ct}from"@lunora/agent/component";import{LunoraError as X}from"@lunora/errors";import{serializeSchemaSnapshot as xn,hashSchemaSnapshot as vn}from"./SCHEMA_SNAPSHOT_VERSION-CTWRkAF5.mjs";import{s as N}from"./paths-C-9fwEgQ.mjs";const dt=[{contextProperty:"access",key:"access",moduleSpecifier:"@lunora/cloudflare-access"},{appMethod:{configKey:"ai",doc:"Override the Workers AI binding backing `ctx.ai` (defaults to `env.AI`).",method:"ai"},contextProperty:"ai",key:"ai",moduleSpecifier:"@lunora/ai"},{appMethod:{configKey:"analytics",doc:"Override the Analytics Engine dataset backing `ctx.analytics` (defaults to `env.ANALYTICS`).",method:"analytics"},contextProperty:"analytics",key:"analytics",moduleSpecifier:"@lunora/bindings/analytics",serverCtxField:{field:`
1
+ import{agentComponent as ct}from"@lunora/agent/component";import{LunoraError as X}from"@lunora/errors";import{serializeSchemaSnapshot as xn,hashSchemaSnapshot as vn}from"./SCHEMA_SNAPSHOT_VERSION-B1BUjuG5.mjs";import{s as N}from"./paths-C-9fwEgQ.mjs";const dt=[{contextProperty:"access",key:"access",moduleSpecifier:"@lunora/cloudflare-access"},{appMethod:{configKey:"ai",doc:"Override the Workers AI binding backing `ctx.ai` (defaults to `env.AI`).",method:"ai"},contextProperty:"ai",key:"ai",moduleSpecifier:"@lunora/ai"},{appMethod:{configKey:"analytics",doc:"Override the Analytics Engine dataset backing `ctx.analytics` (defaults to `env.ANALYTICS`).",method:"analytics"},contextProperty:"analytics",key:"analytics",moduleSpecifier:"@lunora/bindings/analytics",serverCtxField:{field:`
2
2
  /** Analytics Engine telemetry sink. Fire-and-forget and sampled; do not read it back in-handler. */
3
3
  readonly analytics: import("@lunora/bindings/analytics").AnalyticsClient;`,tier:"every"}},{appMethod:{configKey:"browser",doc:"Override the Browser Rendering binding backing `ctx.browser` (defaults to `env.BROWSER`).",method:"browser"},contextProperty:"browser",key:"browser",moduleSpecifier:"@lunora/browser",serverCtxField:{field:`
4
4
  /** Browser Rendering (screenshots/PDF/scrape). Non-deterministic — available only in actions. */
@@ -1210,7 +1210,6 @@ const LUNORA_SCHEMA_SNAPSHOT: { hash: string; json: string } = { hash: ${JSON.st
1210
1210
  ctx,
1211
1211
  identity: identity?.identity ?? null,
1212
1212
  rlsRequired: (schema as unknown as { rlsMode?: string }).rlsMode === "required",
1213
- roles: (ctx as { auth?: { roles?: readonly string[] } }).auth?.roles ?? [],
1214
1213
  shapeWhere,
1215
1214
  table: shape.table,
1216
1215
  tablePublic: (schema as unknown as { tables: Record<string, { isPublic?: boolean }> }).tables[shape.table]?.isPublic === true,
@@ -1,4 +1,4 @@
1
- import{A as S,G as D}from"./emit-BcAkLUfn.mjs";const E=e=>`has${e.charAt(0).toUpperCase()}${e.slice(1)}`,v=S.map(({appMethod:e,key:t})=>[E(t),e.method,e.configKey,e.doc]),m=e=>v.some(([t])=>e[t]),A=e=>e?['import * as lunoraIdentityContract from "../identity.js";']:[],x=(e,t)=>e?['import type { CreateAccessResolverOptions } from "@lunora/cloudflare-access";',`import { createAccessResolver${t?", composeResolvers":""} } from "@lunora/cloudflare-access";`]:[],R=e=>e?['import { createKvIntrospectorFromEnv } from "@lunora/bindings/kv";']:[],C=e=>e?['import notifyConfig from "../notify.js";']:[],k=e=>(e.emailAgents?.length??0)>0,O=e=>k(e)?['import { dispatchAgentEmail } from "@lunora/agent/inbound";']:[],T=e=>k(e)?['import * as lunoraAgentDefinitions from "../agents.js";']:[],L=e=>{const{hasAccess:t,hasAuth:a,hasFramework:r,hasGlobal:n,hasHyperdriveGlobal:s,hasKvIntrospector:l,hasQueue:o,hasScheduler:d,hasStorage:h,hasWorkflow:u,useUmbrella:c,wantsOpenApi:p,wantsOpenRpc:b}=e,i=c?"lunorash/runtime":"@lunora/runtime",g=["ExecutionContextLike","HttpRouterLike","LunoraWorker","Route","ScheduledControllerLike","ShardNamespaceLike","WorkerOptions"];n&&g.push("GlobalIntrospector","AdminTableResolver"),r&&g.push("FrameworkHostHandler");const f=[...n||s?["createCrossShardRelationCapabilities"]:[],"createWorker","resolveLogArchiveFromEnv",...r?["withFrameworkWorker"]:[]].join(", ");return[...a?['import type { AuthNamespaceLike, LunoraAuth, LunoraAuthOptions } from "@lunora/auth";','import { createAuth, createAuthAdmin, createAuthAuditReader, createDoAuthWiring, d1Executor, ensureMigrated, handleAuthRequest, lunoraD1Adapter } from "@lunora/auth";']:[],...x(t,a),...n?['import type { D1CtxDbOptions, D1DatabaseLike, D1Exec } from "@lunora/d1";','import { applyCdcChanges, createD1CtxDb, exportGlobalRows, facetGlobalColumn, importGlobalRows, listGlobalTables, readD1CdcChanges, readGlobalTablePage, retryingExec } from "@lunora/d1";']:[],...s?['import type { HyperdriveEngine } from "@lunora/hyperdrive/global";','import { createHyperdriveGlobalCtxDb } from "@lunora/hyperdrive/global";','import type { SqlCtxDbOptions, SqlExec } from "@lunora/sql-store";']:[],...R(l),...d?['import type { DurableObjectNamespaceLike } from "@lunora/scheduler";','import { createScheduler } from "@lunora/scheduler";']:[],...h?['import type { R2BucketLike, R2S3Credentials, Storage } from "@lunora/storage";','import { createBucketStorage, createStorage } from "@lunora/storage";']:[],...u?['import { createWorkflowsRestClient } from "@lunora/workflow";']:[],...O(e),`import type { ${[...g].toSorted((w,y)=>w.localeCompare(y)).join(", ")} } from "${i}";`,`import { ${f} } from "${i}";`,"",...A(e.identity),...T(e),...n||s?['import schema from "../schema.js";']:[],...C(e.hasNotify),'import { LUNORA_CRONS } from "./crons.js";','import { LUNORA_FUNCTIONS } from "./functions.js";',...o?['import { createQueueCaptureSink, dispatchQueueBatch, shouldCaptureQueue } from "@lunora/queue";','import { LUNORA_QUEUE_REGISTRY } from "./queues.js";']:[],...p?['import { openApiSpec } from "./openapi.js";']:[],...b?['import { openRpcSpec } from "./openrpc.js";']:[],'import { createShardDO } from "./shard.js";']},I=e=>[...e.hasStorage?['/** `.storage(...)` declaration — one bucket (required) plus optional extra named buckets and signed-URL config. Backs `ctx.storage` AND the studio file browser. */\ninterface StorageDeclaration<Env> {\n /** The default R2 bucket binding (the bare `ctx.storage`). */\n bucket: Selector<Env, R2BucketLike>;\n /** Extra named buckets, reached via `ctx.storage.bucket("name")` and the studio\'s bucket picker. */\n buckets?: Record<string, Selector<Env, R2BucketLike>>;\n /** Public base URL signed/public object URLs resolve against. */\n publicBaseUrl?: Selector<Env, string>;\n /** R2 S3-API credentials (`{ accountId, accessKeyId, secretAccessKey, bucket, jurisdiction? }`) enabling `ctx.storage.getPresignedUrl` — native S3 presigned URLs that hit R2 directly, bypassing the worker. Omit to use only the worker-signed `getSignedUrl` path. */\n s3?: Selector<Env, R2S3Credentials>;\n /** HMAC secret for signed URLs. */\n signingSecret?: Selector<Env, string>;\n}']:[],...e.hasScheduler?["/** `.scheduler(...)` declaration — the `SchedulerDO` namespace plus the worker origin its callbacks dispatch back to. Backs `ctx.scheduler` AND the studio's scheduled-jobs view. */\ninterface SchedulerDeclaration<Env> {\n /** The `SchedulerDO` namespace binding (typically `env.SCHEDULER`). */\n namespace: Selector<Env, DurableObjectNamespaceLike & ShardNamespaceLike>;\n /** The worker origin the `SchedulerDO` dispatches HTTP job callbacks back to. */\n origin?: Selector<Env, string>;\n}"]:[],...e.hasGlobal?["/** `.global(...)` declaration — the D1 binding backing `.global()` tables. Backs cross-tenant `ctx.db` reads/writes AND the studio's global data browser. */\ninterface GlobalDeclaration<Env> {\n /** The D1 binding (typically `env.DB`). */\n d1: Selector<Env, D1DatabaseLike>;\n /** The worker origin used to fan reverse cross-backend relations across shards. Without it, such a relation throws a clear error. */\n origin?: Selector<Env, string>;\n}"]:[],...e.hasHyperdriveGlobal?['/** `.hyperdriveGlobal(...)` declaration — backs `.global({ backend: "hyperdrive" })` tables on a Postgres/MySQL database via Hyperdrive. Stays reactive: the writer is injected as `globalDb` and the broadcast hook drives live queries. */\ninterface HyperdriveGlobalDeclaration<Env> {\n /** The Hyperdrive engine — selects the Postgres or MySQL dialect. */\n engine: HyperdriveEngine;\n /** Build the `SqlExec` from `env` — e.g. `buildPgExec(fromPostgresJs(postgres(env.HYPERDRIVE.connectionString)))`. Cache the driver on the DO instance; rebuild lazily after hibernation. */\n exec: (env: Env) => SqlExec;\n /** The worker origin used to fan reverse cross-backend relations across shards. Without it, such a relation throws a clear error. */\n origin?: Selector<Env, string>;\n}']:[],...e.hasAuth?['/** `.auth(...)` declaration — better-auth options plus the storage the adapter reads. Give it `d1` (the default) or `namespace` (a Durable Object that hosts the auth tables), never both. The builder owns the lazy build + `ensureMigrated` dance and wires `authHandler` / `resolveIdentity` / `authAdmin`. */\ninterface AuthDeclaration<Env> {\n /** The D1 binding the auth SQL adapter is wired over (via `lunoraD1Adapter`). Omit only when using `namespace`. */\n d1?: Selector<Env, unknown>;\n /** Shared secret the worker presents on the object\'s internal session route. REQUIRED with `namespace`: the binding is reachable from any worker bound to it, so the secret — not the binding — is the authorization boundary. Without it identity resolution fails closed. */\n internalSecret?: Selector<Env, string>;\n /** Name of the Durable Object instance holding the auth tables. Defaults to `"auth"`. Set it to run separate auth objects (per deployment, per tenant) off one namespace. */\n objectName?: Selector<Env, string>;\n /** The auth Durable Object namespace — the DO-backed mode. Needed for `@better-auth/scim`, which requires native transactions that D1 has none of. The object owns the auth tables, so `/api/auth/*` and identity resolution both go through it. Typed as `AuthNamespaceLike` because `createDoAuthWiring` resolves through `idFromName` + `get` and has no `getByName` fallback — both members are load-bearing here, and `ShardNamespaceLike` leaves both optional. */\n namespace?: Selector<Env, AuthNamespaceLike>;\n /** Build the better-auth options from `env` (secret, plugins, email/password, …). */\n options: (env: Env) => LunoraAuthOptions;\n}']:[]],q=e=>[...e.hasAccess?[" private accessSelector?: Selector<Env, CreateAccessResolverOptions | undefined>;"]:[]," private adminToken?: Selector<Env, string>;",...e.hasAuth?[" private authDeclaration?: AuthDeclaration<Env>;"]:[]," private cdcEnabled = false;"," private reactiveCacheConfig: boolean | { maxBytes?: number; maxEntries?: number } = false;"," private readonly extendFns: ((env: Env, derived: Readonly<WorkerOptions>) => Partial<WorkerOptions>)[] = [];",...e.hasGlobal?[" private globalDeclaration?: GlobalDeclaration<Env>;"]:[],...e.hasHyperdriveGlobal?[" private hyperdriveGlobalDeclaration?: HyperdriveGlobalDeclaration<Env>;"]:[]," private httpRouterApp?: HttpRouterLike;"," private readonly routeMap: Record<string, Route> = {};",...e.hasScheduler?[" private schedulerDeclaration?: SchedulerDeclaration<Env>;"]:[],...m(e)?[" private readonly shardExtras: Partial<ShardConfig> = {};"]:[]," private shardSelector?: Selector<Env, ShardNamespaceLike>;",...e.hasStorage?[" private storageDeclaration?: StorageDeclaration<Env>;"]:[]],N=e=>v.filter(([t])=>e[t]).map(([,t,a,r])=>` /** ${r} */
1
+ import{A as S,G as D}from"./emit-DHDqyZ_P.mjs";const E=e=>`has${e.charAt(0).toUpperCase()}${e.slice(1)}`,v=S.map(({appMethod:e,key:t})=>[E(t),e.method,e.configKey,e.doc]),m=e=>v.some(([t])=>e[t]),A=e=>e?['import * as lunoraIdentityContract from "../identity.js";']:[],x=(e,t)=>e?['import type { CreateAccessResolverOptions } from "@lunora/cloudflare-access";',`import { createAccessResolver${t?", composeResolvers":""} } from "@lunora/cloudflare-access";`]:[],R=e=>e?['import { createKvIntrospectorFromEnv } from "@lunora/bindings/kv";']:[],C=e=>e?['import notifyConfig from "../notify.js";']:[],k=e=>(e.emailAgents?.length??0)>0,O=e=>k(e)?['import { dispatchAgentEmail } from "@lunora/agent/inbound";']:[],T=e=>k(e)?['import * as lunoraAgentDefinitions from "../agents.js";']:[],L=e=>{const{hasAccess:t,hasAuth:a,hasFramework:r,hasGlobal:n,hasHyperdriveGlobal:o,hasKvIntrospector:c,hasQueue:s,hasScheduler:d,hasStorage:h,hasWorkflow:u,useUmbrella:l,wantsOpenApi:p,wantsOpenRpc:b}=e,i=l?"lunorash/runtime":"@lunora/runtime",g=["ExecutionContextLike","HttpRouterLike","LunoraWorker","Route","ScheduledControllerLike","ShardNamespaceLike","WorkerOptions"];n&&g.push("GlobalIntrospector","AdminTableResolver"),r&&g.push("FrameworkHostHandler");const f=[...n||o?["createCrossShardRelationCapabilities"]:[],"createWorker","resolveLogArchiveFromEnv",...r?["withFrameworkWorker"]:[]].join(", ");return[...a?['import type { AuthNamespaceLike, LunoraAuth, LunoraAuthOptions } from "@lunora/auth";','import { createAuth, createAuthAdmin, createAuthAuditReader, createDoAuthWiring, d1Executor, ensureMigrated, handleAuthRequest, lunoraD1Adapter } from "@lunora/auth";']:[],...x(t,a),...n?['import type { D1CtxDbOptions, D1DatabaseLike, D1Exec } from "@lunora/d1";','import { applyCdcChanges, createD1CtxDb, exportGlobalRows, facetGlobalColumn, importGlobalRows, listGlobalTables, readD1CdcChanges, readGlobalTablePage, retryingExec } from "@lunora/d1";']:[],...o?['import type { HyperdriveEngine } from "@lunora/hyperdrive/global";','import { createHyperdriveGlobalCtxDb } from "@lunora/hyperdrive/global";','import type { SqlCtxDbOptions, SqlExec } from "@lunora/sql-store";']:[],...R(c),...d?['import type { DurableObjectNamespaceLike } from "@lunora/scheduler";','import { createScheduler } from "@lunora/scheduler";']:[],...h?['import type { R2BucketLike, R2S3Credentials, Storage } from "@lunora/storage";','import { createBucketStorage, createStorage } from "@lunora/storage";']:[],...u?['import { createWorkflowsRestClient } from "@lunora/workflow";']:[],...O(e),`import type { ${[...g].toSorted((w,y)=>w.localeCompare(y)).join(", ")} } from "${i}";`,`import { ${f} } from "${i}";`,"",...A(e.identity),...T(e),...n||o?['import schema from "../schema.js";']:[],...C(e.hasNotify),'import { LUNORA_CRONS } from "./crons.js";','import { LUNORA_FUNCTIONS } from "./functions.js";',...s?['import { createQueueCaptureSink, dispatchQueueBatch, shouldCaptureQueue } from "@lunora/queue";','import { LUNORA_QUEUE_REGISTRY } from "./queues.js";']:[],...p?['import { openApiSpec } from "./openapi.js";']:[],...b?['import { openRpcSpec } from "./openrpc.js";']:[],'import { createShardDO } from "./shard.js";']},I=e=>[...e.hasStorage?['/** `.storage(...)` declaration — one bucket (required) plus optional extra named buckets and signed-URL config. Backs `ctx.storage` AND the studio file browser. */\ninterface StorageDeclaration<Env> {\n /** The default R2 bucket binding (the bare `ctx.storage`). */\n bucket: Selector<Env, R2BucketLike>;\n /** Extra named buckets, reached via `ctx.storage.bucket("name")` and the studio\'s bucket picker. */\n buckets?: Record<string, Selector<Env, R2BucketLike>>;\n /** Public base URL signed/public object URLs resolve against. */\n publicBaseUrl?: Selector<Env, string>;\n /** R2 S3-API credentials (`{ accountId, accessKeyId, secretAccessKey, bucket, jurisdiction? }`) enabling `ctx.storage.getPresignedUrl` — native S3 presigned URLs that hit R2 directly, bypassing the worker. Omit to use only the worker-signed `getSignedUrl` path. */\n s3?: Selector<Env, R2S3Credentials>;\n /** HMAC secret for signed URLs. */\n signingSecret?: Selector<Env, string>;\n}']:[],...e.hasScheduler?["/** `.scheduler(...)` declaration — the `SchedulerDO` namespace plus the worker origin its callbacks dispatch back to. Backs `ctx.scheduler` AND the studio's scheduled-jobs view. */\ninterface SchedulerDeclaration<Env> {\n /** The `SchedulerDO` namespace binding (typically `env.SCHEDULER`). */\n namespace: Selector<Env, DurableObjectNamespaceLike & ShardNamespaceLike>;\n /** The worker origin the `SchedulerDO` dispatches HTTP job callbacks back to. */\n origin?: Selector<Env, string>;\n}"]:[],...e.hasGlobal?["/** `.global(...)` declaration — the D1 binding backing `.global()` tables. Backs cross-tenant `ctx.db` reads/writes AND the studio's global data browser. */\ninterface GlobalDeclaration<Env> {\n /** The D1 binding (typically `env.DB`). */\n d1: Selector<Env, D1DatabaseLike>;\n /** The worker origin used to fan reverse cross-backend relations across shards. Without it, such a relation throws a clear error. */\n origin?: Selector<Env, string>;\n}"]:[],...e.hasHyperdriveGlobal?['/** `.hyperdriveGlobal(...)` declaration — backs `.global({ backend: "hyperdrive" })` tables on a Postgres/MySQL database via Hyperdrive. Stays reactive: the writer is injected as `globalDb` and the broadcast hook drives live queries. */\ninterface HyperdriveGlobalDeclaration<Env> {\n /** The Hyperdrive engine — selects the Postgres or MySQL dialect. */\n engine: HyperdriveEngine;\n /** Build the `SqlExec` from `env` — e.g. `buildPgExec(fromPostgresJs(postgres(env.HYPERDRIVE.connectionString)))`. Cache the driver on the DO instance; rebuild lazily after hibernation. */\n exec: (env: Env) => SqlExec;\n /** The worker origin used to fan reverse cross-backend relations across shards. Without it, such a relation throws a clear error. */\n origin?: Selector<Env, string>;\n}']:[],...e.hasAuth?['/** `.auth(...)` declaration — better-auth options plus the storage the adapter reads. Give it `d1` (the default) or `namespace` (a Durable Object that hosts the auth tables), never both. The builder owns the lazy build + `ensureMigrated` dance and wires `authHandler` / `resolveIdentity` / `authAdmin`. */\ninterface AuthDeclaration<Env> {\n /** The D1 binding the auth SQL adapter is wired over (via `lunoraD1Adapter`). Omit only when using `namespace`. */\n d1?: Selector<Env, unknown>;\n /** Shared secret the worker presents on the object\'s internal session route. REQUIRED with `namespace`: the binding is reachable from any worker bound to it, so the secret — not the binding — is the authorization boundary. Without it identity resolution fails closed. */\n internalSecret?: Selector<Env, string>;\n /** Name of the Durable Object instance holding the auth tables. Defaults to `"auth"`. Set it to run separate auth objects (per deployment, per tenant) off one namespace. */\n objectName?: Selector<Env, string>;\n /** The auth Durable Object namespace — the DO-backed mode. Needed for `@better-auth/scim`, which requires native transactions that D1 has none of. The object owns the auth tables, so `/api/auth/*` and identity resolution both go through it. Typed as `AuthNamespaceLike` because `createDoAuthWiring` resolves through `idFromName` + `get` and has no `getByName` fallback — both members are load-bearing here, and `ShardNamespaceLike` leaves both optional. */\n namespace?: Selector<Env, AuthNamespaceLike>;\n /** Build the better-auth options from `env` (secret, plugins, email/password, …). */\n options: (env: Env) => LunoraAuthOptions;\n}']:[]],q=e=>[...e.hasAccess?[" private accessSelector?: Selector<Env, CreateAccessResolverOptions | undefined>;"]:[]," private adminToken?: Selector<Env, string>;",...e.hasAuth?[" private authDeclaration?: AuthDeclaration<Env>;"]:[]," private cdcEnabled = false;"," private reactiveCacheConfig: boolean | { maxBytes?: number; maxEntries?: number } = false;"," private readonly extendFns: ((env: Env, derived: Readonly<WorkerOptions>) => Partial<WorkerOptions>)[] = [];",...e.hasGlobal?[" private globalDeclaration?: GlobalDeclaration<Env>;"]:[],...e.hasHyperdriveGlobal?[" private hyperdriveGlobalDeclaration?: HyperdriveGlobalDeclaration<Env>;"]:[]," private httpRouterApp?: HttpRouterLike;"," private readonly routeMap: Record<string, Route> = {};",...e.hasScheduler?[" private schedulerDeclaration?: SchedulerDeclaration<Env>;"]:[],...m(e)?[" private readonly shardExtras: Partial<ShardConfig> = {};"]:[]," private shardSelector?: Selector<Env, ShardNamespaceLike>;",...e.hasStorage?[" private storageDeclaration?: StorageDeclaration<Env>;"]:[]],N=e=>v.filter(([t])=>e[t]).map(([,t,a,r])=>` /** ${r} */
2
2
  public ${t}(factory: NonNullable<ShardConfig["${a}"]>): this {
3
3
  this.shardExtras.${a} = factory;
4
4
 
@@ -197,7 +197,16 @@ ${a.join(`
197
197
 
198
198
  const session = await auth.api.getSession({ headers: (request as Request).headers });
199
199
 
200
- return session?.user?.id ? { userId: session.user.id } : null;
200
+ if (!session?.user?.id) {
201
+ return null;
202
+ }
203
+
204
+ // \`role\` rides along so \`rls(policies, { roles })\` and \`auth.can(...)\`
205
+ // work on this wiring without a hand-written resolver. better-auth's
206
+ // \`admin()\` plugin owns that column (comma-joined for multiple roles)
207
+ // and only an administrator can write it; it is absent when the plugin
208
+ // is off, which reads as no roles.
209
+ return { role: (session.user as { role?: unknown }).role, userId: session.user.id };
201
210
  };
202
211
  const authInstance = getAuth();
203
212
 
@@ -508,7 +517,7 @@ const buildGlobalCdcApplier =
508
517
  return request.changes.length;
509
518
  };
510
519
  `:"",_=e=>[...e.hasAuth?["AuthDeclaration"]:[],"ComposedApp",...e.hasGlobal?["GlobalDeclaration"]:[],...e.hasScheduler?["SchedulerDeclaration"]:[],"Selector",...e.hasStorage?["StorageDeclaration"]:[]].toSorted((t,a)=>t.localeCompare(a)).join(", "),F=e=>{const{hasAuth:t}=e,a=I(e),r=B(e),n=t?` let auth: LunoraAuth | null = null;
511
- `:"",s=t?`
520
+ `:"",o=t?`
512
521
  const ensureAuth = async (env: Env): Promise<void> => {
513
522
  if (!this.authDeclaration || auth) {
514
523
  return;
@@ -528,10 +537,10 @@ const buildGlobalCdcApplier =
528
537
  // migrator). For production run the migrate command ahead of deploy.
529
538
  await ensureMigrated(createAuth({ ...this.authDeclaration.options(env), database: d1(env) as never }));
530
539
  };
531
- `:"",l=t?`
532
- await ensureAuth(env);`:"",o=t?"() => auth":"() => null",d=t?"getAuth: () => LunoraAuth | null":"_getAuth: () => null",h=e.hasFramework?` const buildWorker = (env: Env): LunoraWorker =>
533
- host ? withFrameworkWorker(host, (hostEnv) => this.buildWorkerOptions(hostEnv as Env, ${o})) : createWorker(this.buildWorkerOptions(env, ${o}));`:` const buildWorker = (env: Env): LunoraWorker => createWorker(this.buildWorkerOptions(env, ${o}));`,u=e.hasFramework?"host?: FrameworkHostHandler":"",c=e.emailAgents??[],p=c.length>0?` composed.email = dispatchAgentEmail([
534
- ${c.map(i=>` { agent: lunoraAgentDefinitions.${i.exportName}, binding: ${JSON.stringify(i.bindingName)} },`).join(`
540
+ `:"",c=t?`
541
+ await ensureAuth(env);`:"",s=t?"() => auth":"() => null",d=t?"getAuth: () => LunoraAuth | null":"_getAuth: () => null",h=e.hasFramework?` const buildWorker = (env: Env): LunoraWorker =>
542
+ host ? withFrameworkWorker(host, (hostEnv) => this.buildWorkerOptions(hostEnv as Env, ${s})) : createWorker(this.buildWorkerOptions(env, ${s}));`:` const buildWorker = (env: Env): LunoraWorker => createWorker(this.buildWorkerOptions(env, ${s}));`,u=e.hasFramework?"host?: FrameworkHostHandler":"",l=e.emailAgents??[],p=l.length>0?` composed.email = dispatchAgentEmail([
543
+ ${l.map(i=>` { agent: lunoraAgentDefinitions.${i.exportName}, binding: ${JSON.stringify(i.bindingName)} },`).join(`
535
544
  `)}
536
545
  ]);
537
546
 
@@ -582,13 +591,13 @@ ${b}
582
591
  // build, so the first request constructs them and every later request on
583
592
  // the same isolate reuses them.
584
593
  let worker: LunoraWorker | null = null;
585
- ${n}${s}
594
+ ${n}${o}
586
595
  ${h}
587
596
 
588
597
  const composed: ComposedApp = {
589
598
  ShardDO,
590
599
  fetch: async (request: Request, rawEnv: unknown, context: ExecutionContextLike): Promise<Response> => {
591
- const env = rawEnv as Env;${l}
600
+ const env = rawEnv as Env;${c}
592
601
  worker ??= buildWorker(env);
593
602
 
594
603
  return worker.fetch(request, rawEnv, context);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/codegen",
3
- "version": "1.0.0-alpha.146",
3
+ "version": "1.0.0-alpha.148",
4
4
  "description": "Code generator for Lunora: emits _generated/{api,server,dataModel}.ts from your schema",
5
5
  "keywords": [
6
6
  "cloudflare",
@@ -46,15 +46,15 @@
46
46
  "access": "public"
47
47
  },
48
48
  "dependencies": {
49
- "@lunora/advisor": "1.0.0-alpha.102",
50
- "@lunora/agent": "1.0.0-alpha.78",
51
- "@lunora/container": "1.0.0-alpha.38",
52
- "@lunora/errors": "1.0.0-alpha.27",
49
+ "@lunora/advisor": "1.0.0-alpha.104",
50
+ "@lunora/agent": "1.0.0-alpha.80",
51
+ "@lunora/container": "1.0.0-alpha.39",
52
+ "@lunora/errors": "1.0.0-alpha.28",
53
53
  "@lunora/platform": "1.0.0-alpha.23",
54
- "@lunora/queue": "1.0.0-alpha.40",
55
- "@lunora/scheduler": "1.0.0-alpha.46",
56
- "@lunora/values": "1.0.0-alpha.35",
57
- "@lunora/workflow": "1.0.0-alpha.39",
54
+ "@lunora/queue": "1.0.0-alpha.41",
55
+ "@lunora/scheduler": "1.0.0-alpha.48",
56
+ "@lunora/values": "1.0.0-alpha.36",
57
+ "@lunora/workflow": "1.0.0-alpha.41",
58
58
  "jsonc-parser": "^3.3.1",
59
59
  "quicktype-core": "^26.0.0",
60
60
  "ts-morph": "^28.0.0"
@@ -1,2 +0,0 @@
1
- const a=(e,i=2166136261)=>{let t=i;for(let o=0;o<e.length;o+=1)t^=e.codePointAt(o)??0,t=Math.imul(t,16777619);return(t>>>0).toString(16).padStart(8,"0")},l=e=>`${a(e,2166136261)}${a(e,16777619)}`,g=1;function S(e){const i={},t=Object.keys(e);t.sort();for(const o of t)i[o]=e[o];return i}const c=e=>`${JSON.stringify(e,void 0,2)}
2
- `,$=e=>l(c(e)),r=e=>typeof e=="object"&&e!==null,f=e=>r(e)&&r(e.fields)&&r(e.indexes)&&r(e.relations)&&typeof e.shardMode=="string",k=e=>{if(e===void 0||e.trim()==="")return{status:"absent"};let i;try{i=JSON.parse(e)}catch(o){return{error:`baseline is not valid JSON: ${o instanceof Error?o.message:String(o)}`,status:"invalid"}}if(!r(i)||i.version!==1||!r(i.tables))return{error:`baseline is malformed or written by an incompatible version (expected version ${String(1)})`,status:"invalid"};for(const[o,s]of Object.entries(i.tables))if(!f(s))return{error:`baseline table "${o}" has an invalid structure`,status:"invalid"};return{snapshot:{jurisdiction:typeof i.jurisdiction=="string"?i.jurisdiction:void 0,migrationIds:Array.isArray(i.migrationIds)?i.migrationIds:[],tables:i.tables,version:1},status:"ok"}},p=(e,i)=>e.unique===i.unique&&e.fields.length===i.fields.length&&e.fields.every((t,o)=>t===i.fields[o]),h=(e,i,t,o)=>{const s=[];return t.kind!==o.kind&&s.push({remediation:"backfill",severity:"breaking",summary:`field ${e}.${i} changed type: ${t.kind} → ${o.kind} — add a data migration to convert existing values`,table:e,scope:"table",type:"changedFieldKind"}),t.optional&&!o.optional?s.push({remediation:"backfill",severity:"breaking",summary:`field ${e}.${i} became required — rows missing it would be invalid; add a data migration to backfill it`,table:e,scope:"table",type:"fieldOptionalToRequired"}):!t.optional&&o.optional&&s.push({remediation:"none",scope:"table",severity:"safe",summary:`field ${e}.${i} became optional`,table:e,type:"fieldRequiredToOptional"}),s},m=(e,i,t)=>t.optional?{remediation:"none",scope:"table",severity:"safe",summary:`added optional field ${e}.${i}`,table:e,type:"addedOptionalField"}:{remediation:"backfill",severity:"breaking",summary:`added required field ${e}.${i} — existing rows have no value; add a data migration to backfill it`,table:e,scope:"table",type:"addedRequiredField"},u=(e,i,t,o)=>{for(const[s,n]of Object.entries(t.fields)){const d=i.fields[s];d===void 0?o.push(m(e,s,n)):o.push(...h(e,s,d,n))}for(const s of Object.keys(i.fields))t.fields[s]===void 0&&o.push({remediation:"backfill",severity:"breaking",summary:`removed field ${e}.${s} — add a data migration if stored data must be cleaned up`,table:e,scope:"table",type:"removedField"})},y=(e,i,t,o)=>{for(const[s,n]of Object.entries(t.indexes)){const d=i.indexes[s];if(d===void 0){o.push({remediation:"none",scope:"table",severity:"safe",summary:`added index ${s} on ${e}`,table:e,type:"addedIndex"});continue}p(d,n)||o.push({remediation:"code",severity:"breaking",summary:`index ${s} on ${e} changed shape — a query may have relied on the old index`,table:e,scope:"table",type:"changedIndex"})}for(const s of Object.keys(i.indexes))t.indexes[s]===void 0&&o.push({remediation:"code",severity:"breaking",summary:`removed index ${s} on ${e} — a query that used \`.withIndex("${s}")\` would break`,table:e,scope:"table",type:"removedIndex"})},b=(e,i,t,o)=>{for(const s of Object.keys(t.relations))i.relations[s]===void 0&&o.push({remediation:"none",scope:"schema",severity:"safe",summary:`added relation ${e}.${s}`,table:e,type:"addedRelation"});for(const s of Object.keys(i.relations))t.relations[s]===void 0&&o.push({remediation:"code",scope:"schema",severity:"breaking",summary:`removed relation ${e}.${s}`,table:e,type:"removedRelation"})},v=(e,i,t,o)=>{i.shardMode!==t.shardMode&&o.push({remediation:"rehome",severity:"breaking",summary:`table ${e} changed shard mode: ${i.shardMode} → ${t.shardMode} — its physical storage moves, and existing rows do NOT follow the schema; re-home them with an export/import round trip (https://lunora.sh/docs/concepts/sharding#migrating-a-populated-table)`,table:e,scope:"table",type:"changedShardMode"}),u(e,i,t,o),y(e,i,t,o),b(e,i,t,o)},O=(e,i)=>{const t=[],o=e?.tables??{};for(const[s,n]of Object.entries(i.tables)){const d=o[s];if(d===void 0){t.push({remediation:"none",scope:"table",severity:"safe",summary:`added table ${s}`,table:s,type:"addedTable"});continue}v(s,d,n,t)}for(const s of Object.keys(o))i.tables[s]===void 0&&t.push({remediation:"rehome",scope:"table",severity:"breaking",summary:`removed table ${s} — its rows stay in each shard's SQLite, unreachable through the schema; export the shard first if the data must be kept`,table:s,type:"removedTable"});if(e!==void 0&&e.jurisdiction!==i.jurisdiction){const s=e.jurisdiction??"(none)",n=i.jurisdiction??"(none)";t.push({remediation:"rehome",scope:"schema",severity:"breaking",summary:`Durable Object jurisdiction changed from ${s} to ${n} — this re-homes every DO and strands all existing shard, scheduler, and session-DO data in the old region (no in-place migration; export then import to move it). Revert the change, or override the gate to proceed intentionally.`,type:"changedJurisdiction"})}return{changes:t}};export{g as SCHEMA_SNAPSHOT_VERSION,O as diffSchemaSnapshots,$ as hashSchemaSnapshot,f as isValidTableSnapshot,k as parseSnapshotJson,c as serializeSchemaSnapshot,S as sortKeys};
@@ -1,18 +0,0 @@
1
- import{LunoraError as $}from"@lunora/errors";import{SCHEMA_SNAPSHOT_VERSION as y,sortKeys as E,diffSchemaSnapshots as I,parseSnapshotJson as T}from"./SCHEMA_SNAPSHOT_VERSION-CTWRkAF5.mjs";import{serializeSchemaSnapshot as q}from"./SCHEMA_SNAPSHOT_VERSION-CTWRkAF5.mjs";const _=e=>e==="global"||e==="root"?e:`shardBy:${e.field}`,A=e=>e.kind==="optional"?{kind:e.inner?.kind??"unknown",optional:!0}:{kind:e.kind,optional:!1},L=e=>{const n={};for(const[t,i]of Object.entries(e.shape))n[t]=A(i);const s={};for(const t of e.indexes)s[t.name]={fields:[...t.fields],unique:t.unique??!1};const o={};for(const t of e.relations)o[t.name]={field:t.field,kind:t.kind,table:t.table};return{fields:n,indexes:s,relations:o,shardMode:_(e.shardMode)}},R=(e,n)=>{const s={};for(const t of e.tables)s[t.name]=L(t);const o=[...n].sort();return{jurisdiction:e.jurisdiction,migrationIds:o,tables:E(s),version:y}};class D extends ${constructor(n){super("SCHEMA_SNAPSHOT_PARSE",n,{name:"SchemaSnapshotParseError"})}}const F=e=>{const n=T(e);if(n.status==="invalid")throw new D(n.error);return n.status==="ok"?n.snapshot:void 0},M={deploy:{allowDrift:!0,updateBaseline:!0},prepare:{allowDrift:!0,updateBaseline:!0},verify:{allowDrift:!0,updateBaseline:!1}},g=" • For backward-compatible changes (e.g. adding an optional field): pass `--allow-schema-drift` to skip the block.",S=" • To accept the new shape without a migration (you know data is compatible): pass `--update-schema-baseline`.",j=e=>{const n=e===void 0?void 0:M[e];if(e===void 0||n===void 0)return`${g}
2
- ${S}
3
- `;const s=n.updateBaseline?S:` • To accept the new shape without a migration, run \`lunora prepare --update-schema-baseline\` — \`lunora ${e}\` does not take that flag.`;return`${g}
4
- ${s}
5
- `},h=e=>e.map(n=>` - ${n.summary}`).join(`
6
- `),w=e=>e.remediation==="backfill"&&e.table!==void 0,x=/^[A-Za-z_]\w*$/u,B=e=>` lunora migrate create backfill_${e} --table ${e}`,O=(e,n,s)=>{const o=[...new Set(e.filter(i=>w(i)).map(i=>i.table))],t=[];if(o.length>0){t.push(" • Add a `defineMigration({ id, table, up })` in lunora/ for each affected table, then re-run this command — the baseline is re-blessed on a successful deploy, not by `lunora migrate` itself.\n");const i=o.filter(r=>x.test(r));i.length>0&&t.push(`
7
- Scaffold the missing migration(s) — the generated \`up\` is an identity placeholder you must fill in:
8
- ${i.map(r=>B(r)).join(`
9
- `)}
10
-
11
- `)}return n.length>0&&t.push(` • Migration(s) ${n.join(", ")} declare a non-literal \`table\`, so codegen cannot tell which table they visit and they cover nothing. Use a string literal.
12
- `),t.push(j(s)),[`deploy blocked: ${String(e.length)} unresolved breaking schema change(s) since the last blessed schema baseline:`,h(e),"",`To fix:
13
- ${t.join("")}Docs: https://lunora.dev/docs/migrations`].join(`
14
- `)},H=e=>{const{allowDrift:n=!1,baseline:s,command:o,current:t,migrations:i}=e,r=I(s,t),d=r.changes.filter(a=>a.severity==="breaking"),p=t.migrationIds.filter(a=>!(s?.migrationIds??[]).includes(a)),u=i.filter(a=>p.includes(a.id)),l=(a,f)=>({blocked:a,changes:r.changes,newMigrationIds:p,reason:f}),k=new Set(u.filter(a=>a.table!=="").map(a=>a.table)),v=u.filter(a=>a.table==="").map(a=>a.id);if(r.changes.length===0||s===void 0)return l(!1,"");if(d.length===0)return l(!1,`schema drift detected (all additive/safe):
15
- ${h(r.changes)}`);const m=d.filter(a=>!w(a)||!k.has(a.table));if(m.length===0){const a=new Set(d.map(c=>c.table)),f=u.filter(c=>a.has(c.table)).map(c=>c.id);return l(!1,`breaking schema drift detected, covered by ${String(f.length)} new migration(s) (${f.join(", ")}):
16
- ${h(d)}`)}const b=O(m,v,o);return n?l(!1,`${b}
17
-
18
- (overridden by --allow-schema-drift)`):l(!0,b)};export{y as SCHEMA_SNAPSHOT_VERSION,D as SchemaSnapshotParseError,R as buildSchemaSnapshot,I as diffSchemaSnapshots,H as evaluateSchemaDrift,F as parseSchemaSnapshot,q as serializeSchemaSnapshot};