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

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
@@ -12,14 +12,14 @@ export { default as discoverNondeterministicCalls } from './packem_shared/discov
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-BBulgGbH.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-C5UlpWKF.mjs';
22
+ export { SCHEMA_SNAPSHOT_FILENAME, createCodegenProject, refreshCodegenProject, runCodegen } from './packem_shared/SCHEMA_SNAPSHOT_FILENAME-TeOosleN.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';
@@ -14,7 +14,7 @@ import discoverNondeterministicCalls from './discoverNondeterministicCalls-4KiPQ
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-BBulgGbH.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);
@@ -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"]);
@@ -354,7 +560,27 @@ const extensionTargetIdentifier = (argument) => {
354
560
  return argument;
355
561
  }
356
562
  if (Node.isPropertyAccessExpression(argument)) {
357
- return argument.getNameNode();
563
+ const receiver = argument.getExpression();
564
+ return Node.isIdentifier(receiver) ? receiver : void 0;
565
+ }
566
+ return void 0;
567
+ };
568
+ const pluginConfigObject = (expression) => {
569
+ if (Node.isObjectLiteralExpression(expression)) {
570
+ return expression;
571
+ }
572
+ if (Node.isCallExpression(expression)) {
573
+ const callee = expression.getExpression();
574
+ let name;
575
+ if (Node.isIdentifier(callee)) {
576
+ name = callee.getText();
577
+ } else if (Node.isPropertyAccessExpression(callee)) {
578
+ name = callee.getName();
579
+ }
580
+ if (name === "definePlugin") {
581
+ const configArgument = expression.getArguments()[1];
582
+ return configArgument && Node.isObjectLiteralExpression(configArgument) ? configArgument : void 0;
583
+ }
358
584
  }
359
585
  return void 0;
360
586
  };
@@ -363,8 +589,9 @@ const nextExpressionFromDeclaration = (declaration, argument) => {
363
589
  if (!initializer) {
364
590
  return void 0;
365
591
  }
366
- if (Node.isPropertyAccessExpression(argument) && Node.isObjectLiteralExpression(initializer)) {
367
- return objectPropertyInitializer(initializer, argument.getName());
592
+ if (Node.isPropertyAccessExpression(argument)) {
593
+ const configObject = pluginConfigObject(initializer);
594
+ return configObject ? objectPropertyInitializer(configObject, argument.getName()) : void 0;
368
595
  }
369
596
  return initializer;
370
597
  };
@@ -434,24 +661,30 @@ const parseExtensionVectorIndexes = (options) => {
434
661
  }
435
662
  return parseStandaloneVectorIndexes(object);
436
663
  };
437
- const mergeExtension = (key, options) => {
438
- const bareTables = parseExtensionTables(options);
664
+ const namespaceExtension = (key, bareTables, bareVectorIndexes) => {
439
665
  const bareNames = new Set(bareTables.map((table) => table.name));
440
666
  const tables = bareTables.map((table) => namespaceExtensionTable(table, key, bareNames));
441
- const vectorIndexes = parseExtensionVectorIndexes(options).map((index) => {
667
+ const vectorIndexes = bareVectorIndexes.map((index) => {
442
668
  return { ...index, name: prefixTableName(key, index.name), table: rewriteReference(index.table, key, bareNames) };
443
669
  });
444
670
  return { tables, vectorIndexes };
445
671
  };
446
- const mergeExtendCall = (extendCall) => {
672
+ const mergeExtension = (key, options) => namespaceExtension(key, parseExtensionTables(options), parseExtensionVectorIndexes(options));
673
+ const mergeExtendCall = (extendCall, projectRoot) => {
447
674
  const extendArgument = extendCall.getArguments()[0];
448
675
  if (!extendArgument) {
449
676
  return void 0;
450
677
  }
451
678
  const resolved = resolveSchemaExtensionCall(extendArgument);
452
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
+ }
453
686
  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.`
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.`
455
688
  );
456
689
  return void 0;
457
690
  }
@@ -496,11 +729,11 @@ const parseBaseTables = (object) => {
496
729
  }
497
730
  return tables;
498
731
  };
499
- const applyExtensions = (defineSchemaCall, tables) => {
732
+ const applyExtensions = (defineSchemaCall, tables, projectRoot) => {
500
733
  const existingTableNames = new Set(tables.map((table) => table.name));
501
734
  const vectorIndexes = [];
502
735
  for (const extendCall of extendCallsOf(defineSchemaCall)) {
503
- const merged = mergeExtendCall(extendCall);
736
+ const merged = mergeExtendCall(extendCall, projectRoot);
504
737
  if (!merged) {
505
738
  continue;
506
739
  }
@@ -518,7 +751,7 @@ const applyExtensions = (defineSchemaCall, tables) => {
518
751
  }
519
752
  return vectorIndexes;
520
753
  };
521
- const discoverSchema = (project, schemaPath) => {
754
+ const discoverSchema = (project, schemaPath, projectRoot) => {
522
755
  const file = project.addSourceFileAtPath(schemaPath);
523
756
  const defineSchemaCall = file.getDescendantsOfKind(SyntaxKind.CallExpression).find((call) => {
524
757
  const callee = call.getExpression();
@@ -534,7 +767,7 @@ const discoverSchema = (project, schemaPath) => {
534
767
  const tables = parseBaseTables(argument);
535
768
  const standaloneArgument = defineSchemaCall.getArguments()[1];
536
769
  const standaloneVectorIndexes = standaloneArgument && Node.isObjectLiteralExpression(standaloneArgument) ? parseStandaloneVectorIndexes(standaloneArgument) : [];
537
- const extensionStandaloneVectorIndexes = applyExtensions(defineSchemaCall, tables);
770
+ const extensionStandaloneVectorIndexes = applyExtensions(defineSchemaCall, tables, projectRoot);
538
771
  const vectorIndexes = [...tables.flatMap((table) => table.vectorIndexes), ...standaloneVectorIndexes, ...extensionStandaloneVectorIndexes];
539
772
  return { tables, vectorIndexes };
540
773
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/codegen",
3
- "version": "1.0.0-alpha.4",
3
+ "version": "1.0.0-alpha.6",
4
4
  "description": "Code generator for Lunora: emits _generated/{api,server,dataModel}.ts from your schema",
5
5
  "keywords": [
6
6
  "cloudflare",