@lunora/codegen 1.0.0-alpha.15 → 1.0.0-alpha.17
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 +107 -3
- package/dist/index.d.ts +107 -3
- package/dist/index.mjs +8 -6
- package/dist/packem_shared/{GENERATED_HEADER-CkZUgM4_.mjs → GENERATED_HEADER-BoVKLcnE.mjs} +183 -15
- package/dist/packem_shared/MUTATORS_FILENAME-BhqdPtKp.mjs +81 -0
- package/dist/packem_shared/{OPENRPC_VERSION-VINwUAxf.mjs → OPENRPC_VERSION-BMCOe3B6.mjs} +1 -1
- package/dist/packem_shared/{SCHEMA_SNAPSHOT_FILENAME-DsBxQ5C_.mjs → SCHEMA_SNAPSHOT_FILENAME-BA9tjjOl.mjs} +73 -7
- package/dist/packem_shared/SHAPES_FILENAME-ChV7MqgE.mjs +94 -0
- package/dist/packem_shared/{buildOpenApiDocument-BSoDzIn8.mjs → buildOpenApiDocument-CB2brlbc.mjs} +1 -1
- package/dist/packem_shared/{emitApp-DGmlt5fq.mjs → emitApp-Bh0HsQVK.mjs} +1 -1
- package/dist/packem_shared/{formatAdvisories-8NIv1k0I.mjs → formatAdvisories-LM8-Ixjw.mjs} +8 -2
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
|
@@ -201,6 +201,59 @@ interface MigrationIR {
|
|
|
201
201
|
table: string;
|
|
202
202
|
}
|
|
203
203
|
/**
|
|
204
|
+
* A `defineShape({...})` declaration discovered in `lunora/shapes.ts`
|
|
205
|
+
* (local-first sync engine, Phase 7). The emitted `LUNORA_SHAPES` registry keys
|
|
206
|
+
* on {@link ShapeIR.exportName}; the generated DO's `resolveShape` override
|
|
207
|
+
* dispatches a `shape_subscribe` to the matching registered shape. Discovery is
|
|
208
|
+
* marker-driven (the `__lunoraShape` brand) — no field metadata is lifted here
|
|
209
|
+
* because the runtime object (`columns`/`compileWhere`) carries the authority.
|
|
210
|
+
*/
|
|
211
|
+
interface ShapeIR {
|
|
212
|
+
/** Export binding name — the shape's registry key and import member. */
|
|
213
|
+
exportName: string;
|
|
214
|
+
/** Path relative to `<projectRoot>/lunora/` without extension — always `"shapes"`. */
|
|
215
|
+
filePath: string;
|
|
216
|
+
/**
|
|
217
|
+
* The `table` string literal from the `defineShape({ table })` call, lifted
|
|
218
|
+
* only for static advisor lints (the runtime object stays authoritative).
|
|
219
|
+
* `undefined` when `table` is not a plain string literal — lints skip those.
|
|
220
|
+
*/
|
|
221
|
+
table?: string;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* A `defineMutator({...})` declaration discovered in `lunora/mutators.ts`
|
|
225
|
+
* (local-first sync engine, Phase 7). The emitted registry registers the
|
|
226
|
+
* authoritative `server` impl into the DO's `LUNORA_FUNCTIONS` table (so
|
|
227
|
+
* `handleRpc` transaction-wraps it) and records its path in
|
|
228
|
+
* `LUNORA_MUTATOR_PATHS` so the DO's `isCustomMutator` override routes the
|
|
229
|
+
* client-watermark push protocol. The client `client` impl is split into the
|
|
230
|
+
* browser bundle separately — only the path crosses to the server side.
|
|
231
|
+
*/
|
|
232
|
+
interface MutatorIR {
|
|
233
|
+
/** Export binding name — the mutator's registry key and import member. */
|
|
234
|
+
exportName: string;
|
|
235
|
+
/** Path relative to `<projectRoot>/lunora/` without extension — always `"mutators"`. */
|
|
236
|
+
filePath: string;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* A whole-row `ctx.db.replace(id, document)` write discovered inside a custom
|
|
240
|
+
* mutator's inline `server` impl (`lunora/mutators.ts`) — the input the
|
|
241
|
+
* `mutator_full_row_replace` advisor lint consumes. A `replace` overwrites the
|
|
242
|
+
* entire row, so a concurrent edit to a different column on a synced table is
|
|
243
|
+
* clobbered; `ctx.db.patch(id, { field })` merges at the column level instead.
|
|
244
|
+
* Structurally identical to `AdvisorMutatorWrite` so it passes straight through
|
|
245
|
+
* to the advisor without conversion, exactly as `InsertWriteIR` does for
|
|
246
|
+
* `AdvisorInsertWrite`.
|
|
247
|
+
*/
|
|
248
|
+
interface MutatorWriteIR {
|
|
249
|
+
/** The mutator export whose `server` impl performs the replace, e.g. `renameChannel`. */
|
|
250
|
+
exportName: string;
|
|
251
|
+
/** Openable source path the replace appears in — always `lunora/mutators.ts`. */
|
|
252
|
+
file: string;
|
|
253
|
+
/** 1-based line of the `replace(...)` call. */
|
|
254
|
+
line: number;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
204
257
|
* A single cron job lifted from a `cronJobs()` builder in `lunora/crons.ts`.
|
|
205
258
|
* Mirrors `@lunora/scheduler`'s `CronJob`: {@link CronJobIR.cron} is the compiled
|
|
206
259
|
* standard cron expression, {@link CronJobIR.functionPath} is the target
|
|
@@ -783,7 +836,7 @@ interface ProjectIR {
|
|
|
783
836
|
* pass straight through without conversion. Returns the findings; surfacing them
|
|
784
837
|
* (console, error overlay, studio Advisors table) is the caller's choice.
|
|
785
838
|
*/
|
|
786
|
-
declare const lintSchema: (schema: SchemaIR, queries?: ReadonlyArray<QueryReadIR>, inserts?: ReadonlyArray<InsertWriteIR>, authApiCalls?: ReadonlyArray<AuthApiCallIR>, rlsProcedures?: ReadonlyArray<RlsProcedureIR>, containers?: ReadonlyArray<ContainerIR>, workflows?: ReadonlyArray<WorkflowIR>, workflowCalls?: ReadonlyArray<WorkflowCallIR>, maskProcedures?: ReadonlyArray<MaskProcedureIR>, nondeterministicCalls?: ReadonlyArray<NondeterministicCallIR>, procedureProtections?: ReadonlyArray<ProcedureMiddlewareIR>, argumentValidators?: ReadonlyArray<ArgumentValidatorIR>, secretLiterals?: ReadonlyArray<SecretLiteralIR>, sqlInterpolations?: ReadonlyArray<SqlInterpolationIR>, adminRoutes?: ReadonlyArray<AdminRouteIR>, r2sqlCalls?: ReadonlyArray<R2sqlCallIR>) => Finding[];
|
|
839
|
+
declare const lintSchema: (schema: SchemaIR, queries?: ReadonlyArray<QueryReadIR>, inserts?: ReadonlyArray<InsertWriteIR>, authApiCalls?: ReadonlyArray<AuthApiCallIR>, rlsProcedures?: ReadonlyArray<RlsProcedureIR>, containers?: ReadonlyArray<ContainerIR>, workflows?: ReadonlyArray<WorkflowIR>, workflowCalls?: ReadonlyArray<WorkflowCallIR>, maskProcedures?: ReadonlyArray<MaskProcedureIR>, nondeterministicCalls?: ReadonlyArray<NondeterministicCallIR>, procedureProtections?: ReadonlyArray<ProcedureMiddlewareIR>, argumentValidators?: ReadonlyArray<ArgumentValidatorIR>, secretLiterals?: ReadonlyArray<SecretLiteralIR>, sqlInterpolations?: ReadonlyArray<SqlInterpolationIR>, adminRoutes?: ReadonlyArray<AdminRouteIR>, r2sqlCalls?: ReadonlyArray<R2sqlCallIR>, shapes?: ReadonlyArray<ShapeIR>, mutatorWrites?: ReadonlyArray<MutatorWriteIR>) => Finding[];
|
|
787
840
|
/**
|
|
788
841
|
* Render advisor findings as a single multi-line string for console surfacing:
|
|
789
842
|
* a one-line summary header followed by one `[LEVEL] name: detail` line per
|
|
@@ -898,6 +951,23 @@ declare const discoverMaskProcedures: (project: Project, lunoraDirectory: string
|
|
|
898
951
|
* key); `table` is best-effort and left `""` when not a literal.
|
|
899
952
|
*/
|
|
900
953
|
declare const discoverMigrations: (project: Project, lunoraDirectory: string) => MigrationIR[];
|
|
954
|
+
/** The only file custom mutators may be declared in — mirrors `lunora/queues.ts`. */
|
|
955
|
+
declare const MUTATORS_FILENAME = "mutators.ts";
|
|
956
|
+
/**
|
|
957
|
+
* Decide whether a call's callee is `defineMutator` — either the bare imported
|
|
958
|
+
* identifier (`defineMutator(...)`) or a namespace member access
|
|
959
|
+
* (`server.defineMutator(...)`). Both are valid ES module syntax, so discovery
|
|
960
|
+
* must see mutators declared either way.
|
|
961
|
+
*/
|
|
962
|
+
|
|
963
|
+
/**
|
|
964
|
+
* Discover every custom mutator the project declares: exported
|
|
965
|
+
* `defineMutator()` calls in `lunora/mutators.ts`. Returns `[]` when the file
|
|
966
|
+
* doesn't exist. Only the export binding is lifted — the runtime object carries
|
|
967
|
+
* the authoritative `server` impl + `handler`, so codegen never evaluates the
|
|
968
|
+
* body. The client `client` impl is split into the browser bundle separately.
|
|
969
|
+
*/
|
|
970
|
+
declare const discoverMutators: (project: Project, lunoraDirectory: string) => MutatorIR[];
|
|
901
971
|
/**
|
|
902
972
|
* Discover non-deterministic API calls (`Date.now`, `new Date()`, `Date()`,
|
|
903
973
|
* `Math.random`, `crypto.randomUUID`, `crypto.getRandomValues` — including
|
|
@@ -963,6 +1033,16 @@ declare const discoverRlsMetadata: (project: Project, lunoraDirectory: string) =
|
|
|
963
1033
|
* return a structural IR. Throws if the file or call cannot be found.
|
|
964
1034
|
*/
|
|
965
1035
|
declare const discoverSchema: (project: Project, schemaPath: string, projectRoot?: string) => SchemaIR;
|
|
1036
|
+
/** The only file shapes may be declared in — mirrors `lunora/queues.ts`. */
|
|
1037
|
+
declare const SHAPES_FILENAME = "shapes.ts";
|
|
1038
|
+
/**
|
|
1039
|
+
* Discover every replication shape the project declares: exported
|
|
1040
|
+
* `defineShape()` calls in `lunora/shapes.ts`. Returns `[]` when the file
|
|
1041
|
+
* doesn't exist. Only the export binding is lifted — the runtime object carries
|
|
1042
|
+
* the authoritative `table`/`columns`/`compileWhere`, so codegen never
|
|
1043
|
+
* evaluates the predicate.
|
|
1044
|
+
*/
|
|
1045
|
+
declare const discoverShapes: (project: Project, lunoraDirectory: string) => ShapeIR[];
|
|
966
1046
|
/**
|
|
967
1047
|
* Aggregate the schema-wide storage-rule metadata the studio's inspector reads:
|
|
968
1048
|
* every statically-discovered `(bucket, on, prefix, procedure)` entry across all
|
|
@@ -1001,6 +1081,22 @@ declare const emitApi: (functions: ReadonlyArray<FunctionIR>, workflows?: Readon
|
|
|
1001
1081
|
* Returns `""` when `@lunora/seed` is not a declared dependency, so projects
|
|
1002
1082
|
* that don't use it keep a clean `_generated/` and never import the package.
|
|
1003
1083
|
*/
|
|
1084
|
+
|
|
1085
|
+
/**
|
|
1086
|
+
* Emit `_generated/collections.ts` — one TanStack DB collection factory per
|
|
1087
|
+
* `defineShape` in `lunora/shapes.ts` (the local-first partial-replication
|
|
1088
|
+
* surface). Each factory builds a live collection that syncs its shape's rowset
|
|
1089
|
+
* through the client's poke protocol (`subscribeShape`), so an app feeds the
|
|
1090
|
+
* result straight to `useLiveQuery`.
|
|
1091
|
+
*
|
|
1092
|
+
* Returns `""` (so `writeIfPresent` skips the file) unless the project both
|
|
1093
|
+
* declares shapes AND installs `@lunora/db` — the add-on that ships
|
|
1094
|
+
* `lunoraCollectionOptions`. `@lunora/db` stays a scoped install even under the
|
|
1095
|
+
* `lunorash` umbrella (an opt-in add-on, like `@lunora/auth`), so its import is
|
|
1096
|
+
* always `@lunora/db/collections`; only the in-umbrella `@lunora/client` import
|
|
1097
|
+
* is remapped to `lunorash/client`.
|
|
1098
|
+
*/
|
|
1099
|
+
declare const emitCollections: (shapes: ReadonlyArray<ShapeIR>, hasDatabase: boolean, useUmbrella?: boolean) => string;
|
|
1004
1100
|
interface EmitServerOptions {
|
|
1005
1101
|
containers?: ReadonlyArray<ContainerIR>;
|
|
1006
1102
|
hasAi?: boolean;
|
|
@@ -1047,7 +1143,7 @@ declare const emitServer: ({
|
|
|
1047
1143
|
useUmbrella,
|
|
1048
1144
|
workflows
|
|
1049
1145
|
}?: EmitServerOptions) => string;
|
|
1050
|
-
declare const emitFunctions: (functions: ReadonlyArray<FunctionIR>, migrations?: ReadonlyArray<MigrationIR>, useUmbrella?: boolean) => string;
|
|
1146
|
+
declare const emitFunctions: (functions: ReadonlyArray<FunctionIR>, migrations?: ReadonlyArray<MigrationIR>, useUmbrella?: boolean, mutators?: ReadonlyArray<MutatorIR>, shapes?: ReadonlyArray<ShapeIR>) => string;
|
|
1051
1147
|
/**
|
|
1052
1148
|
* Storage-column map per table for the file browser: `{ table: [field, …] }` for
|
|
1053
1149
|
* every field declared `v.storage(...)` (unwrapping `v.optional(...)`). The
|
|
@@ -1110,10 +1206,14 @@ interface EmitShardOptions {
|
|
|
1110
1206
|
/** A `lunora/` source reads `ctx.r2sql` (R2 SQL) — wires `ctx.r2sql` onto the ActionCtx only. */
|
|
1111
1207
|
hasR2sql?: boolean;
|
|
1112
1208
|
maskMetadata?: MaskMetadataIR;
|
|
1209
|
+
/** Custom mutators declared via `defineMutator` in `lunora/mutators.ts` — wires the `isCustomMutator` push-protocol override. */
|
|
1210
|
+
mutators?: ReadonlyArray<MutatorIR>;
|
|
1113
1211
|
/** Queues declared via `defineQueue` exports in `lunora/queues.ts` — wires the typed `ctx.queues` producers. */
|
|
1114
1212
|
queues?: ReadonlyArray<QueueIR>;
|
|
1115
1213
|
rlsMetadata?: RlsMetadataIR;
|
|
1116
1214
|
schema: SchemaIR;
|
|
1215
|
+
/** Replication shapes declared via `defineShape` in `lunora/shapes.ts` — wires the `resolveShape` subscription override. */
|
|
1216
|
+
shapes?: ReadonlyArray<ShapeIR>;
|
|
1117
1217
|
storageRules?: StorageRulesMetadataIR;
|
|
1118
1218
|
studioFeatures?: StudioFeaturesResult;
|
|
1119
1219
|
/** The project depends on the `lunora` umbrella — import base packages via its subpaths. */
|
|
@@ -1135,9 +1235,11 @@ declare const emitShard: ({
|
|
|
1135
1235
|
hasPipelines,
|
|
1136
1236
|
hasR2sql,
|
|
1137
1237
|
maskMetadata,
|
|
1238
|
+
mutators,
|
|
1138
1239
|
queues,
|
|
1139
1240
|
rlsMetadata,
|
|
1140
1241
|
schema,
|
|
1242
|
+
shapes,
|
|
1141
1243
|
storageRules,
|
|
1142
1244
|
studioFeatures,
|
|
1143
1245
|
useUmbrella,
|
|
@@ -1591,6 +1693,8 @@ interface CodegenResult {
|
|
|
1591
1693
|
generated: {
|
|
1592
1694
|
api: string; /** Fluent worker-composition builder (`_generated/app.ts`) — `defineApp()`. Always written. */
|
|
1593
1695
|
app: string;
|
|
1696
|
+
/** Partial-replication collection factories (`_generated/collections.ts`); `""` (and not written) unless the project declares shapes and installs `@lunora/db`. */
|
|
1697
|
+
collections: string;
|
|
1594
1698
|
/** Container DO classes (`_generated/containers.ts`); `""` (and not written) when no containers are declared. */
|
|
1595
1699
|
containers: string;
|
|
1596
1700
|
crons: string;
|
|
@@ -1725,4 +1829,4 @@ declare const LUNORA_SOLUTION_RULES: ReadonlyArray<LunoraSolutionRule>;
|
|
|
1725
1829
|
*/
|
|
1726
1830
|
declare const findLunoraSolution: (message: string) => LunoraSolution | undefined;
|
|
1727
1831
|
declare const VERSION = "0.0.0";
|
|
1728
|
-
export { type AuthApiCallIR, CONTAINERS_FILENAME, CodegenDiagnosticError, type CodegenOptions, type CodegenResult, type ContainerIR, type CronJobIR, type DriftChange, type EmitAppOptions, FLAGS_FILENAME, type FieldSnapshot, type FlagsIR, type FunctionIR, GENERATED_HEADER, type HttpRouteIR, type IndexIR, type IndexSnapshot, type InsertWriteIR, LUNORA_ERROR_CODES, LUNORA_SOLUTION_RULES, type LunoraSolution, type LunoraSolutionRule, type MaskProcedureIR, type MigrationIR, OPENRPC_VERSION, type OpenApiEmitInput, type OpenRpcEmitInput, type ProjectIR, QUEUES_FILENAME, type QueryReadIR, type QueueIR, type R2sqlCallIR, type RelationSnapshot, type RlsMetadataIR, type RlsPolicyIR, type RlsProcedureIR, type RlsRoleIR, SCHEMA_SNAPSHOT_FILENAME, SCHEMA_SNAPSHOT_VERSION, type SchemaDrift, type SchemaDriftDecision, type SchemaIR, type SchemaSnapshot, SchemaSnapshotParseError, type StorageRuleIR, type StorageRulesMetadataIR, type TableIR, type TableSnapshot, VERSION, type ValidatorIR, type VectorIndexIR, WORKFLOWS_FILENAME, type WorkflowIR, buildOpenApiDocument, buildOpenRpcDocument, buildSchemaSnapshot, createCodegenProject, diagnosticAt, diffSchemaSnapshots, discoverAuthApiCalls, discoverContainers, discoverCrons, discoverFlags, discoverFunctions, discoverHttpRoutes, discoverInserts, discoverMaskProcedures, discoverMigrations, discoverNondeterministicCalls, discoverQueries, discoverQueues, discoverR2sqlCalls, discoverRlsMetadata, discoverRlsProcedures, discoverSchema, discoverStorageRulesMetadata, discoverWorkflows, emitApi, emitApp, emitContainers, emitCrons, emitDataModel, emitDrizzleSchema, emitFunctions, emitOpenApi, emitOpenApiModule, emitOpenRpc, emitOpenRpcModule, emitServer, emitShard, emitVectors, emitWorkflows, emitWranglerCronTriggers, evaluateSchemaDrift, findLunoraSolution, formatAdvisories, lintSchema, parseSchemaSnapshot, refreshCodegenProject, runCodegen, schemaFromIr, serializeSchemaSnapshot, validatorIrToJsonSchema };
|
|
1832
|
+
export { type AuthApiCallIR, CONTAINERS_FILENAME, CodegenDiagnosticError, type CodegenOptions, type CodegenResult, type ContainerIR, type CronJobIR, type DriftChange, type EmitAppOptions, FLAGS_FILENAME, type FieldSnapshot, type FlagsIR, type FunctionIR, GENERATED_HEADER, type HttpRouteIR, type IndexIR, type IndexSnapshot, type InsertWriteIR, LUNORA_ERROR_CODES, LUNORA_SOLUTION_RULES, type LunoraSolution, type LunoraSolutionRule, MUTATORS_FILENAME, type MaskProcedureIR, type MigrationIR, type MutatorIR, OPENRPC_VERSION, type OpenApiEmitInput, type OpenRpcEmitInput, type ProjectIR, QUEUES_FILENAME, type QueryReadIR, type QueueIR, type R2sqlCallIR, type RelationSnapshot, type RlsMetadataIR, type RlsPolicyIR, type RlsProcedureIR, type RlsRoleIR, SCHEMA_SNAPSHOT_FILENAME, SCHEMA_SNAPSHOT_VERSION, SHAPES_FILENAME, type SchemaDrift, type SchemaDriftDecision, type SchemaIR, type SchemaSnapshot, SchemaSnapshotParseError, type ShapeIR, type StorageRuleIR, type StorageRulesMetadataIR, type TableIR, type TableSnapshot, VERSION, type ValidatorIR, type VectorIndexIR, WORKFLOWS_FILENAME, type WorkflowIR, buildOpenApiDocument, buildOpenRpcDocument, buildSchemaSnapshot, createCodegenProject, diagnosticAt, diffSchemaSnapshots, discoverAuthApiCalls, discoverContainers, discoverCrons, discoverFlags, discoverFunctions, discoverHttpRoutes, discoverInserts, discoverMaskProcedures, discoverMigrations, discoverMutators, discoverNondeterministicCalls, discoverQueries, discoverQueues, discoverR2sqlCalls, discoverRlsMetadata, discoverRlsProcedures, discoverSchema, discoverShapes, discoverStorageRulesMetadata, discoverWorkflows, emitApi, emitApp, emitCollections, emitContainers, emitCrons, emitDataModel, emitDrizzleSchema, emitFunctions, emitOpenApi, emitOpenApiModule, emitOpenRpc, emitOpenRpcModule, emitServer, emitShard, emitVectors, emitWorkflows, emitWranglerCronTriggers, evaluateSchemaDrift, findLunoraSolution, formatAdvisories, lintSchema, parseSchemaSnapshot, refreshCodegenProject, runCodegen, schemaFromIr, serializeSchemaSnapshot, validatorIrToJsonSchema };
|
package/dist/index.d.ts
CHANGED
|
@@ -201,6 +201,59 @@ interface MigrationIR {
|
|
|
201
201
|
table: string;
|
|
202
202
|
}
|
|
203
203
|
/**
|
|
204
|
+
* A `defineShape({...})` declaration discovered in `lunora/shapes.ts`
|
|
205
|
+
* (local-first sync engine, Phase 7). The emitted `LUNORA_SHAPES` registry keys
|
|
206
|
+
* on {@link ShapeIR.exportName}; the generated DO's `resolveShape` override
|
|
207
|
+
* dispatches a `shape_subscribe` to the matching registered shape. Discovery is
|
|
208
|
+
* marker-driven (the `__lunoraShape` brand) — no field metadata is lifted here
|
|
209
|
+
* because the runtime object (`columns`/`compileWhere`) carries the authority.
|
|
210
|
+
*/
|
|
211
|
+
interface ShapeIR {
|
|
212
|
+
/** Export binding name — the shape's registry key and import member. */
|
|
213
|
+
exportName: string;
|
|
214
|
+
/** Path relative to `<projectRoot>/lunora/` without extension — always `"shapes"`. */
|
|
215
|
+
filePath: string;
|
|
216
|
+
/**
|
|
217
|
+
* The `table` string literal from the `defineShape({ table })` call, lifted
|
|
218
|
+
* only for static advisor lints (the runtime object stays authoritative).
|
|
219
|
+
* `undefined` when `table` is not a plain string literal — lints skip those.
|
|
220
|
+
*/
|
|
221
|
+
table?: string;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* A `defineMutator({...})` declaration discovered in `lunora/mutators.ts`
|
|
225
|
+
* (local-first sync engine, Phase 7). The emitted registry registers the
|
|
226
|
+
* authoritative `server` impl into the DO's `LUNORA_FUNCTIONS` table (so
|
|
227
|
+
* `handleRpc` transaction-wraps it) and records its path in
|
|
228
|
+
* `LUNORA_MUTATOR_PATHS` so the DO's `isCustomMutator` override routes the
|
|
229
|
+
* client-watermark push protocol. The client `client` impl is split into the
|
|
230
|
+
* browser bundle separately — only the path crosses to the server side.
|
|
231
|
+
*/
|
|
232
|
+
interface MutatorIR {
|
|
233
|
+
/** Export binding name — the mutator's registry key and import member. */
|
|
234
|
+
exportName: string;
|
|
235
|
+
/** Path relative to `<projectRoot>/lunora/` without extension — always `"mutators"`. */
|
|
236
|
+
filePath: string;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* A whole-row `ctx.db.replace(id, document)` write discovered inside a custom
|
|
240
|
+
* mutator's inline `server` impl (`lunora/mutators.ts`) — the input the
|
|
241
|
+
* `mutator_full_row_replace` advisor lint consumes. A `replace` overwrites the
|
|
242
|
+
* entire row, so a concurrent edit to a different column on a synced table is
|
|
243
|
+
* clobbered; `ctx.db.patch(id, { field })` merges at the column level instead.
|
|
244
|
+
* Structurally identical to `AdvisorMutatorWrite` so it passes straight through
|
|
245
|
+
* to the advisor without conversion, exactly as `InsertWriteIR` does for
|
|
246
|
+
* `AdvisorInsertWrite`.
|
|
247
|
+
*/
|
|
248
|
+
interface MutatorWriteIR {
|
|
249
|
+
/** The mutator export whose `server` impl performs the replace, e.g. `renameChannel`. */
|
|
250
|
+
exportName: string;
|
|
251
|
+
/** Openable source path the replace appears in — always `lunora/mutators.ts`. */
|
|
252
|
+
file: string;
|
|
253
|
+
/** 1-based line of the `replace(...)` call. */
|
|
254
|
+
line: number;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
204
257
|
* A single cron job lifted from a `cronJobs()` builder in `lunora/crons.ts`.
|
|
205
258
|
* Mirrors `@lunora/scheduler`'s `CronJob`: {@link CronJobIR.cron} is the compiled
|
|
206
259
|
* standard cron expression, {@link CronJobIR.functionPath} is the target
|
|
@@ -783,7 +836,7 @@ interface ProjectIR {
|
|
|
783
836
|
* pass straight through without conversion. Returns the findings; surfacing them
|
|
784
837
|
* (console, error overlay, studio Advisors table) is the caller's choice.
|
|
785
838
|
*/
|
|
786
|
-
declare const lintSchema: (schema: SchemaIR, queries?: ReadonlyArray<QueryReadIR>, inserts?: ReadonlyArray<InsertWriteIR>, authApiCalls?: ReadonlyArray<AuthApiCallIR>, rlsProcedures?: ReadonlyArray<RlsProcedureIR>, containers?: ReadonlyArray<ContainerIR>, workflows?: ReadonlyArray<WorkflowIR>, workflowCalls?: ReadonlyArray<WorkflowCallIR>, maskProcedures?: ReadonlyArray<MaskProcedureIR>, nondeterministicCalls?: ReadonlyArray<NondeterministicCallIR>, procedureProtections?: ReadonlyArray<ProcedureMiddlewareIR>, argumentValidators?: ReadonlyArray<ArgumentValidatorIR>, secretLiterals?: ReadonlyArray<SecretLiteralIR>, sqlInterpolations?: ReadonlyArray<SqlInterpolationIR>, adminRoutes?: ReadonlyArray<AdminRouteIR>, r2sqlCalls?: ReadonlyArray<R2sqlCallIR>) => Finding[];
|
|
839
|
+
declare const lintSchema: (schema: SchemaIR, queries?: ReadonlyArray<QueryReadIR>, inserts?: ReadonlyArray<InsertWriteIR>, authApiCalls?: ReadonlyArray<AuthApiCallIR>, rlsProcedures?: ReadonlyArray<RlsProcedureIR>, containers?: ReadonlyArray<ContainerIR>, workflows?: ReadonlyArray<WorkflowIR>, workflowCalls?: ReadonlyArray<WorkflowCallIR>, maskProcedures?: ReadonlyArray<MaskProcedureIR>, nondeterministicCalls?: ReadonlyArray<NondeterministicCallIR>, procedureProtections?: ReadonlyArray<ProcedureMiddlewareIR>, argumentValidators?: ReadonlyArray<ArgumentValidatorIR>, secretLiterals?: ReadonlyArray<SecretLiteralIR>, sqlInterpolations?: ReadonlyArray<SqlInterpolationIR>, adminRoutes?: ReadonlyArray<AdminRouteIR>, r2sqlCalls?: ReadonlyArray<R2sqlCallIR>, shapes?: ReadonlyArray<ShapeIR>, mutatorWrites?: ReadonlyArray<MutatorWriteIR>) => Finding[];
|
|
787
840
|
/**
|
|
788
841
|
* Render advisor findings as a single multi-line string for console surfacing:
|
|
789
842
|
* a one-line summary header followed by one `[LEVEL] name: detail` line per
|
|
@@ -898,6 +951,23 @@ declare const discoverMaskProcedures: (project: Project, lunoraDirectory: string
|
|
|
898
951
|
* key); `table` is best-effort and left `""` when not a literal.
|
|
899
952
|
*/
|
|
900
953
|
declare const discoverMigrations: (project: Project, lunoraDirectory: string) => MigrationIR[];
|
|
954
|
+
/** The only file custom mutators may be declared in — mirrors `lunora/queues.ts`. */
|
|
955
|
+
declare const MUTATORS_FILENAME = "mutators.ts";
|
|
956
|
+
/**
|
|
957
|
+
* Decide whether a call's callee is `defineMutator` — either the bare imported
|
|
958
|
+
* identifier (`defineMutator(...)`) or a namespace member access
|
|
959
|
+
* (`server.defineMutator(...)`). Both are valid ES module syntax, so discovery
|
|
960
|
+
* must see mutators declared either way.
|
|
961
|
+
*/
|
|
962
|
+
|
|
963
|
+
/**
|
|
964
|
+
* Discover every custom mutator the project declares: exported
|
|
965
|
+
* `defineMutator()` calls in `lunora/mutators.ts`. Returns `[]` when the file
|
|
966
|
+
* doesn't exist. Only the export binding is lifted — the runtime object carries
|
|
967
|
+
* the authoritative `server` impl + `handler`, so codegen never evaluates the
|
|
968
|
+
* body. The client `client` impl is split into the browser bundle separately.
|
|
969
|
+
*/
|
|
970
|
+
declare const discoverMutators: (project: Project, lunoraDirectory: string) => MutatorIR[];
|
|
901
971
|
/**
|
|
902
972
|
* Discover non-deterministic API calls (`Date.now`, `new Date()`, `Date()`,
|
|
903
973
|
* `Math.random`, `crypto.randomUUID`, `crypto.getRandomValues` — including
|
|
@@ -963,6 +1033,16 @@ declare const discoverRlsMetadata: (project: Project, lunoraDirectory: string) =
|
|
|
963
1033
|
* return a structural IR. Throws if the file or call cannot be found.
|
|
964
1034
|
*/
|
|
965
1035
|
declare const discoverSchema: (project: Project, schemaPath: string, projectRoot?: string) => SchemaIR;
|
|
1036
|
+
/** The only file shapes may be declared in — mirrors `lunora/queues.ts`. */
|
|
1037
|
+
declare const SHAPES_FILENAME = "shapes.ts";
|
|
1038
|
+
/**
|
|
1039
|
+
* Discover every replication shape the project declares: exported
|
|
1040
|
+
* `defineShape()` calls in `lunora/shapes.ts`. Returns `[]` when the file
|
|
1041
|
+
* doesn't exist. Only the export binding is lifted — the runtime object carries
|
|
1042
|
+
* the authoritative `table`/`columns`/`compileWhere`, so codegen never
|
|
1043
|
+
* evaluates the predicate.
|
|
1044
|
+
*/
|
|
1045
|
+
declare const discoverShapes: (project: Project, lunoraDirectory: string) => ShapeIR[];
|
|
966
1046
|
/**
|
|
967
1047
|
* Aggregate the schema-wide storage-rule metadata the studio's inspector reads:
|
|
968
1048
|
* every statically-discovered `(bucket, on, prefix, procedure)` entry across all
|
|
@@ -1001,6 +1081,22 @@ declare const emitApi: (functions: ReadonlyArray<FunctionIR>, workflows?: Readon
|
|
|
1001
1081
|
* Returns `""` when `@lunora/seed` is not a declared dependency, so projects
|
|
1002
1082
|
* that don't use it keep a clean `_generated/` and never import the package.
|
|
1003
1083
|
*/
|
|
1084
|
+
|
|
1085
|
+
/**
|
|
1086
|
+
* Emit `_generated/collections.ts` — one TanStack DB collection factory per
|
|
1087
|
+
* `defineShape` in `lunora/shapes.ts` (the local-first partial-replication
|
|
1088
|
+
* surface). Each factory builds a live collection that syncs its shape's rowset
|
|
1089
|
+
* through the client's poke protocol (`subscribeShape`), so an app feeds the
|
|
1090
|
+
* result straight to `useLiveQuery`.
|
|
1091
|
+
*
|
|
1092
|
+
* Returns `""` (so `writeIfPresent` skips the file) unless the project both
|
|
1093
|
+
* declares shapes AND installs `@lunora/db` — the add-on that ships
|
|
1094
|
+
* `lunoraCollectionOptions`. `@lunora/db` stays a scoped install even under the
|
|
1095
|
+
* `lunorash` umbrella (an opt-in add-on, like `@lunora/auth`), so its import is
|
|
1096
|
+
* always `@lunora/db/collections`; only the in-umbrella `@lunora/client` import
|
|
1097
|
+
* is remapped to `lunorash/client`.
|
|
1098
|
+
*/
|
|
1099
|
+
declare const emitCollections: (shapes: ReadonlyArray<ShapeIR>, hasDatabase: boolean, useUmbrella?: boolean) => string;
|
|
1004
1100
|
interface EmitServerOptions {
|
|
1005
1101
|
containers?: ReadonlyArray<ContainerIR>;
|
|
1006
1102
|
hasAi?: boolean;
|
|
@@ -1047,7 +1143,7 @@ declare const emitServer: ({
|
|
|
1047
1143
|
useUmbrella,
|
|
1048
1144
|
workflows
|
|
1049
1145
|
}?: EmitServerOptions) => string;
|
|
1050
|
-
declare const emitFunctions: (functions: ReadonlyArray<FunctionIR>, migrations?: ReadonlyArray<MigrationIR>, useUmbrella?: boolean) => string;
|
|
1146
|
+
declare const emitFunctions: (functions: ReadonlyArray<FunctionIR>, migrations?: ReadonlyArray<MigrationIR>, useUmbrella?: boolean, mutators?: ReadonlyArray<MutatorIR>, shapes?: ReadonlyArray<ShapeIR>) => string;
|
|
1051
1147
|
/**
|
|
1052
1148
|
* Storage-column map per table for the file browser: `{ table: [field, …] }` for
|
|
1053
1149
|
* every field declared `v.storage(...)` (unwrapping `v.optional(...)`). The
|
|
@@ -1110,10 +1206,14 @@ interface EmitShardOptions {
|
|
|
1110
1206
|
/** A `lunora/` source reads `ctx.r2sql` (R2 SQL) — wires `ctx.r2sql` onto the ActionCtx only. */
|
|
1111
1207
|
hasR2sql?: boolean;
|
|
1112
1208
|
maskMetadata?: MaskMetadataIR;
|
|
1209
|
+
/** Custom mutators declared via `defineMutator` in `lunora/mutators.ts` — wires the `isCustomMutator` push-protocol override. */
|
|
1210
|
+
mutators?: ReadonlyArray<MutatorIR>;
|
|
1113
1211
|
/** Queues declared via `defineQueue` exports in `lunora/queues.ts` — wires the typed `ctx.queues` producers. */
|
|
1114
1212
|
queues?: ReadonlyArray<QueueIR>;
|
|
1115
1213
|
rlsMetadata?: RlsMetadataIR;
|
|
1116
1214
|
schema: SchemaIR;
|
|
1215
|
+
/** Replication shapes declared via `defineShape` in `lunora/shapes.ts` — wires the `resolveShape` subscription override. */
|
|
1216
|
+
shapes?: ReadonlyArray<ShapeIR>;
|
|
1117
1217
|
storageRules?: StorageRulesMetadataIR;
|
|
1118
1218
|
studioFeatures?: StudioFeaturesResult;
|
|
1119
1219
|
/** The project depends on the `lunora` umbrella — import base packages via its subpaths. */
|
|
@@ -1135,9 +1235,11 @@ declare const emitShard: ({
|
|
|
1135
1235
|
hasPipelines,
|
|
1136
1236
|
hasR2sql,
|
|
1137
1237
|
maskMetadata,
|
|
1238
|
+
mutators,
|
|
1138
1239
|
queues,
|
|
1139
1240
|
rlsMetadata,
|
|
1140
1241
|
schema,
|
|
1242
|
+
shapes,
|
|
1141
1243
|
storageRules,
|
|
1142
1244
|
studioFeatures,
|
|
1143
1245
|
useUmbrella,
|
|
@@ -1591,6 +1693,8 @@ interface CodegenResult {
|
|
|
1591
1693
|
generated: {
|
|
1592
1694
|
api: string; /** Fluent worker-composition builder (`_generated/app.ts`) — `defineApp()`. Always written. */
|
|
1593
1695
|
app: string;
|
|
1696
|
+
/** Partial-replication collection factories (`_generated/collections.ts`); `""` (and not written) unless the project declares shapes and installs `@lunora/db`. */
|
|
1697
|
+
collections: string;
|
|
1594
1698
|
/** Container DO classes (`_generated/containers.ts`); `""` (and not written) when no containers are declared. */
|
|
1595
1699
|
containers: string;
|
|
1596
1700
|
crons: string;
|
|
@@ -1725,4 +1829,4 @@ declare const LUNORA_SOLUTION_RULES: ReadonlyArray<LunoraSolutionRule>;
|
|
|
1725
1829
|
*/
|
|
1726
1830
|
declare const findLunoraSolution: (message: string) => LunoraSolution | undefined;
|
|
1727
1831
|
declare const VERSION = "0.0.0";
|
|
1728
|
-
export { type AuthApiCallIR, CONTAINERS_FILENAME, CodegenDiagnosticError, type CodegenOptions, type CodegenResult, type ContainerIR, type CronJobIR, type DriftChange, type EmitAppOptions, FLAGS_FILENAME, type FieldSnapshot, type FlagsIR, type FunctionIR, GENERATED_HEADER, type HttpRouteIR, type IndexIR, type IndexSnapshot, type InsertWriteIR, LUNORA_ERROR_CODES, LUNORA_SOLUTION_RULES, type LunoraSolution, type LunoraSolutionRule, type MaskProcedureIR, type MigrationIR, OPENRPC_VERSION, type OpenApiEmitInput, type OpenRpcEmitInput, type ProjectIR, QUEUES_FILENAME, type QueryReadIR, type QueueIR, type R2sqlCallIR, type RelationSnapshot, type RlsMetadataIR, type RlsPolicyIR, type RlsProcedureIR, type RlsRoleIR, SCHEMA_SNAPSHOT_FILENAME, SCHEMA_SNAPSHOT_VERSION, type SchemaDrift, type SchemaDriftDecision, type SchemaIR, type SchemaSnapshot, SchemaSnapshotParseError, type StorageRuleIR, type StorageRulesMetadataIR, type TableIR, type TableSnapshot, VERSION, type ValidatorIR, type VectorIndexIR, WORKFLOWS_FILENAME, type WorkflowIR, buildOpenApiDocument, buildOpenRpcDocument, buildSchemaSnapshot, createCodegenProject, diagnosticAt, diffSchemaSnapshots, discoverAuthApiCalls, discoverContainers, discoverCrons, discoverFlags, discoverFunctions, discoverHttpRoutes, discoverInserts, discoverMaskProcedures, discoverMigrations, discoverNondeterministicCalls, discoverQueries, discoverQueues, discoverR2sqlCalls, discoverRlsMetadata, discoverRlsProcedures, discoverSchema, discoverStorageRulesMetadata, discoverWorkflows, emitApi, emitApp, emitContainers, emitCrons, emitDataModel, emitDrizzleSchema, emitFunctions, emitOpenApi, emitOpenApiModule, emitOpenRpc, emitOpenRpcModule, emitServer, emitShard, emitVectors, emitWorkflows, emitWranglerCronTriggers, evaluateSchemaDrift, findLunoraSolution, formatAdvisories, lintSchema, parseSchemaSnapshot, refreshCodegenProject, runCodegen, schemaFromIr, serializeSchemaSnapshot, validatorIrToJsonSchema };
|
|
1832
|
+
export { type AuthApiCallIR, CONTAINERS_FILENAME, CodegenDiagnosticError, type CodegenOptions, type CodegenResult, type ContainerIR, type CronJobIR, type DriftChange, type EmitAppOptions, FLAGS_FILENAME, type FieldSnapshot, type FlagsIR, type FunctionIR, GENERATED_HEADER, type HttpRouteIR, type IndexIR, type IndexSnapshot, type InsertWriteIR, LUNORA_ERROR_CODES, LUNORA_SOLUTION_RULES, type LunoraSolution, type LunoraSolutionRule, MUTATORS_FILENAME, type MaskProcedureIR, type MigrationIR, type MutatorIR, OPENRPC_VERSION, type OpenApiEmitInput, type OpenRpcEmitInput, type ProjectIR, QUEUES_FILENAME, type QueryReadIR, type QueueIR, type R2sqlCallIR, type RelationSnapshot, type RlsMetadataIR, type RlsPolicyIR, type RlsProcedureIR, type RlsRoleIR, SCHEMA_SNAPSHOT_FILENAME, SCHEMA_SNAPSHOT_VERSION, SHAPES_FILENAME, type SchemaDrift, type SchemaDriftDecision, type SchemaIR, type SchemaSnapshot, SchemaSnapshotParseError, type ShapeIR, type StorageRuleIR, type StorageRulesMetadataIR, type TableIR, type TableSnapshot, VERSION, type ValidatorIR, type VectorIndexIR, WORKFLOWS_FILENAME, type WorkflowIR, buildOpenApiDocument, buildOpenRpcDocument, buildSchemaSnapshot, createCodegenProject, diagnosticAt, diffSchemaSnapshots, discoverAuthApiCalls, discoverContainers, discoverCrons, discoverFlags, discoverFunctions, discoverHttpRoutes, discoverInserts, discoverMaskProcedures, discoverMigrations, discoverMutators, discoverNondeterministicCalls, discoverQueries, discoverQueues, discoverR2sqlCalls, discoverRlsMetadata, discoverRlsProcedures, discoverSchema, discoverShapes, discoverStorageRulesMetadata, discoverWorkflows, emitApi, emitApp, emitCollections, emitContainers, emitCrons, emitDataModel, emitDrizzleSchema, emitFunctions, emitOpenApi, emitOpenApiModule, emitOpenRpc, emitOpenRpcModule, emitServer, emitShard, emitVectors, emitWorkflows, emitWranglerCronTriggers, evaluateSchemaDrift, findLunoraSolution, formatAdvisories, lintSchema, parseSchemaSnapshot, refreshCodegenProject, runCodegen, schemaFromIr, serializeSchemaSnapshot, validatorIrToJsonSchema };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { formatAdvisories, lintSchema } from './packem_shared/formatAdvisories-
|
|
1
|
+
export { formatAdvisories, lintSchema } from './packem_shared/formatAdvisories-LM8-Ixjw.mjs';
|
|
2
2
|
export { CodegenDiagnosticError, diagnosticAt } from './packem_shared/CodegenDiagnosticError-DeblMkzO.mjs';
|
|
3
3
|
export { default as discoverAuthApiCalls } from './packem_shared/discoverAuthApiCalls-CoirYbg6.mjs';
|
|
4
4
|
export { CONTAINERS_FILENAME, discoverContainers } from './packem_shared/CONTAINERS_FILENAME-DlP6YM_Q.mjs';
|
|
@@ -9,19 +9,21 @@ export { default as discoverHttpRoutes } from './packem_shared/discoverHttpRoute
|
|
|
9
9
|
export { default as discoverInserts } from './packem_shared/discoverInserts-C7zxXkUf.mjs';
|
|
10
10
|
export { default as discoverMaskProcedures } from './packem_shared/discoverMaskProcedures-Cm81kwrb.mjs';
|
|
11
11
|
export { default as discoverMigrations } from './packem_shared/discoverMigrations-Bi5nJ0mJ.mjs';
|
|
12
|
+
export { MUTATORS_FILENAME, discoverMutators } from './packem_shared/MUTATORS_FILENAME-BhqdPtKp.mjs';
|
|
12
13
|
export { default as discoverNondeterministicCalls } from './packem_shared/discoverNondeterministicCalls-C4M8AXmQ.mjs';
|
|
13
14
|
export { default as discoverQueries } from './packem_shared/discoverQueries-B0wGT-xe.mjs';
|
|
14
15
|
export { QUEUES_FILENAME, discoverQueues } from './packem_shared/QUEUES_FILENAME-B5_eWCRe.mjs';
|
|
15
16
|
export { default as discoverR2sqlCalls } from './packem_shared/discoverR2sqlCalls-BVNMd428.mjs';
|
|
16
17
|
export { discoverRlsMetadata, default as discoverRlsProcedures } from './packem_shared/discoverRlsMetadata-BS9GOGC5.mjs';
|
|
17
18
|
export { default as discoverSchema } from './packem_shared/discoverSchema-BnWHHJ4T.mjs';
|
|
19
|
+
export { SHAPES_FILENAME, discoverShapes } from './packem_shared/SHAPES_FILENAME-ChV7MqgE.mjs';
|
|
18
20
|
export { default as discoverStorageRulesMetadata } from './packem_shared/discoverStorageRulesMetadata-Da8BKXcI.mjs';
|
|
19
21
|
export { WORKFLOWS_FILENAME, discoverWorkflows } from './packem_shared/WORKFLOWS_FILENAME-D62dcBGg.mjs';
|
|
20
|
-
export { GENERATED_HEADER, emitApi, emitContainers, emitCrons, emitDataModel, emitDrizzleSchema, emitFunctions, emitServer, emitShard, emitVectors, emitWorkflows, emitWranglerCronTriggers } from './packem_shared/GENERATED_HEADER-
|
|
21
|
-
export { emitApp } from './packem_shared/emitApp-
|
|
22
|
-
export { buildOpenApiDocument, emitOpenApi, emitOpenApiModule } from './packem_shared/buildOpenApiDocument-
|
|
23
|
-
export { OPENRPC_VERSION, buildOpenRpcDocument, emitOpenRpc, emitOpenRpcModule } from './packem_shared/OPENRPC_VERSION-
|
|
24
|
-
export { SCHEMA_SNAPSHOT_FILENAME, createCodegenProject, refreshCodegenProject, runCodegen } from './packem_shared/SCHEMA_SNAPSHOT_FILENAME-
|
|
22
|
+
export { GENERATED_HEADER, emitApi, emitCollections, emitContainers, emitCrons, emitDataModel, emitDrizzleSchema, emitFunctions, emitServer, emitShard, emitVectors, emitWorkflows, emitWranglerCronTriggers } from './packem_shared/GENERATED_HEADER-BoVKLcnE.mjs';
|
|
23
|
+
export { emitApp } from './packem_shared/emitApp-Bh0HsQVK.mjs';
|
|
24
|
+
export { buildOpenApiDocument, emitOpenApi, emitOpenApiModule } from './packem_shared/buildOpenApiDocument-CB2brlbc.mjs';
|
|
25
|
+
export { OPENRPC_VERSION, buildOpenRpcDocument, emitOpenRpc, emitOpenRpcModule } from './packem_shared/OPENRPC_VERSION-BMCOe3B6.mjs';
|
|
26
|
+
export { SCHEMA_SNAPSHOT_FILENAME, createCodegenProject, refreshCodegenProject, runCodegen } from './packem_shared/SCHEMA_SNAPSHOT_FILENAME-BA9tjjOl.mjs';
|
|
25
27
|
export { SCHEMA_SNAPSHOT_VERSION, SchemaSnapshotParseError, buildSchemaSnapshot, diffSchemaSnapshots, evaluateSchemaDrift, parseSchemaSnapshot, serializeSchemaSnapshot } from './packem_shared/SCHEMA_SNAPSHOT_VERSION-wWGP2_5E.mjs';
|
|
26
28
|
export { schemaFromIr } from './packem_shared/schemaFromIr-DTYsLBaA.mjs';
|
|
27
29
|
export { LUNORA_ERROR_CODES, validatorIrToJsonSchema } from './packem_shared/LUNORA_ERROR_CODES-CySpQPD3.mjs';
|
|
@@ -600,6 +600,26 @@ import type { InsertModel } from "./dataModel.js";
|
|
|
600
600
|
export const createSeedClient = (options?: SeedClientOptions): SeedClient<InsertModel> => createSeedClientBase<InsertModel>(schema, options);
|
|
601
601
|
`;
|
|
602
602
|
};
|
|
603
|
+
const emitCollections = (shapes, hasDatabase, useUmbrella = false) => {
|
|
604
|
+
if (shapes.length === 0 || !hasDatabase) {
|
|
605
|
+
return "";
|
|
606
|
+
}
|
|
607
|
+
const base = baseSpecifiers(useUmbrella);
|
|
608
|
+
const factories = shapes.map((shape) => {
|
|
609
|
+
assertIdentifier(shape.exportName, "shape export name");
|
|
610
|
+
return `/** Live collection for the \`${shape.exportName}\` replication shape — pass the shape's validated \`args\` (its partition selector). */
|
|
611
|
+
export const ${shape.exportName}Collection = (client: LunoraClient, args?: Record<string, unknown>): Collection<Row, string> =>
|
|
612
|
+
createCollection(lunoraCollectionOptions({ client, shape: { args, name: "${shape.exportName}" } }).config);`;
|
|
613
|
+
}).join("\n\n");
|
|
614
|
+
return `${GENERATED_HEADER}import type { LunoraClient } from "${base.client}";
|
|
615
|
+
import { lunoraCollectionOptions } from "@lunora/db/collections";
|
|
616
|
+
import type { Row } from "@lunora/db";
|
|
617
|
+
import type { Collection } from "@tanstack/db";
|
|
618
|
+
import { createCollection } from "@tanstack/db";
|
|
619
|
+
|
|
620
|
+
${factories}
|
|
621
|
+
`;
|
|
622
|
+
};
|
|
603
623
|
const moduleAlias = (filePath, index) => `lunora_${sanitizeNamespace(filePath)}_${String(index)}`;
|
|
604
624
|
const CALL_REGISTERED_HELPER = `const callRegistered = async <R>(context: CallerCtx, functionPath: string, args: Record<string, unknown> | undefined): Promise<R> => {
|
|
605
625
|
const registered = LUNORA_FUNCTIONS[functionPath];
|
|
@@ -614,7 +634,7 @@ const CALL_REGISTERED_HELPER = `const callRegistered = async <R>(context: Caller
|
|
|
614
634
|
|
|
615
635
|
return (await registered.handler(context, args ?? {})) as R;
|
|
616
636
|
};`;
|
|
617
|
-
const renderFunctionRegistry = (functions, migrations) => {
|
|
637
|
+
const renderFunctionRegistry = (functions, migrations, mutators = [], shapes = []) => {
|
|
618
638
|
const aliasByPath = /* @__PURE__ */ new Map();
|
|
619
639
|
const registerPath = (filePath) => {
|
|
620
640
|
if (!aliasByPath.has(filePath)) {
|
|
@@ -627,6 +647,12 @@ const renderFunctionRegistry = (functions, migrations) => {
|
|
|
627
647
|
for (const migration of migrations) {
|
|
628
648
|
registerPath(migration.filePath);
|
|
629
649
|
}
|
|
650
|
+
for (const mutator of mutators) {
|
|
651
|
+
registerPath(mutator.filePath);
|
|
652
|
+
}
|
|
653
|
+
for (const shape of shapes) {
|
|
654
|
+
registerPath(shape.filePath);
|
|
655
|
+
}
|
|
630
656
|
const importLines = [...aliasByPath.entries()].map(([filePath, alias]) => {
|
|
631
657
|
if (!IMPORT_PATH_RE.test(filePath)) {
|
|
632
658
|
throw new Error(`@lunora/codegen: refusing to emit import for unsafe file path: ${JSON.stringify(filePath)}`);
|
|
@@ -639,6 +665,12 @@ const renderFunctionRegistry = (functions, migrations) => {
|
|
|
639
665
|
const migrationEntries = migrations.map(
|
|
640
666
|
(migration) => ` ${JSON.stringify(migration.id)}: ${aliasByPath.get(migration.filePath) ?? ""}.${migration.exportName} as unknown as RegisteredDataMigration,`
|
|
641
667
|
).join("\n");
|
|
668
|
+
const mutatorEntries = mutators.map(
|
|
669
|
+
(mutator) => ` "${sanitizeNamespace(mutator.filePath)}:${mutator.exportName}": ${aliasByPath.get(mutator.filePath) ?? ""}.${mutator.exportName} as unknown as RegisteredLunoraFunction,`
|
|
670
|
+
).join("\n");
|
|
671
|
+
const shapeEntries = shapes.map((shape) => ` "${shape.exportName}": ${aliasByPath.get(shape.filePath) ?? ""}.${shape.exportName} as unknown as RegisteredShape,`).join("\n");
|
|
672
|
+
const mutatorPaths = mutators.map((mutator) => `${sanitizeNamespace(mutator.filePath)}:${mutator.exportName}`);
|
|
673
|
+
const combinedDispatch = [dispatchEntries, mutatorEntries].filter((entries) => entries.length > 0).join("\n");
|
|
642
674
|
const installLines = functions.map((definition) => {
|
|
643
675
|
if (definition.lifecycle || Object.keys(definition.args).length === 0) {
|
|
644
676
|
return void 0;
|
|
@@ -651,8 +683,8 @@ const renderFunctionRegistry = (functions, migrations) => {
|
|
|
651
683
|
return `installCompiledValidatorMap(${alias}.${definition.exportName}.args, ${compiled});`;
|
|
652
684
|
}).filter((line) => line !== void 0).join("\n");
|
|
653
685
|
return {
|
|
654
|
-
dispatchBody:
|
|
655
|
-
${
|
|
686
|
+
dispatchBody: combinedDispatch.length > 0 ? `
|
|
687
|
+
${combinedDispatch}
|
|
656
688
|
` : "",
|
|
657
689
|
importBlock: importLines.length > 0 ? `${importLines}
|
|
658
690
|
|
|
@@ -660,6 +692,10 @@ ${dispatchEntries}
|
|
|
660
692
|
installBlock: installLines,
|
|
661
693
|
migrationBody: migrationEntries.length > 0 ? `
|
|
662
694
|
${migrationEntries}
|
|
695
|
+
` : "",
|
|
696
|
+
mutatorPaths,
|
|
697
|
+
shapeBody: shapeEntries.length > 0 ? `
|
|
698
|
+
${shapeEntries}
|
|
663
699
|
` : ""
|
|
664
700
|
};
|
|
665
701
|
};
|
|
@@ -984,11 +1020,30 @@ const renderLifecycleManifest = (functions) => {
|
|
|
984
1020
|
}
|
|
985
1021
|
return manifest;
|
|
986
1022
|
};
|
|
987
|
-
const emitFunctions = (functions, migrations = [], useUmbrella = false) => {
|
|
1023
|
+
const emitFunctions = (functions, migrations = [], useUmbrella = false, mutators = [], shapes = []) => {
|
|
988
1024
|
const hasFunctions = functions.length > 0;
|
|
989
1025
|
const base = baseSpecifiers(useUmbrella);
|
|
990
|
-
const { dispatchBody, importBlock, installBlock, migrationBody } = renderFunctionRegistry(functions, migrations);
|
|
1026
|
+
const { dispatchBody, importBlock, installBlock, migrationBody, mutatorPaths, shapeBody } = renderFunctionRegistry(functions, migrations, mutators, shapes);
|
|
991
1027
|
const lifecycleHooks = renderLifecycleManifest(functions);
|
|
1028
|
+
const shapeTypeImport = shapes.length > 0 ? `import type { RegisteredShape } from "${base.server}";
|
|
1029
|
+
` : "";
|
|
1030
|
+
const shapeRegistry = shapes.length > 0 ? `
|
|
1031
|
+
/**
|
|
1032
|
+
* Replication-shape registry — one entry per \`defineShape\` in \`lunora/shapes.ts\`.
|
|
1033
|
+
* The generated ShardDO's \`resolveShape\` override looks a shape up by name and
|
|
1034
|
+
* evaluates its trusted \`compileWhere(ctx, args)\` to authorize + scope a
|
|
1035
|
+
* \`shape_subscribe\` (reads-as-permissions).
|
|
1036
|
+
*/
|
|
1037
|
+
export const LUNORA_SHAPES: Record<string, RegisteredShape> = {${shapeBody}};
|
|
1038
|
+
` : "";
|
|
1039
|
+
const mutatorPathsRegistry = mutatorPaths.length > 0 ? `
|
|
1040
|
+
/**
|
|
1041
|
+
* Custom-mutator function paths — the \`LUNORA_FUNCTIONS\` keys the generated
|
|
1042
|
+
* ShardDO's \`isCustomMutator\` override routes through the client-watermark push
|
|
1043
|
+
* protocol (\`x-lunora-client-id\`/\`x-lunora-client-seq\` ordering).
|
|
1044
|
+
*/
|
|
1045
|
+
export const LUNORA_MUTATOR_PATHS: ReadonlySet<string> = new Set([${mutatorPaths.map((path) => JSON.stringify(path)).join(", ")}]);
|
|
1046
|
+
` : "";
|
|
992
1047
|
const compiledArgsImport = installBlock.length > 0 ? `import { DEFER_VALIDATION as DEFER, installCompiledValidatorMap } from "${base.values}";
|
|
993
1048
|
` : "";
|
|
994
1049
|
const compiledArgsInstall = installBlock.length > 0 ? `
|
|
@@ -1013,7 +1068,7 @@ ${caller.implementation}
|
|
|
1013
1068
|
const callRegisteredHelper = hasFunctions ? `${CALL_REGISTERED_HELPER}
|
|
1014
1069
|
|
|
1015
1070
|
` : "";
|
|
1016
|
-
return `${GENERATED_HEADER}${importBlock}${compiledArgsImport}import type { ActionCtx, MutationCtx, QueryCtx } from "./server.js";
|
|
1071
|
+
return `${GENERATED_HEADER}${importBlock}${compiledArgsImport}${shapeTypeImport}import type { ActionCtx, MutationCtx, QueryCtx } from "./server.js";
|
|
1017
1072
|
${dataModelImport}
|
|
1018
1073
|
/**
|
|
1019
1074
|
* Single registered function, narrowed to the shape \`handleRpc\` needs.
|
|
@@ -1039,7 +1094,7 @@ export interface RegisteredLunoraFunction {
|
|
|
1039
1094
|
* emits (\`api[namespace][fn].__lunoraRef === "namespace:fn"\`).
|
|
1040
1095
|
*/
|
|
1041
1096
|
export const LUNORA_FUNCTIONS: Record<string, RegisteredLunoraFunction> = {${dispatchBody}};
|
|
1042
|
-
${compiledArgsInstall}
|
|
1097
|
+
${compiledArgsInstall}${shapeRegistry}${mutatorPathsRegistry}
|
|
1043
1098
|
/**
|
|
1044
1099
|
* Connection-lifecycle manifest: the function paths the generated ShardDO
|
|
1045
1100
|
* dispatches when a client's WebSocket connects (\`connect\`) or disconnects
|
|
@@ -1910,15 +1965,19 @@ const emitShard = ({
|
|
|
1910
1965
|
hasPipelines = false,
|
|
1911
1966
|
hasR2sql = false,
|
|
1912
1967
|
maskMetadata,
|
|
1968
|
+
mutators = [],
|
|
1913
1969
|
queues = [],
|
|
1914
1970
|
rlsMetadata,
|
|
1915
1971
|
schema,
|
|
1972
|
+
shapes = [],
|
|
1916
1973
|
storageRules,
|
|
1917
1974
|
studioFeatures,
|
|
1918
1975
|
useUmbrella = false,
|
|
1919
1976
|
workflows = []
|
|
1920
1977
|
}) => {
|
|
1921
1978
|
const base = baseSpecifiers(useUmbrella);
|
|
1979
|
+
const hasMutators = mutators.length > 0;
|
|
1980
|
+
const hasShapes = shapes.length > 0;
|
|
1922
1981
|
const { build: aiBuild, configField: aiConfigField, contextField: aiContextField, stub: aiStub } = emitAiFragments(hasAi);
|
|
1923
1982
|
const kvFragments = emitKvFragments(hasKv);
|
|
1924
1983
|
const flagsFragments = emitFlagsFragments(hasFlags);
|
|
@@ -1980,15 +2039,79 @@ const emitShard = ({
|
|
|
1980
2039
|
const tableColumns = buildTableColumns(schema);
|
|
1981
2040
|
const storageColumns = buildStorageColumns(schema);
|
|
1982
2041
|
const doTypeImports = buildDoTypeImports(hasVectors, workflows.length > 0, queues.length > 0, hasFlags);
|
|
2042
|
+
if (hasShapes) {
|
|
2043
|
+
doTypeImports.push("WhereInput");
|
|
2044
|
+
}
|
|
1983
2045
|
const relationFanout = emitRelationFanout(hasGlobalTables);
|
|
2046
|
+
const shapeResolveOverride = hasShapes ? `
|
|
2047
|
+
protected override resolveShape(name: string, args: Record<string, unknown>, identity?: { identity?: Record<string, unknown>; userId?: string }): { columns?: readonly string[]; effectiveWhere?: WhereInput; global?: boolean; table: string } | undefined {
|
|
2048
|
+
const shape = LUNORA_SHAPES[name];
|
|
2049
|
+
|
|
2050
|
+
if (!shape) {
|
|
2051
|
+
return undefined;
|
|
2052
|
+
}
|
|
2053
|
+
|
|
2054
|
+
this.ensureMigrated();
|
|
2055
|
+
|
|
2056
|
+
// Trusted ctx from the socket's OWN verified identity — the client
|
|
2057
|
+
// supplies only the shape name + args; \`compileWhere\` validates the
|
|
2058
|
+
// args then runs the shape's \`where(ctx, args)\` under that identity,
|
|
2059
|
+
// so which rows replicate is a server decision (reads-as-permissions).
|
|
2060
|
+
const ctx = this.buildCtx({ functionPath: \`__shape__:\${name}\`, identity });
|
|
2061
|
+
const shapeWhere = shape.compileWhere(ctx, args) as unknown as WhereInput;
|
|
2062
|
+
|
|
2063
|
+
// AND-compose with the table's RLS read base-where. A shape runs no
|
|
2064
|
+
// procedure, so the \`.use(rls(...))\` middleware never fires; without
|
|
2065
|
+
// this merge its reads would bypass every read policy on the table
|
|
2066
|
+
// (rows the caller can't see would replicate). \`composeShapeReadWhere\`
|
|
2067
|
+
// evaluates the table's read policies under this same trusted ctx —
|
|
2068
|
+
// exactly the request-time path — and fails closed under a
|
|
2069
|
+
// \`.rls("required")\` schema for a non-\`.public()\`, policy-less table.
|
|
2070
|
+
const effectiveWhere = composeShapeReadWhere(LUNORA_RLS_READ_REGISTRY, {
|
|
2071
|
+
ctx,
|
|
2072
|
+
identity: identity?.identity ?? null,
|
|
2073
|
+
rlsRequired: (schema as unknown as { rlsMode?: string }).rlsMode === "required",
|
|
2074
|
+
roles: (ctx as { auth?: { roles?: readonly string[] } }).auth?.roles ?? [],
|
|
2075
|
+
shapeWhere,
|
|
2076
|
+
table: shape.table,
|
|
2077
|
+
tablePublic: (schema as unknown as { tables: Record<string, { isPublic?: boolean }> }).tables[shape.table]?.isPublic === true,
|
|
2078
|
+
userId: identity?.userId ?? null,
|
|
2079
|
+
});
|
|
2080
|
+
|
|
2081
|
+
// A live shape pokes only from its OWN shard's op-log, so a \`where()\`
|
|
2082
|
+
// that joins to a \`.shardBy()\` table (rows in another DO) is rejected
|
|
2083
|
+
// here — the first point the compiled predicate + shard modes are both
|
|
2084
|
+
// known. Remedy: denormalize, or move the joined table to \`.global()\`.
|
|
2085
|
+
assertShapeShardable(effectiveWhere, schema as unknown as SchemaLike, shape.table);
|
|
2086
|
+
|
|
2087
|
+
// A \`.global()\` table lives in D1 (no per-DO op-log): flag it so the
|
|
2088
|
+
// base serves it through the latency-tiered poll path (\`readGlobalShapeRows\`)
|
|
2089
|
+
// instead of the CDC poke path.
|
|
2090
|
+
const isGlobal = (schema as unknown as SchemaLike).tables[shape.table]?.shardMode?.kind === "global";
|
|
2091
|
+
|
|
2092
|
+
return { columns: shape.columns, effectiveWhere, global: isGlobal, table: shape.table };
|
|
2093
|
+
}
|
|
2094
|
+
` : "";
|
|
2095
|
+
const customMutatorOverride = hasMutators ? `
|
|
2096
|
+
protected override isCustomMutator(functionPath: string): boolean {
|
|
2097
|
+
return LUNORA_MUTATOR_PATHS.has(functionPath);
|
|
2098
|
+
}
|
|
2099
|
+
` : "";
|
|
2100
|
+
const shapeReadRegistryConst = hasShapes ? `
|
|
2101
|
+
/** Per-table RLS read policies (hoisted from \`.use(rls(...))\` chains) the shape resolver AND-merges into each \`defineShape\` predicate so partial replication honours read policies. */
|
|
2102
|
+
const LUNORA_RLS_READ_REGISTRY = buildRlsReadRegistry(Object.values(LUNORA_FUNCTIONS));
|
|
2103
|
+
` : "";
|
|
2104
|
+
const shapeGuardImport = hasShapes ? "assertShapeShardable, " : "";
|
|
1984
2105
|
const importLines = [
|
|
1985
2106
|
`import type { ${doTypeImports.join(", ")} } from "${base.do}";`,
|
|
1986
|
-
`import { applyCdcChanges, createShardCtxDb, runDataMigration, runShardMigrations, ${relationFanout.importFragment}ShardDO as ShardDOBase } from "${base.do}";`,
|
|
2107
|
+
`import { applyCdcChanges, ${shapeGuardImport}createShardCtxDb, runDataMigration, runShardMigrations, ${relationFanout.importFragment}ShardDO as ShardDOBase } from "${base.do}";`,
|
|
1987
2108
|
// `asBucketStorage` (the bucket-aware `ctx.storage` wrapper) and
|
|
1988
2109
|
// `createSecrets` (the `ctx.secrets` core built-in) live in
|
|
1989
2110
|
// `@lunora/server`, the single source — imported here rather than stamped
|
|
1990
|
-
// inline into every generated shard.
|
|
1991
|
-
|
|
2111
|
+
// inline into every generated shard. With shapes, also pull the RLS
|
|
2112
|
+
// read-registry builder + `composeShapeReadWhere` so `resolveShape` can
|
|
2113
|
+
// AND-merge a shape's predicate with the table's read base-where.
|
|
2114
|
+
hasShapes ? `import { asBucketStorage, buildRlsReadRegistry, composeShapeReadWhere, createSecrets } from "${base.server}";` : `import { asBucketStorage, createSecrets } from "${base.server}";`
|
|
1992
2115
|
];
|
|
1993
2116
|
if (hasTables) {
|
|
1994
2117
|
importLines.push(`import { bindOrm, bindTableFacade } from "${base.server}";`);
|
|
@@ -2017,7 +2140,9 @@ const emitShard = ({
|
|
|
2017
2140
|
...paymentsImports,
|
|
2018
2141
|
``,
|
|
2019
2142
|
`import schema from "../schema.js";`,
|
|
2020
|
-
|
|
2143
|
+
// Local-first sync registries are pulled in alongside the function table
|
|
2144
|
+
// only when the project declares them, so the import list stays minimal.
|
|
2145
|
+
`import { ${["LUNORA_FUNCTIONS", "LUNORA_LIFECYCLE_HOOKS", "LUNORA_MIGRATIONS", ...hasMutators ? ["LUNORA_MUTATOR_PATHS"] : [], ...hasShapes ? ["LUNORA_SHAPES"] : []].join(", ")} } from "./functions.js";`
|
|
2021
2146
|
);
|
|
2022
2147
|
const vectorsConfigField = hasVectors ? `
|
|
2023
2148
|
vectors?: (env: Record<string, unknown>) => Record<string, VectorizeIndexLike>;` : "";
|
|
@@ -2142,6 +2267,37 @@ const vectorsStub: VectorSearchLike = {
|
|
|
2142
2267
|
const bindTableHelper = "";
|
|
2143
2268
|
const globalDatabaseThunk = hasHyperdriveGlobal ? "config.hyperdriveGlobal" : "config.d1";
|
|
2144
2269
|
const globalDatabaseLine = hasGlobalTables ? ` const globalDb: DatabaseWriterLike = ${globalDatabaseThunk}?.(env, { identity, userId }) ?? globalDbStub;
|
|
2270
|
+
` : "";
|
|
2271
|
+
const globalShapeReaderOverride = hasShapes && hasGlobalTables ? `
|
|
2272
|
+
protected override async readGlobalShapeRows(resolved: { columns?: readonly string[]; effectiveWhere?: WhereInput; global?: boolean; table: string }, identity?: { identity?: Record<string, unknown>; userId?: string }): Promise<Array<{ doc: Record<string, unknown>; id: string }>> {
|
|
2273
|
+
const env = this.env as Record<string, unknown>;
|
|
2274
|
+
const globalDb: DatabaseWriterLike = ${globalDatabaseThunk}?.(env, identity) ?? globalDbStub;
|
|
2275
|
+
const rows: Array<{ doc: Record<string, unknown>; id: string }> = [];
|
|
2276
|
+
|
|
2277
|
+
let cursor: null | string = null;
|
|
2278
|
+
|
|
2279
|
+
// Drain every page of the global membership so the seed/diff sees the
|
|
2280
|
+
// full rowset (D1 \`findMany\` is paginated). Stop one row past the cap:
|
|
2281
|
+
// a broad \`.global()\` shape would otherwise materialize an unbounded
|
|
2282
|
+
// array before the caller's \`withinGlobalShapeBound\` check rejects it,
|
|
2283
|
+
// so bail early and let the caller fail it closed.
|
|
2284
|
+
do {
|
|
2285
|
+
// eslint-disable-next-line no-await-in-loop -- sequential page drain to assemble the full membership
|
|
2286
|
+
const page = await globalDb.findMany(resolved.table, { cursor, where: resolved.effectiveWhere });
|
|
2287
|
+
|
|
2288
|
+
for (const doc of page.page) {
|
|
2289
|
+
rows.push({ doc, id: String((doc as { _id?: unknown })._id) });
|
|
2290
|
+
|
|
2291
|
+
if (rows.length > ShardDOBase.GLOBAL_SHAPE_MAX_ROWS) {
|
|
2292
|
+
return rows;
|
|
2293
|
+
}
|
|
2294
|
+
}
|
|
2295
|
+
|
|
2296
|
+
cursor = page.isDone ? null : page.continueCursor;
|
|
2297
|
+
} while (cursor !== null);
|
|
2298
|
+
|
|
2299
|
+
return rows;
|
|
2300
|
+
}
|
|
2145
2301
|
` : "";
|
|
2146
2302
|
const facadeBlock = hasTables ? `
|
|
2147
2303
|
const facade = db as unknown as Record<string, ReturnType<typeof bindTableFacade>>;
|
|
@@ -2211,7 +2367,7 @@ const LUNORA_STORAGE_RULES: StorageRulesResult = ${JSON.stringify(storageRulesDa
|
|
|
2211
2367
|
|
|
2212
2368
|
/** Which optional package-backed features this app wires up (discovered from imports / \`ctx.*\` reads / schema signals) served via \`__lunora_admin__:studioFeatures\` so the studio hides nav pages whose package isn't enabled. */
|
|
2213
2369
|
const LUNORA_STUDIO_FEATURES: StudioFeaturesResult = ${JSON.stringify(studioFeaturesData, void 0, 4)};
|
|
2214
|
-
${flagsOverrides.constant}${workflowsMetadataConst}${queuesMetadataConst}${containerSpecs}${workflowSpecs}${queueSpecs}
|
|
2370
|
+
${flagsOverrides.constant}${shapeReadRegistryConst}${workflowsMetadataConst}${queuesMetadataConst}${containerSpecs}${workflowSpecs}${queueSpecs}
|
|
2215
2371
|
export interface ShardDOConfig {
|
|
2216
2372
|
/** Opt into change-data-capture: records a post-image to \`__cdc_log\` on every write (backs streaming export + replay-PITR). */
|
|
2217
2373
|
cdc?: boolean;
|
|
@@ -2326,8 +2482,20 @@ export const createShardDO = (config: ShardDOConfig = {}): new (state: ShardDOSt
|
|
|
2326
2482
|
// do external I/O that can't be rolled back, so both dispatch directly.
|
|
2327
2483
|
// \`ctx.run*\` composition runs inside this span (it never re-enters
|
|
2328
2484
|
// handleRpc); runInTransaction's own guard rejects accidental nesting.
|
|
2485
|
+
//
|
|
2486
|
+
// The replay bookkeeping (idempotency dedup row + custom-mutator
|
|
2487
|
+
// watermark advance) commits INSIDE this span via
|
|
2488
|
+
// \`commitMutationBookkeeping\`, so the writes, the dedup row, and the
|
|
2489
|
+
// watermark are atomic — a crash can't leave the writes durable without
|
|
2490
|
+
// the replay guard.
|
|
2329
2491
|
if (registered.kind === "mutation") {
|
|
2330
|
-
return this.runInTransaction(() =>
|
|
2492
|
+
return this.runInTransaction(async () => {
|
|
2493
|
+
const result = await registered.handler(ctx, args);
|
|
2494
|
+
|
|
2495
|
+
this.commitMutationBookkeeping(result);
|
|
2496
|
+
|
|
2497
|
+
return result;
|
|
2498
|
+
});
|
|
2331
2499
|
}
|
|
2332
2500
|
|
|
2333
2501
|
return registered.handler(ctx, args);
|
|
@@ -2365,7 +2533,7 @@ ${relationFanout.override}
|
|
|
2365
2533
|
iterator: (signal) => (registered.handler as (context: unknown, args: Record<string, unknown>, signal: AbortSignal) => AsyncIterable<unknown>)(this.buildCtx({ functionPath }), args, signal),
|
|
2366
2534
|
};
|
|
2367
2535
|
}
|
|
2368
|
-
|
|
2536
|
+
${customMutatorOverride}${shapeResolveOverride}${globalShapeReaderOverride}
|
|
2369
2537
|
protected override lifecycleHookPaths(event: "connect" | "disconnect"): readonly string[] {
|
|
2370
2538
|
return LUNORA_LIFECYCLE_HOOKS[event];
|
|
2371
2539
|
}
|
|
@@ -2941,4 +3109,4 @@ const emitWranglerCronTriggers = (crons) => {
|
|
|
2941
3109
|
return triggers;
|
|
2942
3110
|
};
|
|
2943
3111
|
|
|
2944
|
-
export { GENERATED_HEADER, buildStorageColumns, emitApi, emitContainers, emitCrons, emitDataModel, emitDrizzleSchema, emitFunctions, emitQueues, emitSeed, emitServer, emitShard, emitVectors, emitWorkflows, emitWranglerCronTriggers };
|
|
3112
|
+
export { GENERATED_HEADER, buildStorageColumns, emitApi, emitCollections, emitContainers, emitCrons, emitDataModel, emitDrizzleSchema, emitFunctions, emitQueues, emitSeed, emitServer, emitShard, emitVectors, emitWorkflows, emitWranglerCronTriggers };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { Node, SyntaxKind } from 'ts-morph';
|
|
4
|
+
import { diagnosticAt } from './CodegenDiagnosticError-DeblMkzO.mjs';
|
|
5
|
+
|
|
6
|
+
const MUTATORS_FILENAME = "mutators.ts";
|
|
7
|
+
const MUTATOR_MODULE_SPECIFIERS = /* @__PURE__ */ new Set(["@lunora/server", "lunorash/server"]);
|
|
8
|
+
const isDefineMutator = (identifier) => {
|
|
9
|
+
const symbol = identifier.getSymbol();
|
|
10
|
+
if (!symbol) {
|
|
11
|
+
return identifier.getText() === "defineMutator";
|
|
12
|
+
}
|
|
13
|
+
for (const declaration of symbol.getDeclarations()) {
|
|
14
|
+
if (!Node.isImportSpecifier(declaration)) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
if (!MUTATOR_MODULE_SPECIFIERS.has(declaration.getImportDeclaration().getModuleSpecifierValue())) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
return declaration.getNameNode().getText() === "defineMutator";
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
};
|
|
24
|
+
const isMutatorNamespaceImport = (identifier) => {
|
|
25
|
+
const symbol = identifier.getSymbol();
|
|
26
|
+
if (!symbol) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
for (const declaration of symbol.getDeclarations()) {
|
|
30
|
+
if (!Node.isNamespaceImport(declaration)) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const importDeclaration = declaration.getFirstAncestorByKind(SyntaxKind.ImportDeclaration);
|
|
34
|
+
return importDeclaration !== void 0 && MUTATOR_MODULE_SPECIFIERS.has(importDeclaration.getModuleSpecifierValue());
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
};
|
|
38
|
+
const isDefineMutatorCallee = (callee) => {
|
|
39
|
+
if (Node.isIdentifier(callee)) {
|
|
40
|
+
return isDefineMutator(callee);
|
|
41
|
+
}
|
|
42
|
+
if (Node.isPropertyAccessExpression(callee)) {
|
|
43
|
+
const object = callee.getExpression();
|
|
44
|
+
return callee.getName() === "defineMutator" && Node.isIdentifier(object) && isMutatorNamespaceImport(object);
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
};
|
|
48
|
+
const mutatorsFromSource = (source) => {
|
|
49
|
+
const mutators = [];
|
|
50
|
+
for (const declaration of source.getVariableDeclarations()) {
|
|
51
|
+
if (!declaration.isExported()) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const initializer = declaration.getInitializer();
|
|
55
|
+
if (initializer?.getKind() !== SyntaxKind.CallExpression) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const callee = initializer.getExpression();
|
|
59
|
+
if (!isDefineMutatorCallee(callee)) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const nameNode = declaration.getNameNode();
|
|
63
|
+
if (!Node.isIdentifier(nameNode)) {
|
|
64
|
+
throw diagnosticAt(nameNode, "defineMutator exports must be plain named exports (no destructuring)");
|
|
65
|
+
}
|
|
66
|
+
mutators.push({ exportName: nameNode.getText(), filePath: "mutators" });
|
|
67
|
+
}
|
|
68
|
+
return mutators;
|
|
69
|
+
};
|
|
70
|
+
const discoverMutators = (project, lunoraDirectory) => {
|
|
71
|
+
const mutatorsPath = join(lunoraDirectory, MUTATORS_FILENAME);
|
|
72
|
+
if (!existsSync(mutatorsPath)) {
|
|
73
|
+
return [];
|
|
74
|
+
}
|
|
75
|
+
const source = project.getSourceFile(mutatorsPath) ?? project.addSourceFileAtPath(mutatorsPath);
|
|
76
|
+
const mutators = mutatorsFromSource(source);
|
|
77
|
+
mutators.sort((a, b) => a.exportName.localeCompare(b.exportName));
|
|
78
|
+
return mutators;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export { MUTATORS_FILENAME, discoverMutators, isDefineMutatorCallee };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GENERATED_HEADER } from './GENERATED_HEADER-
|
|
1
|
+
import { GENERATED_HEADER } from './GENERATED_HEADER-BoVKLcnE.mjs';
|
|
2
2
|
import { s as sanitizeNamespace } from './paths-BRd6JHuF.mjs';
|
|
3
3
|
import { argsObjectSchema, LUNORA_ERROR_CODES } from './LUNORA_ERROR_CODES-CySpQPD3.mjs';
|
|
4
4
|
|
|
@@ -2,7 +2,7 @@ import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
|
2
2
|
import { join, dirname } from 'node:path';
|
|
3
3
|
import { performance } from 'node:perf_hooks';
|
|
4
4
|
import { Node, SyntaxKind, Project } from 'ts-morph';
|
|
5
|
-
import { lintSchema } from './formatAdvisories-
|
|
5
|
+
import { lintSchema } from './formatAdvisories-LM8-Ixjw.mjs';
|
|
6
6
|
import { listLunoraSourceFiles, lunoraRelativePath, classifyProcedureCall, discoverFunctions } from './discoverFunctions-BWMczzBx.mjs';
|
|
7
7
|
import discoverAuthApiCalls from './discoverAuthApiCalls-CoirYbg6.mjs';
|
|
8
8
|
import { discoverContainers } from './CONTAINERS_FILENAME-DlP6YM_Q.mjs';
|
|
@@ -12,19 +12,21 @@ import discoverHttpRoutes from './discoverHttpRoutes-CfP6cMzt.mjs';
|
|
|
12
12
|
import discoverInserts from './discoverInserts-C7zxXkUf.mjs';
|
|
13
13
|
import discoverMaskProcedures, { discoverMaskMetadata } from './discoverMaskProcedures-Cm81kwrb.mjs';
|
|
14
14
|
import discoverMigrations from './discoverMigrations-Bi5nJ0mJ.mjs';
|
|
15
|
+
import { MUTATORS_FILENAME, isDefineMutatorCallee, discoverMutators } from './MUTATORS_FILENAME-BhqdPtKp.mjs';
|
|
15
16
|
import discoverNondeterministicCalls from './discoverNondeterministicCalls-C4M8AXmQ.mjs';
|
|
16
17
|
import discoverQueries from './discoverQueries-B0wGT-xe.mjs';
|
|
17
18
|
import { discoverQueues } from './QUEUES_FILENAME-B5_eWCRe.mjs';
|
|
18
19
|
import discoverR2sqlCalls from './discoverR2sqlCalls-BVNMd428.mjs';
|
|
19
20
|
import discoverRlsProcedures, { discoverRlsMetadata } from './discoverRlsMetadata-BS9GOGC5.mjs';
|
|
20
21
|
import discoverSchema from './discoverSchema-BnWHHJ4T.mjs';
|
|
22
|
+
import { discoverShapes } from './SHAPES_FILENAME-ChV7MqgE.mjs';
|
|
21
23
|
import discoverStorageRulesMetadata from './discoverStorageRulesMetadata-Da8BKXcI.mjs';
|
|
22
24
|
import { e as enclosingExportName$1 } from './discover-ast-CT6BgBr4.mjs';
|
|
23
25
|
import { discoverWorkflows } from './WORKFLOWS_FILENAME-D62dcBGg.mjs';
|
|
24
|
-
import { buildStorageColumns, emitDataModel, emitApi, emitServer, emitFunctions, emitShard, emitContainers, emitWorkflows, emitQueues, emitCrons, emitVectors, emitDrizzleSchema, emitSeed, emitWranglerCronTriggers } from './GENERATED_HEADER-
|
|
25
|
-
import { emitApp } from './emitApp-
|
|
26
|
-
import { buildOpenApiDocument, emitOpenApiModule } from './buildOpenApiDocument-
|
|
27
|
-
import { buildOpenRpcDocument, emitOpenRpcModule } from './OPENRPC_VERSION-
|
|
26
|
+
import { buildStorageColumns, emitDataModel, emitApi, emitServer, emitFunctions, emitShard, emitCollections, emitContainers, emitWorkflows, emitQueues, emitCrons, emitVectors, emitDrizzleSchema, emitSeed, emitWranglerCronTriggers } from './GENERATED_HEADER-BoVKLcnE.mjs';
|
|
27
|
+
import { emitApp } from './emitApp-Bh0HsQVK.mjs';
|
|
28
|
+
import { buildOpenApiDocument, emitOpenApiModule } from './buildOpenApiDocument-CB2brlbc.mjs';
|
|
29
|
+
import { buildOpenRpcDocument, emitOpenRpcModule } from './OPENRPC_VERSION-BMCOe3B6.mjs';
|
|
28
30
|
import { buildSchemaSnapshot, serializeSchemaSnapshot } from './SCHEMA_SNAPSHOT_VERSION-wWGP2_5E.mjs';
|
|
29
31
|
|
|
30
32
|
const HTTP_VERBS = /* @__PURE__ */ new Set(["delete", "get", "head", "options", "patch", "post", "put"]);
|
|
@@ -329,6 +331,61 @@ const buildStudioFeatures = (usage, signals) => {
|
|
|
329
331
|
};
|
|
330
332
|
};
|
|
331
333
|
|
|
334
|
+
const isDatabaseReplaceCall = (call) => {
|
|
335
|
+
const callee = call.getExpression();
|
|
336
|
+
if (!Node.isPropertyAccessExpression(callee) || callee.getName() !== "replace") {
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
const receiver = callee.getExpression();
|
|
340
|
+
if (Node.isPropertyAccessExpression(receiver)) {
|
|
341
|
+
return receiver.getName() === "db";
|
|
342
|
+
}
|
|
343
|
+
return Node.isIdentifier(receiver) && receiver.getText() === "db";
|
|
344
|
+
};
|
|
345
|
+
const serverImplNode = (call) => {
|
|
346
|
+
const argument = call.getArguments()[0];
|
|
347
|
+
if (argument === void 0 || !Node.isObjectLiteralExpression(argument)) {
|
|
348
|
+
return void 0;
|
|
349
|
+
}
|
|
350
|
+
const property = argument.getProperty("server");
|
|
351
|
+
if (property === void 0) {
|
|
352
|
+
return void 0;
|
|
353
|
+
}
|
|
354
|
+
return Node.isPropertyAssignment(property) ? property.getInitializer() : property;
|
|
355
|
+
};
|
|
356
|
+
const exportedDefineMutatorCall = (declaration) => {
|
|
357
|
+
if (!declaration.isExported()) {
|
|
358
|
+
return void 0;
|
|
359
|
+
}
|
|
360
|
+
const initializer = declaration.getInitializer();
|
|
361
|
+
if (initializer?.getKind() !== SyntaxKind.CallExpression) {
|
|
362
|
+
return void 0;
|
|
363
|
+
}
|
|
364
|
+
const call = initializer;
|
|
365
|
+
return isDefineMutatorCallee(call.getExpression()) ? call : void 0;
|
|
366
|
+
};
|
|
367
|
+
const writesFromDeclaration = (declaration) => {
|
|
368
|
+
const call = exportedDefineMutatorCall(declaration);
|
|
369
|
+
const serverImpl = call === void 0 ? void 0 : serverImplNode(call);
|
|
370
|
+
if (serverImpl === void 0) {
|
|
371
|
+
return [];
|
|
372
|
+
}
|
|
373
|
+
const nameNode = declaration.getNameNode();
|
|
374
|
+
const exportName = Node.isIdentifier(nameNode) ? nameNode.getText() : "";
|
|
375
|
+
return serverImpl.getDescendantsOfKind(SyntaxKind.CallExpression).filter((replaceCall) => isDatabaseReplaceCall(replaceCall)).map((replaceCall) => {
|
|
376
|
+
return { exportName, file: "lunora/mutators.ts", line: replaceCall.getStartLineNumber() };
|
|
377
|
+
});
|
|
378
|
+
};
|
|
379
|
+
const mutatorWritesFromSource = (source) => source.getVariableDeclarations().flatMap((declaration) => writesFromDeclaration(declaration));
|
|
380
|
+
const discoverMutatorWrites = (project, lunoraDirectory) => {
|
|
381
|
+
const mutatorsPath = join(lunoraDirectory, MUTATORS_FILENAME);
|
|
382
|
+
if (!existsSync(mutatorsPath)) {
|
|
383
|
+
return [];
|
|
384
|
+
}
|
|
385
|
+
const source = project.getSourceFile(mutatorsPath) ?? project.addSourceFileAtPath(mutatorsPath);
|
|
386
|
+
return mutatorWritesFromSource(source);
|
|
387
|
+
};
|
|
388
|
+
|
|
332
389
|
const discoverPackageDependencies = (projectRoot) => {
|
|
333
390
|
const manifestPath = join(projectRoot, "package.json");
|
|
334
391
|
if (!existsSync(manifestPath)) {
|
|
@@ -743,6 +800,8 @@ const runCodegen = (options) => {
|
|
|
743
800
|
const functions = discoverFunctions(project, lunoraDirectory);
|
|
744
801
|
const httpRoutes = discoverHttpRoutes(project, lunoraDirectory);
|
|
745
802
|
const migrations = discoverMigrations(project, lunoraDirectory);
|
|
803
|
+
const shapes = discoverShapes(project, lunoraDirectory);
|
|
804
|
+
const mutators = discoverMutators(project, lunoraDirectory);
|
|
746
805
|
const workflows = discoverWorkflows(project, lunoraDirectory);
|
|
747
806
|
const queues = discoverQueues(project, lunoraDirectory);
|
|
748
807
|
const crons = discoverCrons(project, lunoraDirectory, workflows);
|
|
@@ -763,7 +822,9 @@ const runCodegen = (options) => {
|
|
|
763
822
|
discoverSecrets(project, lunoraDirectory),
|
|
764
823
|
discoverSqlInterpolation(project, lunoraDirectory),
|
|
765
824
|
discoverAdminRoutes(project, lunoraDirectory),
|
|
766
|
-
discoverR2sqlCalls(project, lunoraDirectory)
|
|
825
|
+
discoverR2sqlCalls(project, lunoraDirectory),
|
|
826
|
+
shapes,
|
|
827
|
+
discoverMutatorWrites(project, lunoraDirectory)
|
|
767
828
|
);
|
|
768
829
|
const rlsMetadata = discoverRlsMetadata(project, lunoraDirectory);
|
|
769
830
|
const maskMetadata = discoverMaskMetadata(project, lunoraDirectory);
|
|
@@ -812,7 +873,7 @@ const runCodegen = (options) => {
|
|
|
812
873
|
useUmbrella,
|
|
813
874
|
workflows
|
|
814
875
|
});
|
|
815
|
-
const functionsContent = emitFunctions(functions, migrations, useUmbrella);
|
|
876
|
+
const functionsContent = emitFunctions(functions, migrations, useUmbrella, mutators, shapes);
|
|
816
877
|
const shardContent = emitShard({
|
|
817
878
|
advisories,
|
|
818
879
|
containers,
|
|
@@ -828,14 +889,17 @@ const runCodegen = (options) => {
|
|
|
828
889
|
hasPipelines,
|
|
829
890
|
hasR2sql,
|
|
830
891
|
maskMetadata,
|
|
892
|
+
mutators,
|
|
831
893
|
queues,
|
|
832
894
|
rlsMetadata,
|
|
833
895
|
schema,
|
|
896
|
+
shapes,
|
|
834
897
|
storageRules: storageRulesMetadata,
|
|
835
898
|
studioFeatures,
|
|
836
899
|
useUmbrella,
|
|
837
900
|
workflows
|
|
838
901
|
});
|
|
902
|
+
const collectionsContent = emitCollections(shapes, dependencies.has("@lunora/db"), useUmbrella);
|
|
839
903
|
const containersContent = emitContainers(containers, schema.jurisdiction);
|
|
840
904
|
const workflowsContent = emitWorkflows(workflows);
|
|
841
905
|
const queuesContent = emitQueues(queues);
|
|
@@ -909,6 +973,7 @@ const runCodegen = (options) => {
|
|
|
909
973
|
writeIfPresent(join(outputDirectory, "workflows.ts"), workflowsContent);
|
|
910
974
|
writeIfPresent(join(outputDirectory, "queues.ts"), queuesContent);
|
|
911
975
|
writeIfPresent(join(outputDirectory, "seed.ts"), seedContent);
|
|
976
|
+
writeIfPresent(join(outputDirectory, "collections.ts"), collectionsContent);
|
|
912
977
|
if (wantsOpenApi) {
|
|
913
978
|
writeIfChanged(join(outputDirectory, "openapi.json"), openApiContent);
|
|
914
979
|
writeIfChanged(join(outputDirectory, "openapi.ts"), openApiModuleContent);
|
|
@@ -935,6 +1000,7 @@ const runCodegen = (options) => {
|
|
|
935
1000
|
generated: {
|
|
936
1001
|
api: apiContent,
|
|
937
1002
|
app: appContent,
|
|
1003
|
+
collections: collectionsContent,
|
|
938
1004
|
containers: containersContent,
|
|
939
1005
|
crons: cronsContent,
|
|
940
1006
|
dataModel: dataModelContent,
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { SyntaxKind, Node } from 'ts-morph';
|
|
4
|
+
import { diagnosticAt } from './CodegenDiagnosticError-DeblMkzO.mjs';
|
|
5
|
+
|
|
6
|
+
const SHAPES_FILENAME = "shapes.ts";
|
|
7
|
+
const SHAPE_MODULE_SPECIFIERS = /* @__PURE__ */ new Set(["@lunora/server", "lunorash/server"]);
|
|
8
|
+
const isDefineShape = (identifier) => {
|
|
9
|
+
const symbol = identifier.getSymbol();
|
|
10
|
+
if (!symbol) {
|
|
11
|
+
return identifier.getText() === "defineShape";
|
|
12
|
+
}
|
|
13
|
+
for (const declaration of symbol.getDeclarations()) {
|
|
14
|
+
if (!Node.isImportSpecifier(declaration)) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
if (!SHAPE_MODULE_SPECIFIERS.has(declaration.getImportDeclaration().getModuleSpecifierValue())) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
return declaration.getNameNode().getText() === "defineShape";
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
};
|
|
24
|
+
const isShapeNamespaceImport = (identifier) => {
|
|
25
|
+
const symbol = identifier.getSymbol();
|
|
26
|
+
if (!symbol) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
for (const declaration of symbol.getDeclarations()) {
|
|
30
|
+
if (!Node.isNamespaceImport(declaration)) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const importDeclaration = declaration.getFirstAncestorByKind(SyntaxKind.ImportDeclaration);
|
|
34
|
+
return importDeclaration !== void 0 && SHAPE_MODULE_SPECIFIERS.has(importDeclaration.getModuleSpecifierValue());
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
};
|
|
38
|
+
const isDefineShapeCallee = (callee) => {
|
|
39
|
+
if (Node.isIdentifier(callee)) {
|
|
40
|
+
return isDefineShape(callee);
|
|
41
|
+
}
|
|
42
|
+
if (Node.isPropertyAccessExpression(callee)) {
|
|
43
|
+
const object = callee.getExpression();
|
|
44
|
+
return callee.getName() === "defineShape" && Node.isIdentifier(object) && isShapeNamespaceImport(object);
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
};
|
|
48
|
+
const tableLiteralFrom = (call) => {
|
|
49
|
+
const [config] = call.getArguments();
|
|
50
|
+
if (!config || !Node.isObjectLiteralExpression(config)) {
|
|
51
|
+
return void 0;
|
|
52
|
+
}
|
|
53
|
+
const tableProperty = config.getProperty("table");
|
|
54
|
+
if (!tableProperty || !Node.isPropertyAssignment(tableProperty)) {
|
|
55
|
+
return void 0;
|
|
56
|
+
}
|
|
57
|
+
const value = tableProperty.getInitializer();
|
|
58
|
+
return value && Node.isStringLiteral(value) ? value.getLiteralValue() : void 0;
|
|
59
|
+
};
|
|
60
|
+
const shapesFromSource = (source) => {
|
|
61
|
+
const shapes = [];
|
|
62
|
+
for (const declaration of source.getVariableDeclarations()) {
|
|
63
|
+
if (!declaration.isExported()) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const initializer = declaration.getInitializer();
|
|
67
|
+
if (initializer?.getKind() !== SyntaxKind.CallExpression) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const callExpression = initializer;
|
|
71
|
+
const callee = callExpression.getExpression();
|
|
72
|
+
if (!isDefineShapeCallee(callee)) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const nameNode = declaration.getNameNode();
|
|
76
|
+
if (!Node.isIdentifier(nameNode)) {
|
|
77
|
+
throw diagnosticAt(nameNode, "defineShape exports must be plain named exports (no destructuring)");
|
|
78
|
+
}
|
|
79
|
+
shapes.push({ exportName: nameNode.getText(), filePath: "shapes", table: tableLiteralFrom(callExpression) });
|
|
80
|
+
}
|
|
81
|
+
return shapes;
|
|
82
|
+
};
|
|
83
|
+
const discoverShapes = (project, lunoraDirectory) => {
|
|
84
|
+
const shapesPath = join(lunoraDirectory, SHAPES_FILENAME);
|
|
85
|
+
if (!existsSync(shapesPath)) {
|
|
86
|
+
return [];
|
|
87
|
+
}
|
|
88
|
+
const source = project.getSourceFile(shapesPath) ?? project.addSourceFileAtPath(shapesPath);
|
|
89
|
+
const shapes = shapesFromSource(source);
|
|
90
|
+
shapes.sort((a, b) => a.exportName.localeCompare(b.exportName));
|
|
91
|
+
return shapes;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export { SHAPES_FILENAME, discoverShapes };
|
package/dist/packem_shared/{buildOpenApiDocument-BSoDzIn8.mjs → buildOpenApiDocument-CB2brlbc.mjs}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GENERATED_HEADER } from './GENERATED_HEADER-
|
|
1
|
+
import { GENERATED_HEADER } from './GENERATED_HEADER-BoVKLcnE.mjs';
|
|
2
2
|
import { s as sanitizeNamespace } from './paths-BRd6JHuF.mjs';
|
|
3
3
|
import { LUNORA_ERROR_CODES, objectSchema, argsObjectSchema, validatorIrToJsonSchema } from './LUNORA_ERROR_CODES-CySpQPD3.mjs';
|
|
4
4
|
|
|
@@ -31,12 +31,16 @@ const toAdvisorSchema = (schema) => {
|
|
|
31
31
|
references: relation.references,
|
|
32
32
|
table: relation.table
|
|
33
33
|
};
|
|
34
|
-
})
|
|
34
|
+
}),
|
|
35
|
+
shardKind: typeof table.shardMode === "string" ? table.shardMode : "shardBy"
|
|
35
36
|
};
|
|
36
37
|
})
|
|
37
38
|
};
|
|
38
39
|
};
|
|
39
|
-
const
|
|
40
|
+
const toAdvisorShapes = (shapes) => shapes.map((shape) => {
|
|
41
|
+
return { exportName: shape.exportName, file: `lunora/${shape.filePath}.ts`, table: shape.table };
|
|
42
|
+
});
|
|
43
|
+
const lintSchema = (schema, queries = [], inserts, authApiCalls, rlsProcedures, containers, workflows, workflowCalls, maskProcedures, nondeterministicCalls, procedureProtections, argumentValidators, secretLiterals, sqlInterpolations, adminRoutes, r2sqlCalls, shapes, mutatorWrites) => runAdvisor(
|
|
40
44
|
{
|
|
41
45
|
adminRoutes,
|
|
42
46
|
argValidators: argumentValidators,
|
|
@@ -44,6 +48,7 @@ const lintSchema = (schema, queries = [], inserts, authApiCalls, rlsProcedures,
|
|
|
44
48
|
containers,
|
|
45
49
|
inserts,
|
|
46
50
|
maskProcedures,
|
|
51
|
+
mutatorWrites,
|
|
47
52
|
nondeterministicCalls,
|
|
48
53
|
procedureProtections,
|
|
49
54
|
queries,
|
|
@@ -51,6 +56,7 @@ const lintSchema = (schema, queries = [], inserts, authApiCalls, rlsProcedures,
|
|
|
51
56
|
rlsProcedures,
|
|
52
57
|
schema: toAdvisorSchema(schema),
|
|
53
58
|
secretLiterals,
|
|
59
|
+
shapes: shapes === void 0 ? void 0 : toAdvisorShapes(shapes),
|
|
54
60
|
sqlInterpolations,
|
|
55
61
|
workflowCalls,
|
|
56
62
|
workflows
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/codegen",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.17",
|
|
4
4
|
"description": "Code generator for Lunora: emits _generated/{api,server,dataModel}.ts from your schema",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare",
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"access": "public"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@lunora/advisor": "1.0.0-alpha.
|
|
50
|
-
"@lunora/container": "1.0.0-alpha.
|
|
49
|
+
"@lunora/advisor": "1.0.0-alpha.8",
|
|
50
|
+
"@lunora/container": "1.0.0-alpha.5",
|
|
51
51
|
"@lunora/queue": "1.0.0-alpha.1",
|
|
52
52
|
"@lunora/scheduler": "1.0.0-alpha.3",
|
|
53
53
|
"@lunora/values": "1.0.0-alpha.3",
|