@lunora/codegen 1.0.0-alpha.5 → 1.0.0-alpha.7

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
@@ -855,7 +855,7 @@ declare const discoverRlsMetadata: (project: Project, lunoraDirectory: string) =
855
855
  * Load `<projectRoot>/lunora/schema.ts`, find `defineSchema({...})`, and
856
856
  * return a structural IR. Throws if the file or call cannot be found.
857
857
  */
858
- declare const discoverSchema: (project: Project, schemaPath: string) => SchemaIR;
858
+ declare const discoverSchema: (project: Project, schemaPath: string, projectRoot?: string) => SchemaIR;
859
859
  /**
860
860
  * Aggregate the schema-wide storage-rule metadata the studio's inspector reads:
861
861
  * every statically-discovered `(bucket, on, prefix, procedure)` entry across all
package/dist/index.d.ts CHANGED
@@ -855,7 +855,7 @@ declare const discoverRlsMetadata: (project: Project, lunoraDirectory: string) =
855
855
  * Load `<projectRoot>/lunora/schema.ts`, find `defineSchema({...})`, and
856
856
  * return a structural IR. Throws if the file or call cannot be found.
857
857
  */
858
- declare const discoverSchema: (project: Project, schemaPath: string) => SchemaIR;
858
+ declare const discoverSchema: (project: Project, schemaPath: string, projectRoot?: string) => SchemaIR;
859
859
  /**
860
860
  * Aggregate the schema-wide storage-rule metadata the studio's inspector reads:
861
861
  * every statically-discovered `(bucket, on, prefix, procedure)` entry across all
package/dist/index.mjs CHANGED
@@ -5,21 +5,21 @@ export { CONTAINERS_FILENAME, discoverContainers } from './packem_shared/CONTAIN
5
5
  export { default as discoverCrons } from './packem_shared/discoverCrons-BL6iGuJ3.mjs';
6
6
  export { discoverFunctions } from './packem_shared/discoverFunctions-DEgAcRuD.mjs';
7
7
  export { default as discoverHttpRoutes } from './packem_shared/discoverHttpRoutes-C978pBiG.mjs';
8
- export { default as discoverInserts } from './packem_shared/discoverInserts-CRQdXvHO.mjs';
8
+ export { default as discoverInserts } from './packem_shared/discoverInserts-pLBFsSAV.mjs';
9
9
  export { default as discoverMaskProcedures } from './packem_shared/discoverMaskProcedures-B64zA740.mjs';
10
10
  export { default as discoverMigrations } from './packem_shared/discoverMigrations-Doj_-BAA.mjs';
11
11
  export { default as discoverNondeterministicCalls } from './packem_shared/discoverNondeterministicCalls-4KiPQxQU.mjs';
12
12
  export { default as discoverQueries } from './packem_shared/discoverQueries-BkIi0dBD.mjs';
13
13
  export { default as discoverR2sqlCalls } from './packem_shared/discoverR2sqlCalls-BpDqvcUn.mjs';
14
14
  export { discoverRlsMetadata, default as discoverRlsProcedures } from './packem_shared/discoverRlsMetadata-DpRB1HMe.mjs';
15
- export { default as discoverSchema } from './packem_shared/discoverSchema-DB_QrIQe.mjs';
15
+ export { default as discoverSchema } from './packem_shared/discoverSchema-DYl0QfDH.mjs';
16
16
  export { default as discoverStorageRulesMetadata } from './packem_shared/discoverStorageRulesMetadata-DAqJUxUv.mjs';
17
17
  export { WORKFLOWS_FILENAME, discoverWorkflows } from './packem_shared/WORKFLOWS_FILENAME-DRDQdhfq.mjs';
18
18
  export { GENERATED_HEADER, emitApi, emitContainers, emitCrons, emitDataModel, emitDrizzleSchema, emitFunctions, emitServer, emitShard, emitVectors, emitWorkflows, emitWranglerCronTriggers } from './packem_shared/GENERATED_HEADER-DF1hQcix.mjs';
19
19
  export { emitApp } from './packem_shared/emitApp-Ci_hcJNO.mjs';
20
20
  export { buildOpenApiDocument, emitOpenApi, emitOpenApiModule } from './packem_shared/buildOpenApiDocument-Cns1EkCQ.mjs';
21
21
  export { OPENRPC_VERSION, buildOpenRpcDocument, emitOpenRpc, emitOpenRpcModule } from './packem_shared/OPENRPC_VERSION-C7zKVeKi.mjs';
22
- export { SCHEMA_SNAPSHOT_FILENAME, createCodegenProject, refreshCodegenProject, runCodegen } from './packem_shared/SCHEMA_SNAPSHOT_FILENAME-BqOtU2lC.mjs';
22
+ export { SCHEMA_SNAPSHOT_FILENAME, createCodegenProject, refreshCodegenProject, runCodegen } from './packem_shared/SCHEMA_SNAPSHOT_FILENAME-g7kpX8hu.mjs';
23
23
  export { SCHEMA_SNAPSHOT_VERSION, SchemaSnapshotParseError, buildSchemaSnapshot, diffSchemaSnapshots, evaluateSchemaDrift, parseSchemaSnapshot, serializeSchemaSnapshot } from './packem_shared/SCHEMA_SNAPSHOT_VERSION-DzLDbWk3.mjs';
24
24
  export { schemaFromIr } from './packem_shared/schemaFromIr-DTYsLBaA.mjs';
25
25
  export { LUNORA_ERROR_CODES, validatorIrToJsonSchema } from './packem_shared/LUNORA_ERROR_CODES-CySpQPD3.mjs';
@@ -7,14 +7,14 @@ import discoverAuthApiCalls from './discoverAuthApiCalls-C35R6z0T.mjs';
7
7
  import { discoverContainers } from './CONTAINERS_FILENAME-0K-pjNb8.mjs';
8
8
  import discoverCrons from './discoverCrons-BL6iGuJ3.mjs';
9
9
  import discoverHttpRoutes from './discoverHttpRoutes-C978pBiG.mjs';
10
- import discoverInserts from './discoverInserts-CRQdXvHO.mjs';
10
+ import discoverInserts from './discoverInserts-pLBFsSAV.mjs';
11
11
  import discoverMaskProcedures, { discoverMaskMetadata } from './discoverMaskProcedures-B64zA740.mjs';
12
12
  import discoverMigrations from './discoverMigrations-Doj_-BAA.mjs';
13
13
  import discoverNondeterministicCalls from './discoverNondeterministicCalls-4KiPQxQU.mjs';
14
14
  import discoverQueries from './discoverQueries-BkIi0dBD.mjs';
15
15
  import discoverR2sqlCalls from './discoverR2sqlCalls-BpDqvcUn.mjs';
16
16
  import discoverRlsProcedures, { discoverRlsMetadata } from './discoverRlsMetadata-DpRB1HMe.mjs';
17
- import discoverSchema from './discoverSchema-DB_QrIQe.mjs';
17
+ import discoverSchema from './discoverSchema-DYl0QfDH.mjs';
18
18
  import discoverStorageRulesMetadata from './discoverStorageRulesMetadata-DAqJUxUv.mjs';
19
19
  import { e as enclosingExportName$1 } from './discover-ast-CT6BgBr4.mjs';
20
20
  import { discoverWorkflows } from './WORKFLOWS_FILENAME-DRDQdhfq.mjs';
@@ -723,7 +723,7 @@ const runCodegen = (options) => {
723
723
  throw new Error(`schema.ts not found at ${schemaPath}`);
724
724
  }
725
725
  const project = options.project ?? createCodegenProject(lunoraDirectory);
726
- const schema = discoverSchema(project, schemaPath);
726
+ const schema = discoverSchema(project, schemaPath, options.projectRoot);
727
727
  const functions = discoverFunctions(project, lunoraDirectory);
728
728
  const httpRoutes = discoverHttpRoutes(project, lunoraDirectory);
729
729
  const migrations = discoverMigrations(project, lunoraDirectory);
@@ -13,9 +13,31 @@ const isDatabaseInsertCall = (call) => {
13
13
  }
14
14
  return Node.isIdentifier(receiver) && receiver.getText() === "db";
15
15
  };
16
+ const resolveStringConst = (identifier) => {
17
+ if (!Node.isIdentifier(identifier)) {
18
+ return void 0;
19
+ }
20
+ const symbol = identifier.getSymbol();
21
+ const declarations = symbol?.getAliasedSymbol()?.getDeclarations() ?? symbol?.getDeclarations() ?? [];
22
+ for (const declaration of declarations) {
23
+ if (Node.isVariableDeclaration(declaration)) {
24
+ const initializer = declaration.getInitializer();
25
+ if (initializer && Node.isStringLiteral(initializer)) {
26
+ return initializer.getLiteralText();
27
+ }
28
+ }
29
+ }
30
+ return void 0;
31
+ };
16
32
  const tableOf = (call) => {
17
33
  const argument = call.getArguments()[0];
18
- return argument && Node.isStringLiteral(argument) ? argument.getLiteralText() : "";
34
+ if (!argument) {
35
+ return "";
36
+ }
37
+ if (Node.isStringLiteral(argument)) {
38
+ return argument.getLiteralText();
39
+ }
40
+ return resolveStringConst(argument) ?? "";
19
41
  };
20
42
  const discoverInserts = (project, lunoraDirectory) => {
21
43
  const writes = [];
@@ -1,6 +1,212 @@
1
- import { SyntaxKind, Node } from 'ts-morph';
1
+ import { Node, SyntaxKind } from 'ts-morph';
2
2
  import { diagnosticAt } from './CodegenDiagnosticError-54jWDxA9.mjs';
3
3
  import { a as parseObjectShape } from './parse-validator-tuQtHrsr.mjs';
4
+ import { createRequire } from 'node:module';
5
+ import { join } from 'node:path';
6
+
7
+ const renderLiteralValue = (value) => {
8
+ switch (typeof value) {
9
+ case "bigint": {
10
+ return value.toString();
11
+ }
12
+ case "boolean":
13
+ case "number": {
14
+ return String(value);
15
+ }
16
+ case "string": {
17
+ return JSON.stringify(value);
18
+ }
19
+ default: {
20
+ return value === null ? "null" : void 0;
21
+ }
22
+ }
23
+ };
24
+ const columnMetaToIR = (column) => {
25
+ const hasDefault = column?.["defaultValue"] !== void 0 || column?.["defaultFn"] !== void 0 || column?.["serverDefault"] !== void 0;
26
+ return {
27
+ ...hasDefault ? { hasDefault: true } : {},
28
+ ...column?.["onUpdateFn"] === void 0 ? {} : { hasOnUpdate: true },
29
+ notNull: column?.["notNull"] ?? true,
30
+ ...column?.["unique"] === true ? { unique: true } : {}
31
+ };
32
+ };
33
+ const runtimeValidatorToIR = (validator) => {
34
+ const meta = validator?._meta ?? {};
35
+ const kind = validator?.kind ?? "unknown";
36
+ const ir = { column: columnMetaToIR(meta["column"]), kind };
37
+ switch (kind) {
38
+ case "array":
39
+ case "optional": {
40
+ ir.inner = runtimeValidatorToIR(meta["inner"]);
41
+ break;
42
+ }
43
+ case "id": {
44
+ ir.tableName = meta["tableName"];
45
+ break;
46
+ }
47
+ case "literal": {
48
+ ir.literalValue = renderLiteralValue(meta["value"]);
49
+ break;
50
+ }
51
+ case "object": {
52
+ const shape = meta["shape"] ?? {};
53
+ ir.shape = Object.fromEntries(Object.entries(shape).map(([name, child]) => [name, runtimeValidatorToIR(child)]));
54
+ break;
55
+ }
56
+ case "record": {
57
+ ir.valueType = runtimeValidatorToIR(meta["valueValidator"]);
58
+ if (meta["keyValidator"] !== void 0) {
59
+ ir.keyType = runtimeValidatorToIR(meta["keyValidator"]);
60
+ }
61
+ break;
62
+ }
63
+ case "storage": {
64
+ if (typeof meta["bucket"] === "string") {
65
+ ir.bucket = meta["bucket"];
66
+ }
67
+ break;
68
+ }
69
+ case "union": {
70
+ const members = meta["members"] ?? [];
71
+ ir.members = members.map((member) => runtimeValidatorToIR(member));
72
+ break;
73
+ }
74
+ }
75
+ return ir;
76
+ };
77
+ const shardModeToIR = (shardMode) => {
78
+ if (shardMode?.kind === "global") {
79
+ return "global";
80
+ }
81
+ if (shardMode?.kind === "shardBy" && typeof shardMode.field === "string") {
82
+ return { field: shardMode.field, kind: "shardBy" };
83
+ }
84
+ return "root";
85
+ };
86
+ const warnDroppedTableFeatures = (builder, bareName) => {
87
+ const dropped = [];
88
+ if (builder.relationMap && Object.keys(builder.relationMap).length > 0) {
89
+ dropped.push("relations");
90
+ }
91
+ if (builder.rankIndexes && builder.rankIndexes.length > 0) {
92
+ dropped.push("rank indexes");
93
+ }
94
+ if (builder.vectorIndexes && builder.vectorIndexes.length > 0) {
95
+ dropped.push("vector indexes");
96
+ }
97
+ if (dropped.length > 0) {
98
+ console.warn(
99
+ `@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.`
100
+ );
101
+ }
102
+ };
103
+ const runtimeTableToIR = (builder, bareName) => {
104
+ const shape = builder.shape ?? {};
105
+ const indexes = (builder.indexes ?? []).map((index) => {
106
+ return { fields: index.fields, name: index.name, ...index.unique ? { unique: true } : {} };
107
+ });
108
+ warnDroppedTableFeatures(builder, bareName);
109
+ return {
110
+ ...builder.isExternallyManaged ? { externallyManaged: true } : {},
111
+ indexes,
112
+ name: bareName,
113
+ rankIndexes: [],
114
+ relations: [],
115
+ searchIndexes: (builder.searchIndexes ?? []).map((index) => {
116
+ return {
117
+ field: index.field,
118
+ ...index.filterFields ? { filterFields: index.filterFields } : {},
119
+ name: index.name
120
+ };
121
+ }),
122
+ shape: Object.fromEntries(Object.entries(shape).map(([name, validator]) => [name, runtimeValidatorToIR(validator)])),
123
+ shardMode: shardModeToIR(builder.shardMode),
124
+ // Inline vector/rank indexes and relations are not yet introspected from a
125
+ // package extension; their presence is surfaced via `warnDroppedTableFeatures`.
126
+ vectorIndexes: []
127
+ };
128
+ };
129
+ const resolvedExtensionToIR = (value) => {
130
+ const { key, tables } = value;
131
+ if (typeof key !== "string" || typeof tables !== "object" || tables === null) {
132
+ return void 0;
133
+ }
134
+ const bareTables = Object.entries(tables).map(([bareName, builder]) => runtimeTableToIR(builder, bareName));
135
+ const vectorIndexes = value["vectorIndexes"] ?? {};
136
+ const bareVectorIndexes = Object.entries(vectorIndexes ?? {}).map(([name, index]) => {
137
+ return {
138
+ ...index.dimensions === void 0 ? {} : { dimensions: index.dimensions },
139
+ ...index.field === void 0 ? {} : { field: index.field },
140
+ ...index.metadata === void 0 ? {} : { metadata: index.metadata },
141
+ ...index.metric === void 0 ? {} : { metric: index.metric },
142
+ name,
143
+ table: index.table ?? ""
144
+ };
145
+ });
146
+ return { bareTables, bareVectorIndexes, key };
147
+ };
148
+ const receiverIdentifierText = (argument) => {
149
+ if (Node.isIdentifier(argument)) {
150
+ return argument.getText();
151
+ }
152
+ if (Node.isPropertyAccessExpression(argument)) {
153
+ const receiver = argument.getExpression();
154
+ return Node.isIdentifier(receiver) ? receiver.getText() : void 0;
155
+ }
156
+ return void 0;
157
+ };
158
+ const accessPathOf = (argument) => {
159
+ const receiverName = receiverIdentifierText(argument);
160
+ if (receiverName === void 0) {
161
+ return void 0;
162
+ }
163
+ const property = Node.isPropertyAccessExpression(argument) ? argument.getName() : void 0;
164
+ const propertyPath = property === void 0 ? [] : [property];
165
+ for (const declaration of argument.getSourceFile().getImportDeclarations()) {
166
+ const moduleSpecifier = declaration.getModuleSpecifierValue();
167
+ for (const named of declaration.getNamedImports()) {
168
+ const localName = named.getAliasNode()?.getText() ?? named.getName();
169
+ if (localName === receiverName) {
170
+ return { importedName: named.getName(), moduleSpecifier, propertyPath };
171
+ }
172
+ }
173
+ if (declaration.getDefaultImport()?.getText() === receiverName) {
174
+ return { importedName: "default", moduleSpecifier, propertyPath };
175
+ }
176
+ if (declaration.getNamespaceImport()?.getText() === receiverName && property !== void 0) {
177
+ return { importedName: property, moduleSpecifier, propertyPath: [] };
178
+ }
179
+ }
180
+ return void 0;
181
+ };
182
+ const readExtensionValue = (module_, access) => {
183
+ let current = module_[access.importedName];
184
+ for (const segment of access.propertyPath) {
185
+ if (typeof current !== "object" || current === null) {
186
+ return void 0;
187
+ }
188
+ current = current[segment];
189
+ }
190
+ return current;
191
+ };
192
+ const resolvePackageExtension = (argument, projectRoot) => {
193
+ const access = accessPathOf(argument);
194
+ if (!access) {
195
+ return void 0;
196
+ }
197
+ try {
198
+ const projectRequire = createRequire(join(projectRoot, "noop.cjs"));
199
+ const resolved = projectRequire.resolve(access.moduleSpecifier);
200
+ const loadedModule = projectRequire(resolved);
201
+ const value = readExtensionValue(loadedModule, access);
202
+ if (typeof value !== "object" || value === null) {
203
+ return void 0;
204
+ }
205
+ return resolvedExtensionToIR(value);
206
+ } catch {
207
+ return void 0;
208
+ }
209
+ };
4
210
 
5
211
  const VECTOR_METRICS = /* @__PURE__ */ new Set(["cosine", "dot-product", "euclidean"]);
