@lunora/codegen 1.0.0-alpha.4 → 1.0.0-alpha.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/LICENSE.md +6 -0
  2. package/__assets__/package-og.svg +1 -1
  3. package/dist/index.d.mts +1175 -25
  4. package/dist/index.d.ts +1175 -25
  5. package/dist/index.mjs +30 -24
  6. package/dist/packem_shared/{CONTAINERS_FILENAME-0K-pjNb8.mjs → CONTAINERS_FILENAME-DjpXMqhp.mjs} +1 -1
  7. package/dist/packem_shared/{CodegenDiagnosticError-54jWDxA9.mjs → CodegenDiagnosticError-DyQ5FwkM.mjs} +7 -5
  8. package/dist/packem_shared/FLAGS_FILENAME-fEZtzWXi.mjs +139 -0
  9. package/dist/packem_shared/GENERATED_HEADER-cUyu5VOU.mjs +3 -0
  10. package/dist/packem_shared/{LUNORA_ERROR_CODES-CySpQPD3.mjs → LUNORA_ERROR_CODES-DvTLozCu.mjs} +8 -1
  11. package/dist/packem_shared/MUTATORS_FILENAME-BZOfUhlY.mjs +81 -0
  12. package/dist/packem_shared/{OPENRPC_VERSION-C7zKVeKi.mjs → OPENRPC_VERSION-DxbqafcJ.mjs} +2 -2
  13. package/dist/packem_shared/QUEUES_FILENAME-Xv6Vy-Ku.mjs +145 -0
  14. package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-C1yHg38Z.mjs +3438 -0
  15. package/dist/packem_shared/{SCHEMA_SNAPSHOT_VERSION-DzLDbWk3.mjs → SCHEMA_SNAPSHOT_VERSION-D0ARY6rL.mjs} +18 -2
  16. package/dist/packem_shared/SHAPES_FILENAME-DOhPGi-6.mjs +94 -0
  17. package/dist/packem_shared/{WORKFLOWS_FILENAME-DRDQdhfq.mjs → WORKFLOWS_FILENAME-B2By8S4s.mjs} +70 -2
  18. package/dist/packem_shared/{buildOpenApiDocument-Cns1EkCQ.mjs → buildOpenApiDocument-_mwWOc2N.mjs} +2 -2
  19. package/dist/packem_shared/{discoverAuthApiCalls-C35R6z0T.mjs → discoverAuthApiCalls-WMx8L2FG.mjs} +1 -1
  20. package/dist/packem_shared/{discoverCrons-BL6iGuJ3.mjs → discoverCrons-D-jrpm97.mjs} +22 -20
  21. package/dist/packem_shared/{discoverFunctions-DEgAcRuD.mjs → discoverFunctions-CZ91aenA.mjs} +72 -14
  22. package/dist/packem_shared/{discoverHttpRoutes-C978pBiG.mjs → discoverHttpRoutes-DNZLDCmm.mjs} +2 -2
  23. package/dist/packem_shared/{discoverInserts-CRQdXvHO.mjs → discoverInserts-DFRJhmCv.mjs} +24 -2
  24. package/dist/packem_shared/{discoverMaskProcedures-B64zA740.mjs → discoverMaskProcedures-B5iFnZ-X.mjs} +58 -2
  25. package/dist/packem_shared/{discoverMigrations-Doj_-BAA.mjs → discoverMigrations-CdKtMlBc.mjs} +10 -4
  26. package/dist/packem_shared/{discoverNondeterministicCalls-4KiPQxQU.mjs → discoverNondeterministicCalls-C_PrQPkA.mjs} +1 -1
  27. package/dist/packem_shared/{discoverQueries-BkIi0dBD.mjs → discoverQueries-B8W9UPrt.mjs} +1 -1
  28. package/dist/packem_shared/{discoverR2sqlCalls-BpDqvcUn.mjs → discoverR2sqlCalls-Bm7Rfnf4.mjs} +1 -1
  29. package/dist/packem_shared/{discoverRlsMetadata-DpRB1HMe.mjs → discoverRlsMetadata-B4GL4ZKm.mjs} +1 -1
  30. package/dist/packem_shared/{discoverSchema-BBulgGbH.mjs → discoverSchema-DFWVgU5o.mjs} +349 -17
  31. package/dist/packem_shared/{discoverStorageRulesMetadata-DAqJUxUv.mjs → discoverStorageRulesMetadata-nosjYcvN.mjs} +1 -1
  32. package/dist/packem_shared/{GENERATED_HEADER-DF1hQcix.mjs → emit-CFz-9dcD.mjs} +1100 -122
  33. package/dist/packem_shared/{emitApp-Ci_hcJNO.mjs → emitApp-D8rVuM__.mjs} +99 -30
  34. package/dist/packem_shared/formatAdvisories-DRhEiJUz.mjs +114 -0
  35. package/dist/packem_shared/{parse-validator-tuQtHrsr.mjs → parse-validator-BSJo1HGP.mjs} +18 -6
  36. package/dist/packem_shared/redact-oTmsol5A.mjs +33 -0
  37. package/package.json +9 -7
  38. package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-C5UlpWKF.mjs +0 -922
  39. package/dist/packem_shared/formatAdvisories-8NIv1k0I.mjs +0 -69
