@lunora/codegen 1.0.0-alpha.3 → 1.0.0-alpha.30
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/__assets__/package-og.svg +1 -1
- package/dist/index.d.mts +1084 -25
- package/dist/index.d.ts +1084 -25
- package/dist/index.mjs +29 -23
- package/dist/packem_shared/{CONTAINERS_FILENAME-0K-pjNb8.mjs → CONTAINERS_FILENAME-DjpXMqhp.mjs} +1 -1
- package/dist/packem_shared/{CodegenDiagnosticError-54jWDxA9.mjs → CodegenDiagnosticError-DyQ5FwkM.mjs} +7 -5
- package/dist/packem_shared/FLAGS_FILENAME-BjpS5w08.mjs +139 -0
- package/dist/packem_shared/{GENERATED_HEADER-CuLyj0WQ.mjs → GENERATED_HEADER-f6nMvllu.mjs} +853 -65
- package/dist/packem_shared/MUTATORS_FILENAME-BZOfUhlY.mjs +81 -0
- package/dist/packem_shared/{OPENRPC_VERSION-BGUrsrt_.mjs → OPENRPC_VERSION-u5SqDDGk.mjs} +1 -1
- package/dist/packem_shared/QUEUES_FILENAME-BF0iUmx7.mjs +119 -0
- package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-Cpfn80SH.mjs +3481 -0
- package/dist/packem_shared/{SCHEMA_SNAPSHOT_VERSION-DzLDbWk3.mjs → SCHEMA_SNAPSHOT_VERSION-D0ARY6rL.mjs} +18 -2
- package/dist/packem_shared/SHAPES_FILENAME-DOhPGi-6.mjs +94 -0
- package/dist/packem_shared/{WORKFLOWS_FILENAME-DRDQdhfq.mjs → WORKFLOWS_FILENAME-CCC_42o3.mjs} +42 -2
- package/dist/packem_shared/{buildOpenApiDocument-CXwnbp4b.mjs → buildOpenApiDocument-AgKWmlry.mjs} +1 -1
- package/dist/packem_shared/{discoverAuthApiCalls-C35R6z0T.mjs → discoverAuthApiCalls-URDoTADN.mjs} +1 -1
- package/dist/packem_shared/{discoverCrons-BL6iGuJ3.mjs → discoverCrons-DdZOeroL.mjs} +20 -17
- package/dist/packem_shared/{discoverFunctions-DEgAcRuD.mjs → discoverFunctions-BJdF7lRs.mjs} +63 -9
- package/dist/packem_shared/{discoverHttpRoutes-C978pBiG.mjs → discoverHttpRoutes-CcwP-Rkr.mjs} +2 -2
- package/dist/packem_shared/{discoverInserts-CRQdXvHO.mjs → discoverInserts-BpFhM32L.mjs} +24 -2
- package/dist/packem_shared/{discoverMaskProcedures-B64zA740.mjs → discoverMaskProcedures-DT-v8wvj.mjs} +58 -2
- package/dist/packem_shared/{discoverMigrations-Doj_-BAA.mjs → discoverMigrations-cG1idBVM.mjs} +10 -4
- package/dist/packem_shared/{discoverNondeterministicCalls-4KiPQxQU.mjs → discoverNondeterministicCalls-CEOjmfk4.mjs} +1 -1
- package/dist/packem_shared/{discoverQueries-BkIi0dBD.mjs → discoverQueries-DeVBQVAG.mjs} +1 -1
- package/dist/packem_shared/{discoverR2sqlCalls-BpDqvcUn.mjs → discoverR2sqlCalls-CWCAU-xJ.mjs} +1 -1
- package/dist/packem_shared/{discoverRlsMetadata-DpRB1HMe.mjs → discoverRlsMetadata-BL0oukaK.mjs} +1 -1
- package/dist/packem_shared/{discoverSchema-BBulgGbH.mjs → discoverSchema-CeXJWVKV.mjs} +349 -17
- package/dist/packem_shared/{discoverStorageRulesMetadata-DAqJUxUv.mjs → discoverStorageRulesMetadata-CFHByjIl.mjs} +1 -1
- package/dist/packem_shared/{emitApp-CzSxVDaG.mjs → emitApp-DKt3rPtr.mjs} +84 -8
- package/dist/packem_shared/{formatAdvisories-8NIv1k0I.mjs → formatAdvisories-C9wNBNvL.mjs} +47 -3
- package/dist/packem_shared/{parse-validator-tuQtHrsr.mjs → parse-validator-D6zI2i85.mjs} +5 -3
- package/dist/packem_shared/redact-oTmsol5A.mjs +33 -0
- package/package.json +9 -7
- package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-BQ_kCZ81.mjs +0 -903
|
@@ -1,6 +1,213 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
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-D6zI2i85.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
|
-
|
|
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)
|
|
367
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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(...)\`
|
|
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
|
|
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-
|
|
2
|
+
import { listLunoraSourceFiles, lunoraRelativePath, classifyProcedureCall } from './discoverFunctions-BJdF7lRs.mjs';
|
|
3
3
|
|
|
4
4
|
const STORAGE_OPERATIONS = /* @__PURE__ */ new Set(["delete", "list", "read", "write"]);
|
|
5
5
|
const isStorageRulesCall = (node) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GENERATED_HEADER } from './GENERATED_HEADER-
|
|
1
|
+
import { GENERATED_HEADER } from './GENERATED_HEADER-f6nMvllu.mjs';
|
|
2
2
|
|
|
3
3
|
const LONG_TAIL = [
|
|
4
4
|
["hasAi", "ai", "ai", "Override the Workers AI binding backing `ctx.ai` (defaults to `env.AI`)."],
|
|
@@ -22,8 +22,28 @@ const LONG_TAIL = [
|
|
|
22
22
|
["hasVectors", "vectors", "vectors", "Wire the Vectorize index map backing `ctx.vectors`."]
|
|
23
23
|
];
|
|
24
24
|
const hasAnyLongTail = (options) => LONG_TAIL.some(([flag]) => options[flag]);
|
|
25
|
+
const buildIdentityImports = (identity) => identity ? [`import * as lunoraIdentityContract from "../identity.js";`] : [];
|
|
26
|
+
const buildAccessImports = (hasAccess, hasAuth) => hasAccess ? [
|
|
27
|
+
`import type { CreateAccessResolverOptions } from "@lunora/cloudflare-access";`,
|
|
28
|
+
`import { createAccessResolver${hasAuth ? ", composeResolvers" : ""} } from "@lunora/cloudflare-access";`
|
|
29
|
+
] : [];
|
|
30
|
+
const buildKvImports = (hasKv) => hasKv ? [`import { createKvIntrospectorFromEnv } from "@lunora/bindings/kv";`] : [];
|
|
25
31
|
const buildImportLines = (options) => {
|
|
26
|
-
const {
|
|
32
|
+
const {
|
|
33
|
+
hasAccess,
|
|
34
|
+
hasAuth,
|
|
35
|
+
hasFramework,
|
|
36
|
+
hasGlobal,
|
|
37
|
+
hasHyperdriveGlobal,
|
|
38
|
+
hasKv,
|
|
39
|
+
hasQueue,
|
|
40
|
+
hasScheduler,
|
|
41
|
+
hasStorage,
|
|
42
|
+
hasWorkflow,
|
|
43
|
+
useUmbrella,
|
|
44
|
+
wantsOpenApi,
|
|
45
|
+
wantsOpenRpc
|
|
46
|
+
} = options;
|
|
27
47
|
const runtimeModule = useUmbrella ? "lunorash/runtime" : "@lunora/runtime";
|
|
28
48
|
const runtimeTypeImports = ["ExecutionContextLike", "LunoraWorker", "Route", "ScheduledControllerLike", "ShardNamespaceLike", "WorkerOptions"];
|
|
29
49
|
if (hasGlobal) {
|
|
@@ -42,6 +62,7 @@ const buildImportLines = (options) => {
|
|
|
42
62
|
`import type { LunoraAuth, LunoraAuthOptions } from "@lunora/auth";`,
|
|
43
63
|
`import { createAuth, createAuthAdmin, ensureMigrated, handleAuthRequest, lunoraD1Adapter } from "@lunora/auth";`
|
|
44
64
|
] : [],
|
|
65
|
+
...buildAccessImports(hasAccess, hasAuth),
|
|
45
66
|
...hasGlobal ? [
|
|
46
67
|
`import type { D1CtxDbOptions, D1DatabaseLike, D1Exec } from "@lunora/d1";`,
|
|
47
68
|
`import { createD1CtxDb, facetGlobalColumn, listGlobalTables, readGlobalTablePage } from "@lunora/d1";`
|
|
@@ -51,15 +72,18 @@ const buildImportLines = (options) => {
|
|
|
51
72
|
`import { createHyperdriveGlobalCtxDb } from "@lunora/hyperdrive/global";`,
|
|
52
73
|
`import type { SqlCtxDbOptions, SqlExec } from "@lunora/sql-store";`
|
|
53
74
|
] : [],
|
|
75
|
+
...buildKvImports(hasKv),
|
|
54
76
|
...hasScheduler ? [`import type { DurableObjectNamespaceLike } from "@lunora/scheduler";`, `import { createScheduler } from "@lunora/scheduler";`] : [],
|
|
55
77
|
...hasStorage ? [`import type { R2BucketLike, Storage } from "@lunora/storage";`, `import { createBucketStorage, createStorage } from "@lunora/storage";`] : [],
|
|
56
78
|
...hasWorkflow ? [`import { createWorkflowsRestClient } from "@lunora/workflow";`] : [],
|
|
57
79
|
`import type { ${[...runtimeTypeImports].toSorted((a, b) => a.localeCompare(b)).join(", ")} } from "${runtimeModule}";`,
|
|
58
80
|
`import { ${runtimeValueImports} } from "${runtimeModule}";`,
|
|
59
81
|
``,
|
|
82
|
+
...buildIdentityImports(options.identity),
|
|
60
83
|
...hasGlobal || hasHyperdriveGlobal ? [`import schema from "../schema.js";`] : [],
|
|
61
84
|
`import { LUNORA_CRONS } from "./crons.js";`,
|
|
62
85
|
`import { LUNORA_FUNCTIONS } from "./functions.js";`,
|
|
86
|
+
...hasQueue ? [`import { dispatchQueueBatch } from "@lunora/queue";`, `import { LUNORA_QUEUE_REGISTRY } from "./queues.js";`] : [],
|
|
63
87
|
...wantsOpenApi ? [`import { openApiSpec } from "./openapi.js";`] : [],
|
|
64
88
|
...wantsOpenRpc ? [`import { openRpcSpec } from "./openrpc.js";`] : [],
|
|
65
89
|
`import { createShardDO } from "./shard.js";`
|
|
@@ -119,9 +143,10 @@ interface AuthDeclaration<Env> {
|
|
|
119
143
|
] : []
|
|
120
144
|
];
|
|
121
145
|
const buildFieldLines = (options) => [
|
|
146
|
+
...options.hasAccess ? [` private accessSelector?: Selector<Env, CreateAccessResolverOptions>;`] : [],
|
|
122
147
|
` private adminToken?: Selector<Env, string>;`,
|
|
123
148
|
...options.hasAuth ? [` private authDeclaration?: AuthDeclaration<Env>;`] : [],
|
|
124
|
-
` private readonly extendFns: ((env: Env) => Partial<WorkerOptions>)[] = [];`,
|
|
149
|
+
` private readonly extendFns: ((env: Env, derived: Readonly<WorkerOptions>) => Partial<WorkerOptions>)[] = [];`,
|
|
125
150
|
...options.hasGlobal ? [` private globalDeclaration?: GlobalDeclaration<Env>;`] : [],
|
|
126
151
|
...options.hasHyperdriveGlobal ? [` private hyperdriveGlobalDeclaration?: HyperdriveGlobalDeclaration<Env>;`] : [],
|
|
127
152
|
` private readonly routeMap: Record<string, Route> = {};`,
|
|
@@ -139,6 +164,14 @@ const buildLongTailMethods = (options) => LONG_TAIL.filter(([flag]) => options[f
|
|
|
139
164
|
}`
|
|
140
165
|
);
|
|
141
166
|
const buildMethodBlocks = (options) => [
|
|
167
|
+
...options.hasAccess ? [
|
|
168
|
+
` /** Wire Cloudflare Access (Zero Trust) — verifies the \`Cf-Access-Jwt-Assertion\` JWT and feeds the identity into \`ctx.auth\` / RLS via \`resolveIdentity\`. When \`.auth(...)\` is also configured, Access is composed ahead of it (Access wins when its JWT is present; everyone else falls through to the app session). */
|
|
169
|
+
public access(selector: Selector<Env, CreateAccessResolverOptions>): this {
|
|
170
|
+
this.accessSelector = selector;
|
|
171
|
+
|
|
172
|
+
return this;
|
|
173
|
+
}`
|
|
174
|
+
] : [],
|
|
142
175
|
` /** Bearer token gating the \`/_lunora/admin/*\` endpoints the studio calls. */
|
|
143
176
|
public admin(selector: Selector<Env, string>): this {
|
|
144
177
|
this.adminToken = selector;
|
|
@@ -153,8 +186,8 @@ const buildMethodBlocks = (options) => [
|
|
|
153
186
|
return this;
|
|
154
187
|
}`
|
|
155
188
|
] : [],
|
|
156
|
-
` /** Escape hatch — merge raw \`WorkerOptions\` (anything not yet sugared) over the derived options at build time. */
|
|
157
|
-
public extend(fn: (env: Env) => Partial<WorkerOptions>): this {
|
|
189
|
+
` /** Escape hatch — merge raw \`WorkerOptions\` (anything not yet sugared) over the derived options at build time. The second \`derived\` argument is a snapshot of the options assembled so far (after \`.auth(...)\` etc.), so you can compose rather than clobber — e.g. wrap \`derived.resolveIdentity\` instead of replacing it. */
|
|
190
|
+
public extend(fn: (env: Env, derived: Readonly<WorkerOptions>) => Partial<WorkerOptions>): this {
|
|
158
191
|
this.extendFns.push(fn);
|
|
159
192
|
|
|
160
193
|
return this;
|
|
@@ -274,7 +307,7 @@ const buildShardFactoryBody = (options) => {
|
|
|
274
307
|
const namespace = this.schedulerDeclaration?.namespace(env);
|
|
275
308
|
const origin = this.schedulerDeclaration?.origin?.(env);
|
|
276
309
|
|
|
277
|
-
return namespace && origin ? createScheduler({ namespace, originUrl: origin }) : undefined;
|
|
310
|
+
return namespace && origin ? createScheduler({${options.jurisdiction ? ` jurisdiction: ${JSON.stringify(options.jurisdiction)},` : ""} namespace, originUrl: origin }) : undefined;
|
|
278
311
|
},
|
|
279
312
|
}
|
|
280
313
|
: {}),`
|
|
@@ -321,6 +354,12 @@ const buildWorkerOptionLines = (options) => [
|
|
|
321
354
|
Object.assign(options, this.buildStorageAdmin(env));
|
|
322
355
|
}`
|
|
323
356
|
] : [],
|
|
357
|
+
// The studio's KV browser is wired zero-config: `createKvIntrospectorFromEnv`
|
|
358
|
+
// scans `env` for every bound Workers KV namespace, so each `kv_namespaces`
|
|
359
|
+
// entry in wrangler.jsonc appears under its binding name (any name, any count)
|
|
360
|
+
// with no manual `createKvIntrospector` call. A deployment with no KV binding
|
|
361
|
+
// yields an empty namespace list rather than crashing.
|
|
362
|
+
...options.hasKv ? [` options.kvIntrospector = createKvIntrospectorFromEnv(env);`] : [],
|
|
324
363
|
...options.hasAuth ? [
|
|
325
364
|
` if (this.authDeclaration) {
|
|
326
365
|
options.authHandler = (request) => {
|
|
@@ -343,13 +382,45 @@ const buildWorkerOptionLines = (options) => [
|
|
|
343
382
|
|
|
344
383
|
options.authAdmin = authInstance ? createAuthAdmin(authInstance) : undefined;
|
|
345
384
|
}`
|
|
385
|
+
] : [],
|
|
386
|
+
// Cloudflare Access — runs AFTER the auth block so it can compose ahead of
|
|
387
|
+
// the better-auth resolver rather than clobber it. With `.auth()` present,
|
|
388
|
+
// a request carrying a verified Access JWT is authenticated by Access and
|
|
389
|
+
// everyone else falls through to the app session; without it, Access is the
|
|
390
|
+
// sole resolver.
|
|
391
|
+
...options.hasAccess ? [
|
|
392
|
+
options.hasAuth ? ` if (this.accessSelector) {
|
|
393
|
+
const accessResolver = createAccessResolver(this.accessSelector(env));
|
|
394
|
+
const fallback = options.resolveIdentity;
|
|
395
|
+
|
|
396
|
+
options.resolveIdentity = fallback ? composeResolvers(accessResolver, fallback) : accessResolver;
|
|
397
|
+
}` : ` if (this.accessSelector) {
|
|
398
|
+
options.resolveIdentity = createAccessResolver(this.accessSelector(env));
|
|
399
|
+
}`
|
|
346
400
|
] : []
|
|
347
401
|
];
|
|
348
402
|
const buildBaseWorkerOptions = (options) => [
|
|
349
403
|
` cronJobs: LUNORA_CRONS,`,
|
|
350
404
|
` functions: LUNORA_FUNCTIONS,`,
|
|
405
|
+
// The declared `defineIdentity(...)` contract — wires the runtime trust
|
|
406
|
+
// boundary so `wrapResolverWithContract` validates every resolved identity
|
|
407
|
+
// against it before it becomes `ctx.auth`. Emitted only when the app declares
|
|
408
|
+
// a contract, so apps without one keep unchanged output.
|
|
409
|
+
...options.identity ? [` identity: lunoraIdentityContract.${options.identity.exportName},`] : [],
|
|
410
|
+
// Schema `.jurisdiction("…")` pins every DO the worker reaches to the
|
|
411
|
+
// Cloudflare data-residency region. Emitted only when declared, so apps
|
|
412
|
+
// without it keep the un-pinned global namespace (and unchanged output).
|
|
413
|
+
...options.jurisdiction ? [` jurisdiction: ${JSON.stringify(options.jurisdiction)},`] : [],
|
|
351
414
|
...options.wantsOpenApi ? [` openApiSpec,`] : [],
|
|
352
415
|
...options.wantsOpenRpc ? [` openRpcSpec,`] : [],
|
|
416
|
+
// The push-consumer handler backing the worker's `queue(batch, …)` entry:
|
|
417
|
+
// routes each delivered batch to its `defineQueue` handler. Built from
|
|
418
|
+
// `@lunora/queue` here (keeping the runtime decoupled) and wired only when the
|
|
419
|
+
// app declares push queues in `lunora/queues.ts`.
|
|
420
|
+
...options.hasQueue ? [
|
|
421
|
+
` queue: (batch: unknown, queueEnv: unknown, _context: ExecutionContextLike): Promise<void> =>`,
|
|
422
|
+
` dispatchQueueBatch(batch as Parameters<typeof dispatchQueueBatch>[0], LUNORA_QUEUE_REGISTRY, { env: queueEnv as Record<string, unknown> }),`
|
|
423
|
+
] : [],
|
|
353
424
|
` routes: this.routeMap,`,
|
|
354
425
|
` shardDO: this.shardSelector?.(env) ?? (undefined as unknown as ShardNamespaceLike),`
|
|
355
426
|
];
|
|
@@ -558,7 +629,12 @@ ${buildWorkerLine}
|
|
|
558
629
|
worker ??= buildWorker(rawEnv as Env);
|
|
559
630
|
|
|
560
631
|
return worker.serverQuery(request, rawEnv, reference, args, options);
|
|
561
|
-
}
|
|
632
|
+
},${options.hasQueue ? `
|
|
633
|
+
queue: async (batch: unknown, rawEnv: unknown, context: ExecutionContextLike): Promise<void> => {
|
|
634
|
+
worker ??= buildWorker(rawEnv as Env);
|
|
635
|
+
|
|
636
|
+
return worker.queue?.(batch, rawEnv, context);
|
|
637
|
+
},` : ""}
|
|
562
638
|
};
|
|
563
639
|
|
|
564
640
|
if (this.emailHandler) {
|
|
@@ -581,7 +657,7 @@ ${buildBaseWorkerOptions(options).join("\n")}
|
|
|
581
657
|
}
|
|
582
658
|
|
|
583
659
|
${workerOptionLines.join("\n\n")}${workerOptionLines.length > 0 ? "\n\n" : ""} for (const fn of this.extendFns) {
|
|
584
|
-
Object.assign(options, fn(env));
|
|
660
|
+
Object.assign(options, fn(env, { ...options }));
|
|
585
661
|
}
|
|
586
662
|
|
|
587
663
|
return options;
|