@prisma-next/family-mongo 0.7.0 → 0.8.0-dev.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +22 -9
  2. package/dist/control-adapter.d.mts +75 -0
  3. package/dist/control-adapter.d.mts.map +1 -0
  4. package/dist/control-adapter.mjs +1 -0
  5. package/dist/control.d.mts +60 -16
  6. package/dist/control.d.mts.map +1 -1
  7. package/dist/control.mjs +257 -276
  8. package/dist/control.mjs.map +1 -1
  9. package/dist/ir.d.mts +131 -0
  10. package/dist/ir.d.mts.map +1 -0
  11. package/dist/ir.mjs +54 -0
  12. package/dist/ir.mjs.map +1 -0
  13. package/dist/mongo-contract-serializer-Co3EaTVj.mjs +98 -0
  14. package/dist/mongo-contract-serializer-Co3EaTVj.mjs.map +1 -0
  15. package/dist/schema-verify.d.mts +22 -2
  16. package/dist/schema-verify.d.mts.map +1 -0
  17. package/dist/schema-verify.mjs +1 -1
  18. package/dist/verify-mongo-schema-BL7t9YTB.mjs +592 -0
  19. package/dist/verify-mongo-schema-BL7t9YTB.mjs.map +1 -0
  20. package/package.json +20 -22
  21. package/src/core/contract-to-schema.ts +84 -0
  22. package/src/core/control-adapter.ts +97 -0
  23. package/src/core/control-instance.ts +275 -272
  24. package/src/core/control-target-descriptor.ts +26 -0
  25. package/src/core/control-types.ts +6 -4
  26. package/src/core/ir/mongo-contract-serializer-base.ts +124 -0
  27. package/src/core/ir/mongo-contract-serializer.ts +18 -0
  28. package/src/core/ir/mongo-schema-verifier-base.ts +87 -0
  29. package/src/core/operation-preview.ts +131 -0
  30. package/src/core/schema-diff.ts +402 -0
  31. package/src/core/schema-verify/canonicalize-introspection.ts +389 -0
  32. package/src/core/schema-verify/verify-mongo-schema.ts +60 -0
  33. package/src/exports/control-adapter.ts +1 -0
  34. package/src/exports/control.ts +8 -1
  35. package/src/exports/ir.ts +3 -0
  36. package/src/exports/schema-verify.ts +4 -2
  37. package/src/core/mongo-target-descriptor.ts +0 -180
package/dist/control.mjs CHANGED
@@ -1,16 +1,90 @@
1
+ import { i as contractToMongoSchemaIR, n as canonicalizeSchemasForVerification, r as diffMongoSchemas, t as verifyMongoSchema } from "./verify-mongo-schema-BL7t9YTB.mjs";
2
+ import { t as MongoContractSerializer } from "./mongo-contract-serializer-Co3EaTVj.mjs";
1
3
  import { mongoEmission } from "@prisma-next/mongo-emitter";
2
- import { createMongoRunnerDeps, extractDb, introspectSchema } from "@prisma-next/adapter-mongo/control";
3
4
  import { APP_SPACE_ID, SchemaTreeNode, VERIFY_CODE_HASH_MISMATCH, VERIFY_CODE_MARKER_MISSING, VERIFY_CODE_TARGET_MISMATCH } from "@prisma-next/framework-components/control";
4
5
  import { assertDescriptorSelfConsistency } from "@prisma-next/migration-tools/spaces";
5
- import { validateMongoContract } from "@prisma-next/mongo-contract";
6
- import { MongoMigrationPlanner, MongoMigrationRunner, contractToMongoSchemaIR, formatMongoOperations, initMarker, readAllMarkers, readMarker, updateMarker } from "@prisma-next/target-mongo/control";
7
- import { verifyMongoSchema } from "@prisma-next/target-mongo/schema-verify";
8
6
  import { ifDefined } from "@prisma-next/utils/defined";