@@ -1,6 +1,7 @@
1
1
  import { relative, sep } from 'node:path';
2
2
  import { SyntaxKind, Node } from 'ts-morph';
3
- import { listLunoraSourceFiles } from './discoverFunctions-DEgAcRuD.mjs';
3
+ import { diagnosticAt } from './CodegenDiagnosticError-DyQ5FwkM.mjs';
4
+ import { listLunoraSourceFiles } from './discoverFunctions-CZ91aenA.mjs';
4
5
 
5
6
  const TS_EXTENSION_RE = /\.ts$/u;
6
7
  const isDefineMigration = (identifier) => {
@@ -43,9 +44,14 @@ const migrationFromDeclaration = (declaration, relativePath) => {
43
44
  const id = stringProperty(argument, "id");
44
45
  const exportName = declaration.getName();
45
46
  if (id === void 0 || id.trim() === "") {
46
- throw Object.assign(
47
- new Error(`Migration "${exportName}" in "${relativePath}" must declare \`id\` as a non-empty string literal so codegen can key the registry.`),
48
- { code: "MIGRATION_ID_NOT_STATIC", name: "LunoraError", status: 500 }
47
+ throw diagnosticAt(
48
+ argument,
49
+ `Migration "${exportName}" in "${relativePath}" must declare \`id\` as a non-empty string literal so codegen can key the registry.`,
50
+ {
51
+ code: "MIGRATION_ID_NOT_STATIC",
52
+ name: "LunoraError",
53
+ status: 500
54
+ }
49
55
  );
50
56
  }
51
57
  return { exportName, filePath: relativePath, id, table: stringProperty(argument, "table") ?? "" };
@@ -1,5 +1,5 @@
1
1
  import { Node, SyntaxKind } from 'ts-morph';
2
- import { listLunoraSourceFiles, lunoraRelativePath, classifyProcedureCall } from './discoverFunctions-DEgAcRuD.mjs';
2
+ import { listLunoraSourceFiles, lunoraRelativePath, classifyProcedureCall } from './discoverFunctions-CZ91aenA.mjs';
3
3
 
4
4
  const PROPERTY_CALLS = {
5
5
  "crypto.getRandomValues": "crypto.getRandomValues",
@@ -1,5 +1,5 @@
1
1
  import { SyntaxKind, Node } from 'ts-morph';
2
- import { listLunoraSourceFiles, lunoraRelativePath } from './discoverFunctions-DEgAcRuD.mjs';
2
+ import { listLunoraSourceFiles, lunoraRelativePath } from './discoverFunctions-CZ91aenA.mjs';
3
3
 
4
4
  const INDEX_METHODS = /* @__PURE__ */ new Set(["withIndex", "withSearchIndex"]);
5
5
  const isDatabaseQueryCall = (call) => {
@@ -1,5 +1,5 @@
1
1
  import { Node, SyntaxKind } from 'ts-morph';
2
- import { listLunoraSourceFiles, lunoraRelativePath, classifyProcedureCall } from './discoverFunctions-DEgAcRuD.mjs';
2
+ import { listLunoraSourceFiles, lunoraRelativePath, classifyProcedureCall } from './discoverFunctions-CZ91aenA.mjs';
3
3
 
4
4
  const handlerOf = (call, receiver) => {
5
5
  if (receiver) {
@@ -1,5 +1,5 @@
1
1
  import { Node, SyntaxKind } from 'ts-morph';
2
- import { listLunoraSourceFiles, lunoraRelativePath, classifyProcedureCall } from './discoverFunctions-DEgAcRuD.mjs';
2
+ import { listLunoraSourceFiles, lunoraRelativePath, classifyProcedureCall } from './discoverFunctions-CZ91aenA.mjs';
3
3
 
4
4
  const isRlsCall = (node) => {
5
5
  if (!Node.isCallExpression(node)) {
@@ -1,6 +1,213 @@
1
- import { SyntaxKind, Node } from 'ts-morph';
2
- import { diagnosticAt } from './CodegenDiagnosticError-54jWDxA9.mjs';
3
- import { a as parseObjectShape } from './parse-validator-tuQtHrsr.mjs';
1
+ import { LunoraError } from '@lunora/errors';
2
+ import { Node, SyntaxKind } from 'ts-morph';
3
+ import { diagnosticAt } from './CodegenDiagnosticError-DyQ5FwkM.mjs';
4
+ import { a as parseObjectShape } from './parse-validator-BSJo1HGP.mjs';
5
+ import { createRequire } from 'node:module';
6
+ import { join } from 'node:path';
7
+
8
+ const renderLiteralValue = (value) => {
9
+ switch (typeof value) {
10
+ case "bigint": {
11
+ return value.toString();
12
+ }
13
+ case "boolean":
14
+ case "number": {
15
+ return String(value);
16
+ }
17
+ case "string": {
18
+ return JSON.stringify(value);
19
+ }
20
+ default: {
21
+ return value === null ? "null" : void 0;
22
+ }
23
+ }
24
+ };
25
+ const columnMetaToIR = (column) => {
26
+ const hasDefault = column?.["defaultValue"] !== void 0 || column?.["defaultFn"] !== void 0 || column?.["serverDefault"] !== void 0;
27
+ return {
28
+ ...hasDefault ? { hasDefault: true } : {},
29
+ ...column?.["onUpdateFn"] === void 0 ? {} : { hasOnUpdate: true },
30
+ notNull: column?.["notNull"] ?? true,
31
+ ...column?.["unique"] === true ? { unique: true } : {}
32
+ };
33
+ };
34
+ const runtimeValidatorToIR = (validator) => {
35
+ const meta = validator?._meta ?? {};
36
+ const kind = validator?.kind ?? "unknown";
37
+ const ir = { column: columnMetaToIR(meta["column"]), kind };
38
+ switch (kind) {
39
+ case "array":
40
+ case "optional": {
41
+ ir.inner = runtimeValidatorToIR(meta["inner"]);
42
+ break;
43
+ }
44
+ case "id": {
45
+ ir.tableName = meta["tableName"];
46
+ break;
47
+ }
48
+ case "literal": {
49
+ ir.literalValue = renderLiteralValue(meta["value"]);
50
+ break;
51
+ }
52
+ case "object": {
53
+ const shape = meta["shape"] ?? {};
54
+ ir.shape = Object.fromEntries(Object.entries(shape).map(([name, child]) => [name, runtimeValidatorToIR(child)]));
55
+ break;
56
+ }
57
+ case "record": {
58
+ ir.valueType = runtimeValidatorToIR(meta["valueValidator"]);
59
+ if (meta["keyValidator"] !== void 0) {
60
+ ir.keyType = runtimeValidatorToIR(meta["keyValidator"]);
61
+ }
62
+ break;
63
+ }
64
+ case "storage": {
65
+ if (typeof meta["bucket"] === "string") {
66
+ ir.bucket = meta["bucket"];
67
+ }
68
+ break;
69
+ }
70
+ case "union": {
71
+ const members = meta["members"] ?? [];
72
+ ir.members = members.map((member) => runtimeValidatorToIR(member));
73
+ break;
74
+ }
75
+ }
76
+ return ir;
77
+ };
78
+ const shardModeToIR = (shardMode) => {
79
+ if (shardMode?.kind === "global") {
80
+ return "global";
81
+ }
82
+ if (shardMode?.kind === "shardBy" && typeof shardMode.field === "string") {
83
+ return { field: shardMode.field, kind: "shardBy" };
84
+ }
85
+ return "root";
86
+ };
87
+ const warnDroppedTableFeatures = (builder, bareName) => {
88
+ const dropped = [];
89
+ if (builder.relationMap && Object.keys(builder.relationMap).length > 0) {
90
+ dropped.push("relations");
91
+ }
92
+ if (builder.rankIndexes && builder.rankIndexes.length > 0) {
93
+ dropped.push("rank indexes");
94
+ }
95
+ if (builder.vectorIndexes && builder.vectorIndexes.length > 0) {
96
+ dropped.push("vector indexes");
97
+ }
98
+ if (dropped.length > 0) {
99
+ console.warn(
100
+ `@lunora/codegen: package schema-extension table "${bareName}" declares ${dropped.join(" + ")}, which are not yet introspected from a node_modules extension — they will be absent from the generated types.`
101
+ );
102
+ }
103
+ };
104
+ const runtimeTableToIR = (builder, bareName) => {
105
+ const shape = builder.shape ?? {};
106
+ const indexes = (builder.indexes ?? []).map((index) => {
107
+ return { fields: index.fields, name: index.name, ...index.unique ? { unique: true } : {} };
108
+ });
109
+ warnDroppedTableFeatures(builder, bareName);
110
+ return {
111
+ ...builder.isExternallyManaged ? { externallyManaged: true } : {},
112
+ indexes,
113
+ name: bareName,
114
+ rankIndexes: [],
115
+ relations: [],
116
+ searchIndexes: (builder.searchIndexes ?? []).map((index) => {
117
+ return {
118
+ field: index.field,
119
+ ...index.filterFields ? { filterFields: index.filterFields } : {},
120
+ name: index.name
121
+ };
122
+ }),
123
+ shape: Object.fromEntries(Object.entries(shape).map(([name, validator]) => [name, runtimeValidatorToIR(validator)])),
124
+ shardMode: shardModeToIR(builder.shardMode),
125
+ // Inline vector/rank indexes and relations are not yet introspected from a
126
+ // package extension; their presence is surfaced via `warnDroppedTableFeatures`.
127
+ vectorIndexes: []
128
+ };
129
+ };
130
+ const resolvedExtensionToIR = (value) => {
131
+ const { key, tables } = value;
132
+ if (typeof key !== "string" || typeof tables !== "object" || tables === null) {
133
+ return void 0;
134
+ }
135
+ const bareTables = Object.entries(tables).map(([bareName, builder]) => runtimeTableToIR(builder, bareName));
136
+ const vectorIndexes = value["vectorIndexes"] ?? {};
137
+ const bareVectorIndexes = Object.entries(vectorIndexes ?? {}).map(([name, index]) => {
138
+ return {
139
+ ...index.dimensions === void 0 ? {} : { dimensions: index.dimensions },
140
+ ...index.field === void 0 ? {} : { field: index.field },
141
+ ...index.metadata === void 0 ? {} : { metadata: index.metadata },
142
+ ...index.metric === void 0 ? {} : { metric: index.metric },
143
+ name,
144
+ table: index.table ?? ""
145
+ };
146
+ });
147
+ return { bareTables, bareVectorIndexes, key };
148
+ };
149
+ const receiverIdentifierText = (argument) => {
150
+ if (Node.isIdentifier(argument)) {
151
+ return argument.getText();
152
+ }
153
+ if (Node.isPropertyAccessExpression(argument)) {
154
+ const receiver = argument.getExpression();
155
+ return Node.isIdentifier(receiver) ? receiver.getText() : void 0;
156
+ }
157
+ return void 0;
158
+ };
159
+ const accessPathOf = (argument) => {
160
+ const receiverName = receiverIdentifierText(argument);
161
+ if (receiverName === void 0) {
162
+ return void 0;
163
+ }
164
+ const property = Node.isPropertyAccessExpression(argument) ? argument.getName() : void 0;
165
+ const propertyPath = property === void 0 ? [] : [property];
166
+ for (const declaration of argument.getSourceFile().getImportDeclarations()) {
167
+ const moduleSpecifier = declaration.getModuleSpecifierValue();
168
+ for (const named of declaration.getNamedImports()) {
169
+ const localName = named.getAliasNode()?.getText() ?? named.getName();
170
+ if (localName === receiverName) {
171
+ return { importedName: named.getName(), moduleSpecifier, propertyPath };
172
+ }
173
+ }
174
+ if (declaration.getDefaultImport()?.getText() === receiverName) {
175
+ return { importedName: "default", moduleSpecifier, propertyPath };
176
+ }
177
+ if (declaration.getNamespaceImport()?.getText() === receiverName && property !== void 0) {
178
+ return { importedName: property, moduleSpecifier, propertyPath: [] };
179
+ }
180
+ }
181
+ return void 0;
182
+ };
183
+ const readExtensionValue = (module_, access) => {
184
+ let current = module_[access.importedName];
185
+ for (const segment of access.propertyPath) {
186
+ if (typeof current !== "object" || current === null) {
187
+ return void 0;
188
+ }
189
+ current = current[segment];
190
+ }
191
+ return current;
192
+ };
193
+ const resolvePackageExtension = (argument, projectRoot) => {
194
+ const access = accessPathOf(argument);
195
+ if (!access) {
196
+ return void 0;
197
+ }
198
+ try {
199
+ const projectRequire = createRequire(join(projectRoot, "noop.cjs"));
200
+ const resolved = projectRequire.resolve(access.moduleSpecifier);
201
+ const loadedModule = projectRequire(resolved);
202
+ const value = readExtensionValue(loadedModule, access);
203
+ if (typeof value !== "object" || value === null) {
204
+ return void 0;
205
+ }
206
+ return resolvedExtensionToIR(value);
207
+ } catch {
208
+ return void 0;
209
+ }
210
+ };
4
211
 
5
212
  const VECTOR_METRICS = /* @__PURE__ */ new Set(["cosine", "dot-product", "euclidean"]);
6
213
  const ON_DELETE_ACTIONS = /* @__PURE__ */ new Set(["cascade", "restrict", "set null"]);
@@ -179,6 +386,54 @@ const parseGlobalBackend = (args) => {
179
386
  }
180
387
  return "d1";
181
388
  };
389
+ const softDeleteFieldOf = (optionsArgument) => {
390
+ if (optionsArgument && Node.isObjectLiteralExpression(optionsArgument)) {
391
+ const fieldProperty = optionsArgument.getProperty("field");
392
+ if (fieldProperty && Node.isPropertyAssignment(fieldProperty)) {
393
+ const initializer = fieldProperty.getInitializer();
394
+ if (initializer && Node.isStringLiteral(initializer)) {
395
+ return initializer.getLiteralText();
396
+ }
397
+ }
398
+ }
399
+ return "deletedAt";
400
+ };
401
+ const stringPropertyOf = (object, property) => {
402
+ const node = object.getProperty(property);
403
+ if (node && Node.isPropertyAssignment(node)) {
404
+ const initializer = node.getInitializer();
405
+ if (initializer && Node.isStringLiteral(initializer)) {
406
+ return initializer.getLiteralText();
407
+ }
408
+ }
409
+ return void 0;
410
+ };
411
+ const stringArrayPropertyOf = (object, property) => {
412
+ const node = object.getProperty(property);
413
+ if (node && Node.isPropertyAssignment(node)) {
414
+ const initializer = node.getInitializer();
415
+ if (initializer && Node.isArrayLiteralExpression(initializer)) {
416
+ const items = initializer.getElements().filter((element) => Node.isStringLiteral(element)).map((element) => element.getLiteralText());
417
+ return items.length > 0 ? items : void 0;
418
+ }
419
+ }
420
+ return void 0;
421
+ };
422
+ const parseSourceCall = (args) => {
423
+ const first = args[0];
424
+ if (!first || !Node.isObjectLiteralExpression(first)) {
425
+ return { binding: "", hasTenantBy: false, unanalyzable: true };
426
+ }
427
+ return {
428
+ binding: stringPropertyOf(first, "binding") ?? "",
429
+ columns: stringArrayPropertyOf(first, "columns"),
430
+ hasReconcile: first.getProperty("reconcileEveryMs") !== void 0,
431
+ hasTenantBy: first.getProperty("tenantBy") !== void 0,
432
+ idColumn: stringPropertyOf(first, "idColumn"),
433
+ mode: stringPropertyOf(first, "mode"),
434
+ query: stringPropertyOf(first, "query")
435
+ };
436
+ };
182
437
  const applyTableMethod = (accumulator, method, args, name) => {
183
438
  switch (method) {
184
439
  case "externallyManaged": {
@@ -194,6 +449,10 @@ const applyTableMethod = (accumulator, method, args, name) => {
194
449
  accumulator.indexes.push(parseIndexCall(args));
195
450
  break;
196
451
  }
452
+ case "public": {
453
+ accumulator.isPublic = true;
454
+ break;
455
+ }
197
456
  case "rankIndex": {
198
457
  accumulator.rankIndexes.push(parseRankIndexCall(args));
199
458
  break;
@@ -214,6 +473,15 @@ const applyTableMethod = (accumulator, method, args, name) => {
214
473
  accumulator.shardMode = { field: field && Node.isStringLiteral(field) ? field.getLiteralText() : "_unknown_", kind: "shardBy" };
215
474
  break;
216
475
  }
476
+ case "softDelete": {
477
+ accumulator.softDelete = { field: softDeleteFieldOf(args[0]) };
478
+ break;
479
+ }
480
+ case "source": {
481
+ accumulator.externalSource = parseSourceCall(args);
482
+ accumulator.externallyManaged = true;
483
+ break;
484
+ }
217
485
  case "vectorize": {
218
486
  const vectorIndex = parseVectorizeCall(args, name);
219
487
  if (vectorIndex) {
@@ -227,6 +495,7 @@ const parseTableBuilder = (expression, name) => {
227
495
  const accumulator = {
228
496
  externallyManaged: false,
229
497
  indexes: [],
498
+ isPublic: false,
230
499
  rankIndexes: [],
231
500
  relations: [],
232
501
  searchIndexes: [],
@@ -251,16 +520,22 @@ const parseTableBuilder = (expression, name) => {
251
520
  break;
252
521
  }
253
522
  }
523
+ if (accumulator.softDelete && !(accumulator.softDelete.field in shape)) {
524
+ shape = { ...shape, [accumulator.softDelete.field]: { inner: { kind: "number" }, kind: "optional" } };
525
+ }
254
526
  return {
255
527
  externallyManaged: accumulator.externallyManaged,
528
+ externalSource: accumulator.externalSource,
256
529
  globalBackend: accumulator.shardMode === "global" ? accumulator.globalBackend ?? "d1" : void 0,
257
530
  indexes: accumulator.indexes,
531
+ isPublic: accumulator.isPublic,
258
532
  name,
259
533
  rankIndexes: accumulator.rankIndexes,
260
534
  relations: accumulator.relations,
261
535
  searchIndexes: accumulator.searchIndexes,
262
536
  shape,
263
537
  shardMode: accumulator.shardMode,
538
+ softDelete: accumulator.softDelete,
264
539
  vectorIndexes: accumulator.vectorIndexes
265
540
  };
266
541
  };
@@ -354,7 +629,27 @@ const extensionTargetIdentifier = (argument) => {
354
629
  return argument;
355
630
  }
356
631
  if (Node.isPropertyAccessExpression(argument)) {
357
- return argument.getNameNode();
632
+ const receiver = argument.getExpression();
633
+ return Node.isIdentifier(receiver) ? receiver : void 0;
634
+ }
635
+ return void 0;
636
+ };
637
+ const pluginConfigObject = (expression) => {
638
+ if (Node.isObjectLiteralExpression(expression)) {
639
+ return expression;
640
+ }
641
+ if (Node.isCallExpression(expression)) {
642
+ const callee = expression.getExpression();
643
+ let name;
644
+ if (Node.isIdentifier(callee)) {
645
+ name = callee.getText();
646
+ } else if (Node.isPropertyAccessExpression(callee)) {
647
+ name = callee.getName();
648
+ }
649
+ if (name === "definePlugin") {
650
+ const configArgument = expression.getArguments()[1];
651
+ return configArgument && Node.isObjectLiteralExpression(configArgument) ? configArgument : void 0;
652
+ }
358
653
  }
359
654
  return void 0;
360
655
  };
@@ -363,8 +658,9 @@ const nextExpressionFromDeclaration = (declaration, argument) => {
363
658
  if (!initializer) {
364
659
  return void 0;
365
660
  }
366
- if (Node.isPropertyAccessExpression(argument) && Node.isObjectLiteralExpression(initializer)) {
367
- return objectPropertyInitializer(initializer, argument.getName());
661
+ if (Node.isPropertyAccessExpression(argument)) {
662
+ const configObject = pluginConfigObject(initializer);
663
+ return configObject ? objectPropertyInitializer(configObject, argument.getName()) : void 0;
368
664
  }
369
665
  return initializer;
370
666
  };
@@ -434,24 +730,30 @@ const parseExtensionVectorIndexes = (options) => {
434
730
  }
435
731
  return parseStandaloneVectorIndexes(object);
436
732
  };
437
- const mergeExtension = (key, options) => {
438
- const bareTables = parseExtensionTables(options);
733
+ const namespaceExtension = (key, bareTables, bareVectorIndexes) => {
439
734
  const bareNames = new Set(bareTables.map((table) => table.name));
440
735
  const tables = bareTables.map((table) => namespaceExtensionTable(table, key, bareNames));
441
- const vectorIndexes = parseExtensionVectorIndexes(options).map((index) => {
736
+ const vectorIndexes = bareVectorIndexes.map((index) => {
442
737
  return { ...index, name: prefixTableName(key, index.name), table: rewriteReference(index.table, key, bareNames) };
443
738
  });
444
739
  return { tables, vectorIndexes };
445
740
  };
446
- const mergeExtendCall = (extendCall) => {
741
+ const mergeExtension = (key, options) => namespaceExtension(key, parseExtensionTables(options), parseExtensionVectorIndexes(options));
742
+ const mergeExtendCall = (extendCall, projectRoot) => {
447
743
  const extendArgument = extendCall.getArguments()[0];
448
744
  if (!extendArgument) {
449
745
  return void 0;
450
746
  }
451
747
  const resolved = resolveSchemaExtensionCall(extendArgument);
452
748
  if (!resolved) {
749
+ if (projectRoot !== void 0) {
750
+ const fromPackage = resolvePackageExtension(extendArgument, projectRoot);
751
+ if (fromPackage) {
752
+ return namespaceExtension(fromPackage.key, fromPackage.bareTables, fromPackage.bareVectorIndexes);
753
+ }
754
+ }
453
755
  console.warn(
454
- `@lunora/codegen: skipping \`.extend(${extendArgument.getText()})\` — its \`defineSchemaExtension(...)\` definition could not be resolved from local sources (cross-package node_modules/.d.ts resolution is a deferred phase). Extension tables will be absent from the generated types.`
756
+ `@lunora/codegen: skipping \`.extend(${extendArgument.getText()})\` — its \`defineSchemaExtension(...)\` could not be resolved from local sources, and ${projectRoot === void 0 ? "no project root was available to resolve the package" : "the package could not be imported/introspected"}. Extension tables will be absent from the generated types.`
455
757
  );
456
758
  return void 0;
457
759
  }
@@ -481,6 +783,36 @@ const extendCallsOf = (defineSchemaCall) => {
481
783
  }
482
784
  return calls;
483
785
  };
786
+ const chainedStringLiteralArgument = (defineSchemaCall, methodName, noun, allowed, expected) => {
787
+ let current = defineSchemaCall;
788
+ for (; ; ) {
789
+ const parent = current.getParent();
790
+ if (!parent || !Node.isPropertyAccessExpression(parent)) {
791
+ break;
792
+ }
793
+ const callParent = parent.getParent();
794
+ if (!callParent || !Node.isCallExpression(callParent)) {
795
+ break;
796
+ }
797
+ if (parent.getName() === methodName) {
798
+ const argument = callParent.getArguments()[0];
799
+ if (!argument || !Node.isStringLiteral(argument)) {
800
+ throw diagnosticAt(callParent, `\`.${methodName}(...)\` expects a string literal (${expected})`);
801
+ }
802
+ const value = argument.getLiteralText();
803
+ if (!allowed.has(value)) {
804
+ throw diagnosticAt(argument, `unknown ${noun} ${JSON.stringify(value)} — expected ${expected}`);
805
+ }
806
+ return value;
807
+ }
808
+ current = callParent;
809
+ }
810
+ return void 0;
811
+ };
812
+ const JURISDICTIONS = /* @__PURE__ */ new Set(["eu", "fedramp", "us"]);
813
+ const jurisdictionOf = (defineSchemaCall) => chainedStringLiteralArgument(defineSchemaCall, "jurisdiction", "jurisdiction", JURISDICTIONS, '"eu", "us", or "fedramp"');
814
+ const RLS_MODES = /* @__PURE__ */ new Set(["required"]);
815
+ const rlsModeOf = (defineSchemaCall) => chainedStringLiteralArgument(defineSchemaCall, "rls", "rls mode", RLS_MODES, '"required"');
484
816
  const parseBaseTables = (object) => {
485
817
  const tables = [];
486
818
  for (const property of object.getProperties()) {
@@ -496,11 +828,11 @@ const parseBaseTables = (object) => {
496
828
  }
497
829
  return tables;
498
830
  };
499
- const applyExtensions = (defineSchemaCall, tables) => {
831
+ const applyExtensions = (defineSchemaCall, tables, projectRoot) => {
500
832
  const existingTableNames = new Set(tables.map((table) => table.name));
501
833
  const vectorIndexes = [];
502
834
  for (const extendCall of extendCallsOf(defineSchemaCall)) {
503
- const merged = mergeExtendCall(extendCall);
835
+ const merged = mergeExtendCall(extendCall, projectRoot);
504
836
  if (!merged) {
505
837
  continue;
506
838
  }
@@ -518,14 +850,14 @@ const applyExtensions = (defineSchemaCall, tables) => {
518
850
  }
519
851
  return vectorIndexes;
520
852
  };
521
- const discoverSchema = (project, schemaPath) => {
853
+ const discoverSchema = (project, schemaPath, projectRoot) => {
522
854
  const file = project.addSourceFileAtPath(schemaPath);
523
855
  const defineSchemaCall = file.getDescendantsOfKind(SyntaxKind.CallExpression).find((call) => {
524
856
  const callee = call.getExpression();
525
857
  return Node.isIdentifier(callee) && callee.getText() === "defineSchema";
526
858
  });
527
859
  if (!defineSchemaCall) {
528
- throw new Error(`defineSchema() not found in ${schemaPath}`);
860
+ throw new LunoraError("INTERNAL", `defineSchema() not found in ${schemaPath}`);
529
861
  }
530
862
  const argument = defineSchemaCall.getArguments()[0];
531
863
  if (!argument || !Node.isObjectLiteralExpression(argument)) {
@@ -534,9 +866,9 @@ const discoverSchema = (project, schemaPath) => {
534
866
  const tables = parseBaseTables(argument);
535
867
  const standaloneArgument = defineSchemaCall.getArguments()[1];
536
868
  const standaloneVectorIndexes = standaloneArgument && Node.isObjectLiteralExpression(standaloneArgument) ? parseStandaloneVectorIndexes(standaloneArgument) : [];
537
- const extensionStandaloneVectorIndexes = applyExtensions(defineSchemaCall, tables);
869
+ const extensionStandaloneVectorIndexes = applyExtensions(defineSchemaCall, tables, projectRoot);
538
870
  const vectorIndexes = [...tables.flatMap((table) => table.vectorIndexes), ...standaloneVectorIndexes, ...extensionStandaloneVectorIndexes];
539
- return { tables, vectorIndexes };
871
+ return { jurisdiction: jurisdictionOf(defineSchemaCall), rlsMode: rlsModeOf(defineSchemaCall), tables, vectorIndexes };
540
872
  };
541
873
 
542
874
  export { discoverSchema as default };
@@ -1,5 +1,5 @@
1
1
  import { Node } from 'ts-morph';
2
- import { listLunoraSourceFiles, lunoraRelativePath, classifyProcedureCall } from './discoverFunctions-DEgAcRuD.mjs';
2
+ import { listLunoraSourceFiles, lunoraRelativePath, classifyProcedureCall } from './discoverFunctions-CZ91aenA.mjs';
3
3
 
4
4
  const STORAGE_OPERATIONS = /* @__PURE__ */ new Set(["delete", "list", "read", "write"]);
5
5
  const isStorageRulesCall = (node) => {