6
212
  const ON_DELETE_ACTIONS = /* @__PURE__ */ new Set(["cascade", "restrict", "set null"]);
@@ -455,24 +661,30 @@ const parseExtensionVectorIndexes = (options) => {
455
661
  }
456
662
  return parseStandaloneVectorIndexes(object);
457
663
  };
458
- const mergeExtension = (key, options) => {
459
- const bareTables = parseExtensionTables(options);
664
+ const namespaceExtension = (key, bareTables, bareVectorIndexes) => {
460
665
  const bareNames = new Set(bareTables.map((table) => table.name));
461
666
  const tables = bareTables.map((table) => namespaceExtensionTable(table, key, bareNames));
462
- const vectorIndexes = parseExtensionVectorIndexes(options).map((index) => {
667
+ const vectorIndexes = bareVectorIndexes.map((index) => {
463
668
  return { ...index, name: prefixTableName(key, index.name), table: rewriteReference(index.table, key, bareNames) };
464
669
  });
465
670
  return { tables, vectorIndexes };
466
671
  };
467
- const mergeExtendCall = (extendCall) => {
672
+ const mergeExtension = (key, options) => namespaceExtension(key, parseExtensionTables(options), parseExtensionVectorIndexes(options));
673
+ const mergeExtendCall = (extendCall, projectRoot) => {
468
674
  const extendArgument = extendCall.getArguments()[0];
469
675
  if (!extendArgument) {
470
676
  return void 0;
471
677
  }
472
678
  const resolved = resolveSchemaExtensionCall(extendArgument);
473
679
  if (!resolved) {
680
+ if (projectRoot !== void 0) {
681
+ const fromPackage = resolvePackageExtension(extendArgument, projectRoot);
682
+ if (fromPackage) {
683
+ return namespaceExtension(fromPackage.key, fromPackage.bareTables, fromPackage.bareVectorIndexes);
684
+ }
685
+ }
474
686
  console.warn(
475
- `@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.`
687
+ `@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.`
476
688
  );
477
689
  return void 0;
478
690
  }
@@ -517,11 +729,11 @@ const parseBaseTables = (object) => {
517
729
  }
518
730
  return tables;
519
731
  };
520
- const applyExtensions = (defineSchemaCall, tables) => {
732
+ const applyExtensions = (defineSchemaCall, tables, projectRoot) => {
521
733
  const existingTableNames = new Set(tables.map((table) => table.name));
522
734
  const vectorIndexes = [];
523
735
  for (const extendCall of extendCallsOf(defineSchemaCall)) {
524
- const merged = mergeExtendCall(extendCall);
736
+ const merged = mergeExtendCall(extendCall, projectRoot);
525
737
  if (!merged) {
526
738
  continue;
527
739
  }
@@ -539,7 +751,7 @@ const applyExtensions = (defineSchemaCall, tables) => {
539
751
  }
540
752
  return vectorIndexes;
541
753
  };
542
- const discoverSchema = (project, schemaPath) => {
754
+ const discoverSchema = (project, schemaPath, projectRoot) => {
543
755
  const file = project.addSourceFileAtPath(schemaPath);
544
756
  const defineSchemaCall = file.getDescendantsOfKind(SyntaxKind.CallExpression).find((call) => {
545
757
  const callee = call.getExpression();
@@ -555,7 +767,7 @@ const discoverSchema = (project, schemaPath) => {
555
767
  const tables = parseBaseTables(argument);
556
768
  const standaloneArgument = defineSchemaCall.getArguments()[1];
557
769
  const standaloneVectorIndexes = standaloneArgument && Node.isObjectLiteralExpression(standaloneArgument) ? parseStandaloneVectorIndexes(standaloneArgument) : [];
558
- const extensionStandaloneVectorIndexes = applyExtensions(defineSchemaCall, tables);
770
+ const extensionStandaloneVectorIndexes = applyExtensions(defineSchemaCall, tables, projectRoot);
559
771
  const vectorIndexes = [...tables.flatMap((table) => table.vectorIndexes), ...standaloneVectorIndexes, ...extensionStandaloneVectorIndexes];
560
772
  return { tables, vectorIndexes };
561
773
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/codegen",
3
- "version": "1.0.0-alpha.5",
3
+ "version": "1.0.0-alpha.7",
4
4
  "description": "Code generator for Lunora: emits _generated/{api,server,dataModel}.ts from your schema",
5
5
  "keywords": [
6
6
  "cloudflare",