9
- import { MongoDriverImpl } from "@prisma-next/driver-mongo";
10
- import { projectSchemaToSpace } from "@prisma-next/migration-tools/aggregate";
11
- import { MongoSchemaIR } from "@prisma-next/mongo-schema-ir";
12
- import mongoTargetDescriptorMeta from "@prisma-next/target-mongo/pack";
13
- import { notOk, ok } from "@prisma-next/utils/result";
7
+ //#region src/core/operation-preview.ts
8
+ function formatKeySpec(keys) {
9
+ return `{ ${keys.map((k) => `${JSON.stringify(k.field)}: ${JSON.stringify(k.direction)}`).join(", ")} }`;
10
+ }
11
+ function formatOptions(cmd) {
12
+ const parts = [];
13
+ if (cmd.unique) parts.push("unique: true");
14
+ if (cmd.sparse) parts.push("sparse: true");
15
+ if (cmd.expireAfterSeconds !== void 0) parts.push(`expireAfterSeconds: ${cmd.expireAfterSeconds}`);
16
+ if (cmd.name) parts.push(`name: ${JSON.stringify(cmd.name)}`);
17
+ if (cmd.collation) parts.push(`collation: ${JSON.stringify(cmd.collation)}`);
18
+ if (cmd.weights) parts.push(`weights: ${JSON.stringify(cmd.weights)}`);
19
+ if (cmd.default_language) parts.push(`default_language: ${JSON.stringify(cmd.default_language)}`);
20
+ if (cmd.language_override) parts.push(`language_override: ${JSON.stringify(cmd.language_override)}`);
21
+ if (cmd.wildcardProjection) parts.push(`wildcardProjection: ${JSON.stringify(cmd.wildcardProjection)}`);
22
+ if (cmd.partialFilterExpression) parts.push(`partialFilterExpression: ${JSON.stringify(cmd.partialFilterExpression)}`);
23
+ if (parts.length === 0) return void 0;
24
+ return `{ ${parts.join(", ")} }`;
25
+ }
26
+ function formatCreateCollectionOptions(cmd) {
27
+ const parts = [];
28
+ if (cmd.capped) parts.push("capped: true");
29
+ if (cmd.size !== void 0) parts.push(`size: ${cmd.size}`);
30
+ if (cmd.max !== void 0) parts.push(`max: ${cmd.max}`);
31
+ if (cmd.timeseries) parts.push(`timeseries: ${JSON.stringify(cmd.timeseries)}`);
32
+ if (cmd.collation) parts.push(`collation: ${JSON.stringify(cmd.collation)}`);
33
+ if (cmd.clusteredIndex) parts.push(`clusteredIndex: ${JSON.stringify(cmd.clusteredIndex)}`);
34
+ if (cmd.validator) parts.push(`validator: ${JSON.stringify(cmd.validator)}`);
35
+ if (cmd.validationLevel) parts.push(`validationLevel: ${JSON.stringify(cmd.validationLevel)}`);
36
+ if (cmd.validationAction) parts.push(`validationAction: ${JSON.stringify(cmd.validationAction)}`);
37
+ if (cmd.changeStreamPreAndPostImages) parts.push(`changeStreamPreAndPostImages: ${JSON.stringify(cmd.changeStreamPreAndPostImages)}`);
38
+ if (parts.length === 0) return void 0;
39
+ return `{ ${parts.join(", ")} }`;
40
+ }
41
+ var MongoDdlCommandFormatter = class {
42
+ createIndex(cmd) {
43
+ const keySpec = formatKeySpec(cmd.keys);
44
+ const opts = formatOptions(cmd);
45
+ return opts ? `db.${cmd.collection}.createIndex(${keySpec}, ${opts})` : `db.${cmd.collection}.createIndex(${keySpec})`;
46
+ }
47
+ dropIndex(cmd) {
48
+ return `db.${cmd.collection}.dropIndex(${JSON.stringify(cmd.name)})`;
49
+ }
50
+ createCollection(cmd) {
51
+ const opts = formatCreateCollectionOptions(cmd);
52
+ return opts ? `db.createCollection(${JSON.stringify(cmd.collection)}, ${opts})` : `db.createCollection(${JSON.stringify(cmd.collection)})`;
53
+ }
54
+ dropCollection(cmd) {
55
+ return `db.${cmd.collection}.drop()`;
56
+ }
57
+ collMod(cmd) {
58
+ const parts = [`collMod: ${JSON.stringify(cmd.collection)}`];
59
+ if (cmd.validator) parts.push(`validator: ${JSON.stringify(cmd.validator)}`);
60
+ if (cmd.validationLevel) parts.push(`validationLevel: ${JSON.stringify(cmd.validationLevel)}`);
61
+ if (cmd.validationAction) parts.push(`validationAction: ${JSON.stringify(cmd.validationAction)}`);
62
+ if (cmd.changeStreamPreAndPostImages) parts.push(`changeStreamPreAndPostImages: ${JSON.stringify(cmd.changeStreamPreAndPostImages)}`);
63
+ return `db.runCommand({ ${parts.join(", ")} })`;
64
+ }
65
+ };
66
+ const formatter = new MongoDdlCommandFormatter();
67
+ function formatMongoOperations(operations) {
68
+ const statements = [];
69
+ for (const operation of operations) {
70
+ const candidate = operation;
71
+ if (!("execute" in candidate) || !Array.isArray(candidate["execute"])) continue;
72
+ for (const step of candidate["execute"]) if (step.command && typeof step.command.accept === "function") statements.push(step.command.accept(formatter));
73
+ }
74
+ return statements;
75
+ }
76
+ /**
77
+ * Wraps `formatMongoOperations` into the family-agnostic
78
+ * `OperationPreview` shape. Each statement carries
79
+ * `language: 'mongodb-shell'`. Mirrors `sqlOperationsToPreview`.
80
+ */
81
+ function mongoOperationsToPreview(operations) {
82
+ return { statements: formatMongoOperations(operations).map((text) => ({
83
+ text,
84
+ language: "mongodb-shell"
85
+ })) };
86
+ }
87
+ //#endregion
14
88
  //#region src/core/schema-to-view.ts
15
89
  function mongoSchemaToView(schema) {
16
90
  const collectionNodes = schema.collections.map((collection) => collectionToSchemaNode(collection.name, collection));
@@ -104,170 +178,29 @@ function collectionToSchemaNode(name, collection) {
104
178
  }
105
179
  //#endregion
106
180
  //#region src/core/control-instance.ts
107
- function extractDb$1(driver) {
108
- const mongoDriver = driver;
109
- if (!mongoDriver.db) throw new Error("Mongo control driver does not expose a db property. Use createMongoControlDriver() from @prisma-next/adapter-mongo/control.");
110
- return mongoDriver.db;
181
+ function deserializeMongoContract(contractJson) {
182
+ return new MongoContractSerializer().deserializeContract(contractJson);
183
+ }
184
+ /**
185
+ * Family-method contract input. By the time control-plane methods
186
+ * (`verify`, `verifySchema`, `sign`, …) are invoked through the CLI
187
+ * control client (`client.ts`), the input has already been threaded
188
+ * through `familyInstance.validateContract`. The value is therefore a
189
+ * class-form `MongoTargetContract` (or a structurally-equivalent
190
+ * envelope post-deserialization) and must NOT be re-fed through
191
+ * structural validation (arktype rejects extra keys like `namespaces`).
192
+ *
193
+ * The parameter type on the framework SPI is `unknown` for variance
194
+ * reasons (so the family can express its own contract type without
195
+ * leaking it to the framework). This helper recovers the validated
196
+ * shape with a single narrow cast.
197
+ */
198
+ function asValidatedMongoContract(contract) {
199
+ return contract;
200
+ }
201
+ function isMongoControlAdapter(value) {
202
+ return typeof value === "object" && value !== null && "readMarker" in value && typeof value.readMarker === "function" && "readAllMarkers" in value && typeof value.readAllMarkers === "function" && "introspectSchema" in value && typeof value.introspectSchema === "function";
111
203
  }
112
- var MongoFamilyInstance = class {
113
- familyId = "mongo";
114
- validateContract(contractJson) {
115
- return validateMongoContract(contractJson).contract;
116
- }
117
- async verify(options) {
118
- const { driver, contract: rawContract, expectedTargetId, contractPath, configPath } = options;
119
- const startTime = Date.now();
120
- const contract = validateMongoContract(rawContract).contract;
121
- const contractStorageHash = contract.storage.storageHash;
122
- const contractProfileHash = contract.profileHash;
123
- const contractTarget = contract.target;
124
- const baseOpts = {
125
- contractStorageHash,
126
- contractProfileHash,
127
- expectedTargetId,
128
- contractPath,
129
- ...ifDefined("configPath", configPath)
130
- };
131
- if (contractTarget !== expectedTargetId) return buildVerifyResult({
132
- ...baseOpts,
133
- ok: false,
134
- code: VERIFY_CODE_TARGET_MISMATCH,
135
- summary: "Target mismatch",
136
- actualTargetId: contractTarget,
137
- totalTime: Date.now() - startTime
138
- });
139
- const marker = await readMarker(extractDb$1(driver), APP_SPACE_ID);
140
- if (!marker) return buildVerifyResult({
141
- ...baseOpts,
142
- ok: false,
143
- code: VERIFY_CODE_MARKER_MISSING,
144
- summary: "Marker missing",
145
- totalTime: Date.now() - startTime
146
- });
147
- if (marker.storageHash !== contractStorageHash) return buildVerifyResult({
148
- ...baseOpts,
149
- ok: false,
150
- code: VERIFY_CODE_HASH_MISMATCH,
151
- summary: "Hash mismatch",
152
- marker,
153
- totalTime: Date.now() - startTime
154
- });
155
- if (contractProfileHash && marker.profileHash !== contractProfileHash) return buildVerifyResult({
156
- ...baseOpts,
157
- ok: false,
158
- code: VERIFY_CODE_HASH_MISMATCH,
159
- summary: "Hash mismatch",
160
- marker,
161
- totalTime: Date.now() - startTime
162
- });
163
- return buildVerifyResult({
164
- ...baseOpts,
165
- ok: true,
166
- summary: "Database matches contract",
167
- marker,
168
- totalTime: Date.now() - startTime
169
- });
170
- }
171
- async schemaVerify(options) {
172
- const { driver, contract: rawContract, strict, contractPath, configPath } = options;
173
- const contract = validateMongoContract(rawContract).contract;
174
- return verifyMongoSchema({
175
- contract,
176
- schema: await introspectSchema(extractDb$1(driver)),
177
- strict,
178
- frameworkComponents: options.frameworkComponents,
179
- context: {
180
- contractPath,
181
- ...ifDefined("configPath", configPath)
182
- }
183
- });
184
- }
185
- schemaVerifyAgainstSchema(options) {
186
- return verifyMongoSchema({
187
- contract: validateMongoContract(options.contract).contract,
188
- schema: options.schema,
189
- strict: options.strict,
190
- frameworkComponents: options.frameworkComponents
191
- });
192
- }
193
- async sign(options) {
194
- const { driver, contract: rawContract, contractPath, configPath } = options;
195
- const startTime = Date.now();
196
- const contract = validateMongoContract(rawContract).contract;
197
- const contractStorageHash = contract.storage.storageHash;
198
- const contractProfileHash = contract.profileHash;
199
- const db = extractDb$1(driver);
200
- const existingMarker = await readMarker(db, APP_SPACE_ID);
201
- let markerCreated = false;
202
- let markerUpdated = false;
203
- let previousHashes;
204
- if (!existingMarker) {
205
- await initMarker(db, APP_SPACE_ID, {
206
- storageHash: contractStorageHash,
207
- profileHash: contractProfileHash
208
- });
209
- markerCreated = true;
210
- } else {
211
- const storageHashMatches = existingMarker.storageHash === contractStorageHash;
212
- const profileHashMatches = existingMarker.profileHash === contractProfileHash;
213
- if (!storageHashMatches || !profileHashMatches) {
214
- previousHashes = {
215
- storageHash: existingMarker.storageHash,
216
- profileHash: existingMarker.profileHash
217
- };
218
- if (!await updateMarker(db, APP_SPACE_ID, existingMarker.storageHash, {
219
- storageHash: contractStorageHash,
220
- profileHash: contractProfileHash
221
- })) throw new Error("CAS conflict: marker was modified by another process during sign");
222
- markerUpdated = true;
223
- }
224
- }
225
- let summary;
226
- if (markerCreated) summary = "Database signed (marker created)";
227
- else if (markerUpdated) summary = `Database signed (marker updated from ${previousHashes?.storageHash ?? "unknown"})`;
228
- else summary = "Database already signed with this contract";
229
- return {
230
- ok: true,
231
- summary,
232
- contract: {
233
- storageHash: contractStorageHash,
234
- profileHash: contractProfileHash
235
- },
236
- target: {
237
- expected: contract.target,
238
- actual: contract.target
239
- },
240
- marker: {
241
- created: markerCreated,
242
- updated: markerUpdated,
243
- ...ifDefined("previous", previousHashes)
244
- },
245
- meta: {
246
- contractPath,
247
- ...ifDefined("configPath", configPath)
248
- },
249
- timings: { total: Date.now() - startTime }
250
- };
251
- }
252
- async readMarker(options) {
253
- return readMarker(extractDb$1(options.driver), options.space);
254
- }
255
- async readAllMarkers(options) {
256
- return readAllMarkers(extractDb$1(options.driver));
257
- }
258
- async introspect(options) {
259
- return introspectSchema(extractDb$1(options.driver));
260
- }
261
- toSchemaView(schema) {
262
- return mongoSchemaToView(schema);
263
- }
264
- toOperationPreview(operations) {
265
- return { statements: formatMongoOperations(operations).map((text) => ({
266
- text,
267
- language: "mongodb-shell"
268
- })) };
269
- }
270
- };
271
204
  function buildVerifyResult(opts) {
272
205
  return {
273
206
  ok: opts.ok,
@@ -304,7 +237,157 @@ function createMongoFamilyInstance(controlStack) {
304
237
  headRefHash: headRef.hash
305
238
  });
306
239
  }
307
- return new MongoFamilyInstance();
240
+ const adapter = controlStack.adapter;
241
+ const getControlAdapter = () => {
242
+ if (!adapter) throw new Error("Mongo family requires an adapter descriptor in ControlStack");
243
+ const controlAdapter = adapter.create(controlStack);
244
+ if (!isMongoControlAdapter(controlAdapter)) throw new Error("Adapter does not implement MongoControlAdapter (missing readMarker, readAllMarkers, or introspectSchema)");
245
+ return controlAdapter;
246
+ };
247
+ const asMongoDriver = (driver) => driver;
248
+ return {
249
+ familyId: "mongo",
250
+ validateContract(contractJson) {
251
+ return deserializeMongoContract(contractJson);
252
+ },
253
+ async verify(options) {
254
+ const { driver, contract: rawContract, expectedTargetId, contractPath, configPath } = options;
255
+ const startTime = Date.now();
256
+ const contract = asValidatedMongoContract(rawContract);
257
+ const contractStorageHash = contract.storage.storageHash;
258
+ const contractProfileHash = contract.profileHash;
259
+ const contractTarget = contract.target;
260
+ const baseOpts = {
261
+ contractStorageHash,
262
+ contractProfileHash,
263
+ expectedTargetId,
264
+ contractPath,
265
+ ...ifDefined("configPath", configPath)
266
+ };
267
+ if (contractTarget !== expectedTargetId) return buildVerifyResult({
268
+ ...baseOpts,
269
+ ok: false,
270
+ code: VERIFY_CODE_TARGET_MISMATCH,
271
+ summary: "Target mismatch",
272
+ actualTargetId: contractTarget,
273
+ totalTime: Date.now() - startTime
274
+ });
275
+ const marker = await getControlAdapter().readMarker(asMongoDriver(driver), APP_SPACE_ID);
276
+ if (!marker) return buildVerifyResult({
277
+ ...baseOpts,
278
+ ok: false,
279
+ code: VERIFY_CODE_MARKER_MISSING,
280
+ summary: "Marker missing",
281
+ totalTime: Date.now() - startTime
282
+ });
283
+ if (marker.storageHash !== contractStorageHash) return buildVerifyResult({
284
+ ...baseOpts,
285
+ ok: false,
286
+ code: VERIFY_CODE_HASH_MISMATCH,
287
+ summary: "Hash mismatch",
288
+ marker,
289
+ totalTime: Date.now() - startTime
290
+ });
291
+ if (contractProfileHash && marker.profileHash !== contractProfileHash) return buildVerifyResult({
292
+ ...baseOpts,
293
+ ok: false,
294
+ code: VERIFY_CODE_HASH_MISMATCH,
295
+ summary: "Hash mismatch",
296
+ marker,
297
+ totalTime: Date.now() - startTime
298
+ });
299
+ return buildVerifyResult({
300
+ ...baseOpts,
301
+ ok: true,
302
+ summary: "Database matches contract",
303
+ marker,
304
+ totalTime: Date.now() - startTime
305
+ });
306
+ },
307
+ verifySchema(options) {
308
+ return verifyMongoSchema({
309
+ contract: asValidatedMongoContract(options.contract),
310
+ schema: options.schema,
311
+ strict: options.strict,
312
+ frameworkComponents: options.frameworkComponents
313
+ });
314
+ },
315
+ async sign(options) {
316
+ const { driver, contract: rawContract, contractPath, configPath } = options;
317
+ const startTime = Date.now();
318
+ const contract = asValidatedMongoContract(rawContract);
319
+ const contractStorageHash = contract.storage.storageHash;
320
+ const contractProfileHash = contract.profileHash;
321
+ const controlAdapter = getControlAdapter();
322
+ const mongoDriver = asMongoDriver(driver);
323
+ const existingMarker = await controlAdapter.readMarker(mongoDriver, APP_SPACE_ID);
324
+ let markerCreated = false;
325
+ let markerUpdated = false;
326
+ let previousHashes;
327
+ if (!existingMarker) {
328
+ await controlAdapter.initMarker(mongoDriver, APP_SPACE_ID, {
329
+ storageHash: contractStorageHash,
330
+ profileHash: contractProfileHash
331
+ });
332
+ markerCreated = true;
333
+ } else {
334
+ const storageHashMatches = existingMarker.storageHash === contractStorageHash;
335
+ const profileHashMatches = existingMarker.profileHash === contractProfileHash;
336
+ if (!storageHashMatches || !profileHashMatches) {
337
+ previousHashes = {
338
+ storageHash: existingMarker.storageHash,
339
+ profileHash: existingMarker.profileHash
340
+ };
341
+ if (!await controlAdapter.updateMarker(mongoDriver, APP_SPACE_ID, existingMarker.storageHash, {
342
+ storageHash: contractStorageHash,
343
+ profileHash: contractProfileHash
344
+ })) throw new Error("CAS conflict: marker was modified by another process during sign");
345
+ markerUpdated = true;
346
+ }
347
+ }
348
+ let summary;
349
+ if (markerCreated) summary = "Database signed (marker created)";
350
+ else if (markerUpdated) summary = `Database signed (marker updated from ${previousHashes?.storageHash ?? "unknown"})`;
351
+ else summary = "Database already signed with this contract";
352
+ return {
353
+ ok: true,
354
+ summary,
355
+ contract: {
356
+ storageHash: contractStorageHash,
357
+ profileHash: contractProfileHash
358
+ },
359
+ target: {
360
+ expected: contract.target,
361
+ actual: contract.target
362
+ },
363
+ marker: {
364
+ created: markerCreated,
365
+ updated: markerUpdated,
366
+ ...ifDefined("previous", previousHashes)
367
+ },
368
+ meta: {
369
+ contractPath,
370
+ ...ifDefined("configPath", configPath)
371
+ },
372
+ timings: { total: Date.now() - startTime }
373
+ };
374
+ },
375
+ async readMarker(options) {
376
+ return getControlAdapter().readMarker(asMongoDriver(options.driver), options.space);
377
+ },
378
+ async readAllMarkers(options) {
379
+ return getControlAdapter().readAllMarkers(asMongoDriver(options.driver));
380
+ },
381
+ async introspect(options) {
382
+ return getControlAdapter().introspectSchema(asMongoDriver(options.driver));
383
+ },
384
+ toSchemaView(schema) {
385
+ return mongoSchemaToView(schema);
386
+ },
387
+ toOperationPreview(operations) {
388
+ return mongoOperationsToPreview(operations);
389
+ }
390
+ };
308
391
  }
309
392
  //#endregion
310
393
  //#region src/core/control-descriptor.ts
@@ -320,108 +403,6 @@ var MongoFamilyDescriptor = class {
320
403
  };
321
404
  const mongoFamilyDescriptor = new MongoFamilyDescriptor();
322
405
  //#endregion
323
- //#region src/core/mongo-target-descriptor.ts
324
- /**
325
- * `migration.ts` default-exports a `Migration` subclass whose `operations`
326
- * getter returns the ordered list of operations and whose `describe()`
327
- * returns the manifest identity metadata. `MongoMigrationPlanner.plan()`
328
- * returns a `MigrationPlanWithAuthoringSurface` that knows how to render
329
- * itself back to such a file; `MongoMigrationPlanner.emptyMigration()`
330
- * returns the same shape for `migration new`. Users run the scaffolded
331
- * `migration.ts` directly (via `node migration.ts`) to self-emit
332
- * `ops.json` and attest the `migrationHash`.
333
- */
334
- const mongoTargetDescriptor = {
335
- ...mongoTargetDescriptorMeta,
336
- migrations: {
337
- createPlanner(_family) {
338
- return new MongoMigrationPlanner();
339
- },
340
- createRunner(family) {
341
- let cachedDeps;
342
- const runMongo = async (driver, runnerOptions) => {
343
- cachedDeps ??= createMongoRunnerDeps(driver, MongoDriverImpl.fromDb(extractDb(driver)), family);
344
- return new MongoMigrationRunner(cachedDeps).execute({
345
- ...runnerOptions,
346
- destinationContract: runnerOptions.destinationContract
347
- });
348
- };
349
- return {
350
- async execute(options) {
351
- const { driver, ...runnerOptions } = options;
352
- return runMongo(driver, runnerOptions);
353
- },
354
- async executeAcrossSpaces({ driver, perSpaceOptions }) {
355
- const members = perSpaceOptions.map(toSpaceMember);
356
- const perSpaceResults = [];
357
- for (let i = 0; i < perSpaceOptions.length; i++) {
358
- const spaceOptions = perSpaceOptions[i];
359
- if (!spaceOptions) continue;
360
- const member = members[i];
361
- if (!member) continue;
362
- const others = members.filter((_, j) => j !== i);
363
- const projectSchema = (schema) => {
364
- return new MongoSchemaIR(projectSchemaToSpace(schema, member, others).collections);
365
- };
366
- const result = await runMongo(driver, {
367
- ...spaceOptions,
368
- projectSchema
369
- });
370
- if (!result.ok) return notOk({
371
- ...result.failure,
372
- failingSpace: spaceOptions.space
373
- });
374
- perSpaceResults.push({
375
- space: spaceOptions.space,
376
- value: result.value
377
- });
378
- }
379
- return ok({ perSpaceResults });
380
- }
381
- };
382
- },
383
- contractToSchema(contract) {
384
- return contractToMongoSchemaIR(contract);
385
- }
386
- },
387
- create() {
388
- return {
389
- familyId: "mongo",
390
- targetId: "mongo"
391
- };
392
- }
393
- };
394
- /**
395
- * Synthesise the minimum {@link projectSchemaToSpace}-compatible
396
- * `ContractSpaceMember` shape from a per-space option entry. The
397
- * projector only reads `spaceId` and `contract.storage`; the rest of
398
- * `ContractSpaceMember` (head ref invariants, hydrated migration
399
- * graph) is irrelevant at runner time and stubbed with sentinels.
400
- *
401
- * The `as unknown as ContractSpaceMember` cast is the load-bearing bit
402
- * — the projector duck-types its members so a sentinel-shaped graph
403
- * never gets read, but the framework type carries a richer shape.
404
- */
405
- function toSpaceMember(opts) {
406
- return {
407
- spaceId: opts.space,
408
- contract: opts.destinationContract,
409
- headRef: {
410
- hash: "",
411
- invariants: []
412
- },
413
- migrations: {
414
- graph: {
415
- nodes: /* @__PURE__ */ new Set(),
416
- forwardChain: /* @__PURE__ */ new Map(),
417
- reverseChain: /* @__PURE__ */ new Map(),
418
- migrationByHash: /* @__PURE__ */ new Map()
419
- },
420
- packagesByMigrationHash: /* @__PURE__ */ new Map()
421
- }
422
- };
423
- }
424
- //#endregion
425
- export { createMongoFamilyInstance, mongoFamilyDescriptor, mongoTargetDescriptor };
406
+ export { canonicalizeSchemasForVerification, contractToMongoSchemaIR, createMongoFamilyInstance, diffMongoSchemas, formatMongoOperations, mongoFamilyDescriptor, mongoOperationsToPreview };
426
407
 
427
408
  //# sourceMappingURL=control.mjs.map