@prisma-next/target-mongo 0.5.0-dev.9 → 0.5.1

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 (38) hide show
  1. package/dist/codec-types.d.mts.map +1 -1
  2. package/dist/codec-types.mjs +1 -1
  3. package/dist/control.d.mts +24 -7
  4. package/dist/control.d.mts.map +1 -1
  5. package/dist/control.mjs +150 -86
  6. package/dist/control.mjs.map +1 -1
  7. package/dist/descriptor-meta-DdXFJeK1.mjs +12 -0
  8. package/dist/descriptor-meta-DdXFJeK1.mjs.map +1 -0
  9. package/dist/{migration-factories-Dbk5afMU.mjs → migration-factories-ZBsWqXt-.mjs} +4 -3
  10. package/dist/migration-factories-ZBsWqXt-.mjs.map +1 -0
  11. package/dist/migration.d.mts +7 -1
  12. package/dist/migration.d.mts.map +1 -1
  13. package/dist/migration.mjs +2 -3
  14. package/dist/{op-factory-call-CVgzmLJh.d.mts → op-factory-call-9z5D19cP.d.mts} +1 -2
  15. package/dist/op-factory-call-9z5D19cP.d.mts.map +1 -0
  16. package/dist/pack.d.mts.map +1 -1
  17. package/dist/pack.mjs +3 -15
  18. package/dist/pack.mjs.map +1 -1
  19. package/dist/runtime.d.mts +15 -0
  20. package/dist/runtime.d.mts.map +1 -0
  21. package/dist/runtime.mjs +21 -0
  22. package/dist/runtime.mjs.map +1 -0
  23. package/dist/schema-verify.d.mts.map +1 -1
  24. package/dist/schema-verify.mjs +2 -3
  25. package/dist/{verify-mongo-schema-P0TRBJNs.mjs → verify-mongo-schema-DlPXaotB.mjs} +2 -6
  26. package/dist/verify-mongo-schema-DlPXaotB.mjs.map +1 -0
  27. package/package.json +20 -17
  28. package/src/core/marker-ledger.ts +90 -20
  29. package/src/core/migration-factories.ts +8 -0
  30. package/src/core/mongo-ops-serializer.ts +49 -9
  31. package/src/core/mongo-planner.ts +25 -4
  32. package/src/core/mongo-runner.ts +80 -57
  33. package/src/core/planner-produced-migration.ts +0 -1
  34. package/src/core/render-typescript.ts +3 -7
  35. package/src/exports/runtime.ts +32 -0
  36. package/dist/migration-factories-Dbk5afMU.mjs.map +0 -1
  37. package/dist/op-factory-call-CVgzmLJh.d.mts.map +0 -1
  38. package/dist/verify-mongo-schema-P0TRBJNs.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"codec-types.d.mts","names":[],"sources":["../src/exports/codec-types.ts"],"sourcesContent":[],"mappings":";KAAY,UAAA;EAAA,SAAA,kBAMiC,EAAA;;;;;;;;;;;;;;;;;;;;;oBAAA;qBAAuB"}
1
+ {"version":3,"file":"codec-types.d.mts","names":[],"sources":["../src/exports/codec-types.ts"],"mappings":";KAAY,UAAA;EAAA,SACD,kBAAA;IAAA,SAA+B,KAAA;IAAA,SAAwB,MAAA;EAAA;EAAA,SACvD,gBAAA;IAAA,SAA6B,KAAA;IAAA,SAAwB,MAAA;EAAA;EAAA,SACrD,gBAAA;IAAA,SAA6B,KAAA;IAAA,SAAwB,MAAA;EAAA;EAAA,SACrD,eAAA;IAAA,SAA4B,KAAA;IAAA,SAAwB,MAAA;EAAA;EAAA,SACpD,cAAA;IAAA,SAA2B,KAAA;IAAA,SAAyB,MAAA;EAAA;EAAA,SACpD,cAAA;IAAA,SAA2B,KAAA,EAAO,IAAA;IAAA,SAAe,MAAA,EAAQ,IAAA;EAAA;EAAA,SACzD,gBAAA;IAAA,SACE,KAAA;IAAA,SACA,MAAA;EAAA;AAAA"}
@@ -1 +1 @@
1
- export { };
1
+ export {};
@@ -1,11 +1,11 @@
1
- import { a as DropCollectionCall, c as schemaCollectionToCreateCollectionOptions, i as CreateIndexCall, l as schemaIndexToCreateIndexOptions, n as CollModMeta, o as DropIndexCall, r as CreateCollectionCall, s as OpFactoryCall, t as CollModCall } from "./op-factory-call-CVgzmLJh.mjs";
1
+ import { a as DropCollectionCall, c as schemaCollectionToCreateCollectionOptions, i as CreateIndexCall, l as schemaIndexToCreateIndexOptions, n as CollModMeta, o as DropIndexCall, r as CreateCollectionCall, s as OpFactoryCall, t as CollModCall } from "./op-factory-call-9z5D19cP.mjs";
2
2
  import { MongoSchemaIR } from "@prisma-next/mongo-schema-ir";
3
3
  import { MongoQueryPlan } from "@prisma-next/mongo-query-ast/execution";
4
4
  import { AnyMongoMigrationOperation, MongoAndExpr, MongoDdlCommandVisitor, MongoExistsExpr, MongoExprFilter, MongoFieldFilter, MongoFilterExpr, MongoFilterVisitor, MongoInspectionCommandVisitor, MongoMigrationPlanOperation, MongoNotExpr, MongoOrExpr } from "@prisma-next/mongo-query-ast/control";
5
5
  import { Migration, MigrationMeta } from "@prisma-next/migration-tools/migration";
6
6
  import { MigrationOperationPolicy, MigrationPlan, MigrationPlanOperation, MigrationPlanWithAuthoringSurface, MigrationPlanner, MigrationPlannerConflict, MigrationPlannerResult, MigrationRunnerExecutionChecks, MigrationRunnerResult, MigrationScaffoldContext, OperationContext } from "@prisma-next/framework-components/control";
7
7
  import { MongoContract } from "@prisma-next/mongo-contract";
8
- import { ContractMarkerRecord } from "@prisma-next/contract/types";
8
+ import { Contract, ContractMarkerRecord } from "@prisma-next/contract/types";
9
9
  import { Db } from "mongodb";
10
10
  import { TargetBoundComponentDescriptor } from "@prisma-next/framework-components/components";
11
11
  import { MongoAdapter, MongoDriver } from "@prisma-next/mongo-lowering";
@@ -33,10 +33,21 @@ declare function readMarker(db: Db): Promise<ContractMarkerRecord | null>;
33
33
  declare function initMarker(db: Db, destination: {
34
34
  readonly storageHash: string;
35
35
  readonly profileHash: string;
36
+ readonly invariants?: readonly string[];
36
37
  }): Promise<void>;
38
+ /**
39
+ * Updates the marker doc atomically (CAS on `expectedFrom`).
40
+ *
41
+ * `destination.invariants`:
42
+ * - `undefined` → existing field left untouched.
43
+ * - explicit value → merged into the existing field server-side via an
44
+ * aggregation pipeline (`$setUnion + $sortArray`), atomic at the
45
+ * document level. `[]` is a no-op merge.
46
+ */
37
47
  declare function updateMarker(db: Db, expectedFrom: string, destination: {
38
48
  readonly storageHash: string;
39
49
  readonly profileHash: string;
50
+ readonly invariants?: readonly string[];
40
51
  }): Promise<boolean>;
41
52
  declare function writeLedgerEntry(db: Db, entry: {
42
53
  readonly edgeId: string;
@@ -68,7 +79,12 @@ declare class MongoMigrationPlanner implements MigrationPlanner<'mongo', 'mongo'
68
79
  readonly contract: unknown;
69
80
  readonly schema: unknown;
70
81
  readonly policy: MigrationOperationPolicy;
71
- readonly fromHash: string;
82
+ /**
83
+ * The "from" contract (state the planner assumes the database starts at),
84
+ * or `null` for reconciliation flows. Used to populate `describe().from`
85
+ * on the produced plan as `fromContract?.storage.storageHash ?? null`.
86
+ */
87
+ readonly fromContract: Contract | null;
72
88
  readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'mongo', 'mongo'>>;
73
89
  }): MigrationPlannerResult;
74
90
  /**
@@ -89,10 +105,12 @@ interface MarkerOperations {
89
105
  initMarker(destination: {
90
106
  readonly storageHash: string;
91
107
  readonly profileHash: string;
108
+ readonly invariants?: readonly string[];
92
109
  }): Promise<void>;
93
110
  updateMarker(expectedFrom: string, destination: {
94
111
  readonly storageHash: string;
95
112
  readonly profileHash: string;
113
+ readonly invariants?: readonly string[];
96
114
  }): Promise<boolean>;
97
115
  writeLedgerEntry(entry: {
98
116
  readonly edgeId: string;
@@ -165,9 +183,8 @@ declare function renderOps(calls: ReadonlyArray<OpFactoryCall>): MongoMigrationP
165
183
  //#endregion
166
184
  //#region src/core/render-typescript.d.ts
167
185
  interface RenderMigrationMeta {
168
- readonly from: string;
186
+ readonly from: string | null;
169
187
  readonly to: string;
170
- readonly kind?: string;
171
188
  readonly labels?: readonly string[];
172
189
  }
173
190
  /**
@@ -176,8 +193,8 @@ interface RenderMigrationMeta {
176
193
  * `Migration` (i.e. `MongoMigration`) from `@prisma-next/family-mongo`, and
177
194
  * implements the abstract `operations` and `describe` members. `meta` is
178
195
  * always rendered — `describe()` is part of the `Migration` contract, so
179
- * even an empty stub must satisfy it; callers pass empty strings for a
180
- * migration-new scaffold.
196
+ * even an empty stub must satisfy it; callers pass `from: null` for a
197
+ * baseline `migration-new` scaffold (and a real `to` hash either way).
181
198
  *
182
199
  * The walk is polymorphic: each call node contributes its own
183
200
  * `renderTypeScript()` expression and declares its own
@@ -1 +1 @@
1
- {"version":3,"file":"control.d.mts","names":[],"sources":["../src/core/contract-to-schema.ts","../src/core/ddl-formatter.ts","../src/core/filter-evaluator.ts","../src/core/marker-ledger.ts","../src/core/mongo-ops-serializer.ts","../src/core/mongo-planner.ts","../src/core/mongo-runner.ts","../src/core/planner-produced-migration.ts","../src/core/render-ops.ts","../src/core/render-typescript.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"control.d.mts","names":[],"sources":["../src/core/contract-to-schema.ts","../src/core/ddl-formatter.ts","../src/core/filter-evaluator.ts","../src/core/marker-ledger.ts","../src/core/mongo-ops-serializer.ts","../src/core/mongo-planner.ts","../src/core/mongo-runner.ts","../src/core/planner-produced-migration.ts","../src/core/render-ops.ts","../src/core/render-typescript.ts"],"mappings":"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"}
package/dist/control.mjs CHANGED
@@ -1,16 +1,15 @@
1
- import { n as contractToMongoSchemaIR, t as verifyMongoSchema } from "./verify-mongo-schema-P0TRBJNs.mjs";
2
- import { a as dropCollection, n as createCollection, o as dropIndex, r as createIndex, t as collMod } from "./migration-factories-Dbk5afMU.mjs";
1
+ import { n as contractToMongoSchemaIR, t as verifyMongoSchema } from "./verify-mongo-schema-DlPXaotB.mjs";
2
+ import { a as dropCollection, n as createCollection, o as dropIndex, r as createIndex, t as collMod } from "./migration-factories-ZBsWqXt-.mjs";
3
3
  import { canonicalize, deepEqual } from "@prisma-next/mongo-schema-ir";
4
4
  import { AggregateCommand, MongoAddFieldsStage, MongoLimitStage, MongoLookupStage, MongoMatchStage, MongoMergeStage, MongoProjectStage, MongoSortStage, RawAggregateCommand, RawDeleteManyCommand, RawDeleteOneCommand, RawFindOneAndDeleteCommand, RawFindOneAndUpdateCommand, RawInsertManyCommand, RawInsertOneCommand, RawUpdateManyCommand, RawUpdateOneCommand } from "@prisma-next/mongo-query-ast/execution";
5
+ import { type } from "arktype";
5
6
  import { CollModCommand, CreateCollectionCommand, CreateIndexCommand, DropCollectionCommand, DropIndexCommand, ListCollectionsCommand, ListIndexesCommand, MongoAndExpr, MongoExistsExpr, MongoFieldFilter, MongoNotExpr, MongoOrExpr } from "@prisma-next/mongo-query-ast/control";
6
7
  import { ifDefined } from "@prisma-next/utils/defined";
7
- import { type } from "arktype";
8
8
  import { TsExpression, jsonToTsSource, renderImports } from "@prisma-next/ts-render";
9
9
  import { Migration } from "@prisma-next/migration-tools/migration";
10
10
  import { detectScaffoldRuntime, shebangLineFor } from "@prisma-next/migration-tools/migration-ts";
11
11
  import { errorRunnerFailed } from "@prisma-next/errors/execution";
12
12
  import { notOk, ok } from "@prisma-next/utils/result";
13
-
14
13
  //#region src/core/ddl-formatter.ts
15
14
  function formatKeySpec(keys) {
16
15
  return `{ ${keys.map((k) => `${JSON.stringify(k.field)}: ${JSON.stringify(k.direction)}`).join(", ")} }`;
@@ -80,7 +79,6 @@ function formatMongoOperations(operations) {
80
79
  }
81
80
  return statements;
82
81
  }
83
-
84
82
  //#endregion
85
83
  //#region src/core/filter-evaluator.ts
86
84
  function getNestedField(doc, path) {
@@ -133,11 +131,35 @@ var FilterEvaluator = class {
133
131
  throw new Error("Aggregation expression filters are not supported in migration checks");
134
132
  }
135
133
  };
136
-
137
134
  //#endregion
138
135
  //#region src/core/marker-ledger.ts
139
136
  const COLLECTION = "_prisma_migrations";
140
137
  const MARKER_ID = "marker";
138
+ const MongoMarkerDocSchema = type({
139
+ storageHash: "string",
140
+ profileHash: "string",
141
+ "contractJson?": "unknown | null",
142
+ "canonicalVersion?": "number | null",
143
+ "updatedAt?": "Date",
144
+ "appTag?": "string | null",
145
+ "meta?": type({ "[string]": "unknown" }).or("null"),
146
+ "invariants?": type("string").array(),
147
+ "+": "delete"
148
+ });
149
+ function parseMongoMarkerDoc(doc) {
150
+ const result = MongoMarkerDocSchema(doc);
151
+ if (result instanceof type.errors) throw new Error(`Invalid marker doc on ${COLLECTION}: ${result.summary}`);
152
+ return {
153
+ storageHash: result.storageHash,
154
+ profileHash: result.profileHash,
155
+ contractJson: result.contractJson ?? null,
156
+ canonicalVersion: result.canonicalVersion ?? null,
157
+ updatedAt: result.updatedAt ?? /* @__PURE__ */ new Date(),
158
+ appTag: result.appTag ?? null,
159
+ meta: result.meta ?? {},
160
+ invariants: result.invariants ?? []
161
+ };
162
+ }
141
163
  async function executeAggregate(db, cmd) {
142
164
  return db.collection(cmd.collection).aggregate(cmd.pipeline).toArray();
143
165
  }
@@ -150,15 +172,7 @@ async function executeFindOneAndUpdate(db, cmd) {
150
172
  async function readMarker(db) {
151
173
  const doc = (await executeAggregate(db, new RawAggregateCommand(COLLECTION, [{ $match: { _id: MARKER_ID } }, { $limit: 1 }])))[0];
152
174
  if (!doc) return null;
153
- return {
154
- storageHash: doc["storageHash"],
155
- profileHash: doc["profileHash"],
156
- contractJson: doc["contractJson"] ?? null,
157
- canonicalVersion: doc["canonicalVersion"] ?? null,
158
- updatedAt: doc["updatedAt"],
159
- appTag: doc["appTag"] ?? null,
160
- meta: doc["meta"] ?? {}
161
- };
175
+ return parseMongoMarkerDoc(doc);
162
176
  }
163
177
  async function initMarker(db, destination) {
164
178
  await executeInsertOne(db, new RawInsertOneCommand(COLLECTION, {
@@ -169,18 +183,36 @@ async function initMarker(db, destination) {
169
183
  canonicalVersion: null,
170
184
  updatedAt: /* @__PURE__ */ new Date(),
171
185
  appTag: null,
172
- meta: {}
186
+ meta: {},
187
+ invariants: destination.invariants ?? []
173
188
  }));
174
189
  }
190
+ /**
191
+ * Updates the marker doc atomically (CAS on `expectedFrom`).
192
+ *
193
+ * `destination.invariants`:
194
+ * - `undefined` → existing field left untouched.
195
+ * - explicit value → merged into the existing field server-side via an
196
+ * aggregation pipeline (`$setUnion + $sortArray`), atomic at the
197
+ * document level. `[]` is a no-op merge.
198
+ */
175
199
  async function updateMarker(db, expectedFrom, destination) {
176
- return await executeFindOneAndUpdate(db, new RawFindOneAndUpdateCommand(COLLECTION, {
177
- _id: MARKER_ID,
178
- storageHash: expectedFrom
179
- }, { $set: {
200
+ const setBase = {
180
201
  storageHash: destination.storageHash,
181
202
  profileHash: destination.profileHash,
182
203
  updatedAt: /* @__PURE__ */ new Date()
183
- } }, false)) !== null;
204
+ };
205
+ const update = destination.invariants === void 0 ? { $set: setBase } : [{ $set: {
206
+ ...setBase,
207
+ invariants: { $sortArray: {
208
+ input: { $setUnion: [{ $ifNull: ["$invariants", []] }, destination.invariants] },
209
+ sortBy: 1
210
+ } }
211
+ } }];
212
+ return await executeFindOneAndUpdate(db, new RawFindOneAndUpdateCommand(COLLECTION, {
213
+ _id: MARKER_ID,
214
+ storageHash: expectedFrom
215
+ }, update, false)) !== null;
184
216
  }
185
217
  async function writeLedgerEntry(db, entry) {
186
218
  await executeInsertOne(db, new RawInsertOneCommand(COLLECTION, {
@@ -191,7 +223,6 @@ async function writeLedgerEntry(db, entry) {
191
223
  appliedAt: /* @__PURE__ */ new Date()
192
224
  }));
193
225
  }
194
-
195
226
  //#endregion
196
227
  //#region src/core/mongo-ops-serializer.ts
197
228
  const CreateIndexJson = type({
@@ -320,13 +351,9 @@ const QueryPlanJson = type({
320
351
  target: "string",
321
352
  storageHash: "string",
322
353
  lane: "string",
323
- paramDescriptors: "unknown[]",
324
354
  "targetFamily?": "string",
325
355
  "profileHash?": "string",
326
- "annotations?": "Record<string, unknown>",
327
- "refs?": "Record<string, unknown>",
328
- "projection?": "Record<string, string> | string[]",
329
- "projectionTypes?": "Record<string, string>"
356
+ "annotations?": "Record<string, unknown>"
330
357
  })
331
358
  });
332
359
  const CheckJson = type({
@@ -364,7 +391,7 @@ const DataTransformOperationJson = type({
364
391
  });
365
392
  function validate(schema, data, context) {
366
393
  try {
367
- return schema.assert(data);
394
+ return schema.assert(stripUndefinedDeep(data));
368
395
  } catch (error) {
369
396
  /* v8 ignore start -- assertion libraries always throw Error instances */
370
397
  const message = error instanceof Error ? error.message : String(error);
@@ -372,6 +399,51 @@ function validate(schema, data, context) {
372
399
  throw new Error(`Invalid ${context}: ${message}`);
373
400
  }
374
401
  }
402
+ /**
403
+ * Strip `undefined`-valued properties before they reach arktype's optional-key
404
+ * assertions.
405
+ *
406
+ * Op IRs (e.g. `CreateCollectionCommand`) assign every optional field on
407
+ * every instance — fields the caller did not provide land as
408
+ * `undefined`-valued properties. arktype treats `{ foo?: 'boolean' }` as
409
+ * "key may be absent, but if present must be boolean", so the bare instance
410
+ * fails validation when it crosses the deserialize boundary in-process
411
+ * (no JSON round-trip happens between planner → runner). This helper
412
+ * recovers the JSON-round-tripped shape (undefined keys absent) without
413
+ * forcing every caller to round-trip.
414
+ *
415
+ * Returns the original value reference whenever no change is needed.
416
+ * That preserves prototype-bound payload values such as BSON wrappers
417
+ * (`ObjectId`, `Decimal128`, `Binary`, …) which embed no `undefined`
418
+ * own-enumerable properties and therefore never trigger a rebuild.
419
+ * Top-level op IRs (class instances with `undefined` optional fields)
420
+ * still get flattened to plain records as required by arktype.
421
+ */
422
+ function stripUndefinedDeep(value) {
423
+ if (Array.isArray(value)) {
424
+ let changed = false;
425
+ const next = value.map((item) => {
426
+ const stripped = stripUndefinedDeep(item);
427
+ if (stripped !== item) changed = true;
428
+ return stripped;
429
+ });
430
+ return changed ? next : value;
431
+ }
432
+ if (value === null || typeof value !== "object") return value;
433
+ const entries = Object.entries(value);
434
+ const out = {};
435
+ let changed = false;
436
+ for (const [key, val] of entries) {
437
+ if (val === void 0) {
438
+ changed = true;
439
+ continue;
440
+ }
441
+ const stripped = stripUndefinedDeep(val);
442
+ if (stripped !== val) changed = true;
443
+ out[key] = stripped;
444
+ }
445
+ return changed ? out : value;
446
+ }
375
447
  function deserializeFilterExpr(json) {
376
448
  const record = json;
377
449
  const kind = record["kind"];
@@ -490,13 +562,9 @@ function deserializeMongoQueryPlan(json) {
490
562
  target: m.target,
491
563
  storageHash: m.storageHash,
492
564
  lane: m.lane,
493
- paramDescriptors: m.paramDescriptors,
494
565
  ...ifDefined("targetFamily", m.targetFamily),
495
566
  ...ifDefined("profileHash", m.profileHash),
496
- ...ifDefined("annotations", m.annotations),
497
- ...ifDefined("refs", m.refs),
498
- ...ifDefined("projection", m.projection),
499
- ...ifDefined("projectionTypes", m.projectionTypes)
567
+ ...ifDefined("annotations", m.annotations)
500
568
  };
501
569
  return {
502
570
  collection: data.collection,
@@ -625,7 +693,6 @@ function deserializeMongoOps(json) {
625
693
  function serializeMongoOps(ops) {
626
694
  return JSON.stringify(ops, null, 2);
627
695
  }
628
-
629
696
  //#endregion
630
697
  //#region src/core/op-factory-call.ts
631
698
  const TARGET_MIGRATION_MODULE = "@prisma-next/target-mongo/migration";
@@ -780,13 +847,11 @@ function schemaCollectionToCreateCollectionOptions(coll) {
780
847
  changeStreamPreAndPostImages: opts?.changeStreamPreAndPostImages
781
848
  };
782
849
  }
783
-
784
850
  //#endregion
785
851
  //#region src/core/render-ops.ts
786
852
  function renderOps(calls) {
787
853
  return calls.map((call) => call.toOp());
788
854
  }
789
-
790
855
  //#endregion
791
856
  //#region src/core/render-typescript.ts
792
857
  /**
@@ -818,8 +883,8 @@ const BASE_IMPORTS = [{
818
883
  * `Migration` (i.e. `MongoMigration`) from `@prisma-next/family-mongo`, and
819
884
  * implements the abstract `operations` and `describe` members. `meta` is
820
885
  * always rendered — `describe()` is part of the `Migration` contract, so
821
- * even an empty stub must satisfy it; callers pass empty strings for a
822
- * migration-new scaffold.
886
+ * even an empty stub must satisfy it; callers pass `from: null` for a
887
+ * baseline `migration-new` scaffold (and a real `to` hash either way).
823
888
  *
824
889
  * The walk is polymorphic: each call node contributes its own
825
890
  * `renderTypeScript()` expression and declares its own
@@ -861,7 +926,6 @@ function buildDescribeMethod(meta) {
861
926
  lines.push(" return {");
862
927
  lines.push(` from: ${JSON.stringify(meta.from)},`);
863
928
  lines.push(` to: ${JSON.stringify(meta.to)},`);
864
- if (meta.kind) lines.push(` kind: ${JSON.stringify(meta.kind)},`);
865
929
  if (meta.labels && meta.labels.length > 0) lines.push(` labels: ${jsonToTsSource(meta.labels)},`);
866
930
  lines.push(" };");
867
931
  lines.push(" }");
@@ -872,7 +936,6 @@ function indent(text, spaces) {
872
936
  const pad = " ".repeat(spaces);
873
937
  return text.split("\n").map((line) => line.trim() ? `${pad}${line}` : line).join("\n");
874
938
  }
875
-
876
939
  //#endregion
877
940
  //#region src/core/planner-produced-migration.ts
878
941
  /**
@@ -892,6 +955,8 @@ function indent(text, spaces) {
892
955
  * cycle.
893
956
  */
894
957
  var PlannerProducedMongoMigration = class extends Migration {
958
+ calls;
959
+ meta;
895
960
  targetId = "mongo";
896
961
  constructor(calls, meta) {
897
962
  super();
@@ -908,12 +973,10 @@ var PlannerProducedMongoMigration = class extends Migration {
908
973
  return renderCallsToTypeScript(this.calls, {
909
974
  from: this.meta.from,
910
975
  to: this.meta.to,
911
- ...ifDefined("kind", this.meta.kind),
912
976
  ...ifDefined("labels", this.meta.labels)
913
977
  });
914
978
  }
915
979
  };
916
-
917
980
  //#endregion
918
981
  //#region src/core/mongo-planner.ts
919
982
  function buildIndexLookupKey(index) {
@@ -973,8 +1036,8 @@ var MongoMigrationPlanner = class {
973
1036
  const originColl = originIR.collection(collName);
974
1037
  const destColl = destinationIR.collection(collName);
975
1038
  if (!originColl) {
976
- if (destColl && collectionHasOptions(destColl)) {
977
- const opts = schemaCollectionToCreateCollectionOptions(destColl);
1039
+ if (destColl && (collectionHasOptions(destColl) || destColl.indexes.length === 0)) {
1040
+ const opts = collectionHasOptions(destColl) ? schemaCollectionToCreateCollectionOptions(destColl) : void 0;
978
1041
  collCreates.push(new CreateCollectionCall(collName, opts));
979
1042
  }
980
1043
  } else if (!destColl) collDrops.push(new DropCollectionCall(collName));
@@ -1030,7 +1093,7 @@ var MongoMigrationPlanner = class {
1030
1093
  return {
1031
1094
  kind: "success",
1032
1095
  plan: new PlannerProducedMongoMigration(result.calls, {
1033
- from: options.fromHash,
1096
+ from: options.fromContract?.storage.storageHash ?? null,
1034
1097
  to: contract.storage.storageHash
1035
1098
  })
1036
1099
  };
@@ -1086,7 +1149,6 @@ function planMutableOptionsDiffCall(collName, origin, dest) {
1086
1149
  operationClass: desiredCSPPI.enabled ? "widening" : "destructive"
1087
1150
  });
1088
1151
  }
1089
-
1090
1152
  //#endregion
1091
1153
  //#region src/core/mongo-runner.ts
1092
1154
  const READ_ONLY_CHECK_COMMAND_KINDS = new Set(["aggregate", "rawAggregate"]);
@@ -1098,6 +1160,7 @@ function runnerFailure(code, summary, opts) {
1098
1160
  });
1099
1161
  }
1100
1162
  var MongoMigrationRunner = class {
1163
+ deps;
1101
1164
  constructor(deps) {
1102
1165
  this.deps = deps;
1103
1166
  }
@@ -1142,40 +1205,44 @@ var MongoMigrationRunner = class {
1142
1205
  }
1143
1206
  const destination = options.plan.destination;
1144
1207
  const profileHash = options.destinationContract.profileHash ?? destination.storageHash;
1145
- if (operationsExecuted === 0 && existingMarker?.storageHash === destination.storageHash && existingMarker.profileHash === profileHash) return ok({
1146
- operationsPlanned: operations.length,
1147
- operationsExecuted
1148
- });
1149
- const liveSchema = await this.deps.introspectSchema();
1150
- const verifyResult = verifyMongoSchema({
1151
- contract: options.destinationContract,
1152
- schema: liveSchema,
1153
- strict: options.strictVerification ?? true,
1154
- frameworkComponents: options.frameworkComponents,
1155
- ...options.context ? { context: options.context } : {}
1156
- });
1157
- if (!verifyResult.ok) return runnerFailure("SCHEMA_VERIFY_FAILED", verifyResult.summary, {
1158
- why: "The resulting database schema does not satisfy the destination contract.",
1159
- meta: { issues: verifyResult.schema.issues }
1160
- });
1161
- if (existingMarker) {
1162
- if (!await markerOps.updateMarker(existingMarker.storageHash, {
1208
+ const incomingInvariants = options.plan.providedInvariants ?? [];
1209
+ const existingInvariantSet = new Set(existingMarker?.invariants ?? []);
1210
+ const incomingIsSubsetOfExisting = incomingInvariants.every((id) => existingInvariantSet.has(id));
1211
+ const markerAlreadyAtDestination = existingMarker !== null && existingMarker.storageHash === destination.storageHash && existingMarker.profileHash === profileHash;
1212
+ if (!(operationsExecuted === 0 && markerAlreadyAtDestination && incomingIsSubsetOfExisting)) {
1213
+ const liveSchema = await this.deps.introspectSchema();
1214
+ const verifyResult = verifyMongoSchema({
1215
+ contract: options.destinationContract,
1216
+ schema: liveSchema,
1217
+ strict: options.strictVerification ?? true,
1218
+ frameworkComponents: options.frameworkComponents,
1219
+ ...options.context ? { context: options.context } : {}
1220
+ });
1221
+ if (!verifyResult.ok) return runnerFailure("SCHEMA_VERIFY_FAILED", verifyResult.summary, {
1222
+ why: "The resulting database schema does not satisfy the destination contract.",
1223
+ meta: { issues: verifyResult.schema.issues }
1224
+ });
1225
+ if (existingMarker) {
1226
+ if (!await markerOps.updateMarker(existingMarker.storageHash, {
1227
+ storageHash: destination.storageHash,
1228
+ profileHash,
1229
+ invariants: incomingInvariants
1230
+ })) return runnerFailure("MARKER_CAS_FAILURE", "Marker was modified by another process during migration execution.", { meta: {
1231
+ expectedStorageHash: existingMarker.storageHash,
1232
+ destinationStorageHash: destination.storageHash
1233
+ } });
1234
+ } else await markerOps.initMarker({
1163
1235
  storageHash: destination.storageHash,
1164
- profileHash
1165
- })) return runnerFailure("MARKER_CAS_FAILURE", "Marker was modified by another process during migration execution.", { meta: {
1166
- expectedStorageHash: existingMarker.storageHash,
1167
- destinationStorageHash: destination.storageHash
1168
- } });
1169
- } else await markerOps.initMarker({
1170
- storageHash: destination.storageHash,
1171
- profileHash
1172
- });
1173
- const originHash = existingMarker?.storageHash ?? "";
1174
- await markerOps.writeLedgerEntry({
1175
- edgeId: `${originHash}->${destination.storageHash}`,
1176
- from: originHash,
1177
- to: destination.storageHash
1178
- });
1236
+ profileHash,
1237
+ invariants: incomingInvariants
1238
+ });
1239
+ const originHash = existingMarker?.storageHash ?? "";
1240
+ await markerOps.writeLedgerEntry({
1241
+ edgeId: `${originHash}->${destination.storageHash}`,
1242
+ from: originHash,
1243
+ to: destination.storageHash
1244
+ });
1245
+ }
1179
1246
  return ok({
1180
1247
  operationsPlanned: operations.length,
1181
1248
  operationsExecuted
@@ -1195,7 +1262,7 @@ var MongoMigrationRunner = class {
1195
1262
  };
1196
1263
  }
1197
1264
  for (const plan of op.run) {
1198
- const wireCommand = await adapter.lower(plan);
1265
+ const wireCommand = await adapter.lower(plan, {});
1199
1266
  for await (const _ of driver.execute(wireCommand));
1200
1267
  }
1201
1268
  if (runPostchecks && op.postcheck.length > 0) {
@@ -1221,7 +1288,7 @@ var MongoMigrationRunner = class {
1221
1288
  collection: check.source.collection
1222
1289
  }
1223
1290
  });
1224
- const wireCommand = await adapter.lower(check.source);
1291
+ const wireCommand = await adapter.lower(check.source, {});
1225
1292
  let matchFound = false;
1226
1293
  for await (const row of driver.execute(wireCommand)) if (filterEvaluator.evaluate(check.filter, row)) {
1227
1294
  matchFound = true;
@@ -1254,10 +1321,7 @@ var MongoMigrationRunner = class {
1254
1321
  }
1255
1322
  ensureMarkerCompatibility(marker, plan) {
1256
1323
  const origin = plan.origin ?? null;
1257
- if (!origin) {
1258
- if (marker) return runnerFailure("MARKER_ORIGIN_MISMATCH", "Database already has a contract marker but the plan has no origin. This would silently overwrite the existing marker.", { meta: { markerStorageHash: marker.storageHash } });
1259
- return;
1260
- }
1324
+ if (!origin) return;
1261
1325
  if (!marker) return runnerFailure("MARKER_ORIGIN_MISMATCH", `Missing contract marker: expected origin storage hash ${origin.storageHash}.`, { meta: { expectedOriginStorageHash: origin.storageHash } });
1262
1326
  if (marker.storageHash !== origin.storageHash) return runnerFailure("MARKER_ORIGIN_MISMATCH", `Existing contract marker (${marker.storageHash}) does not match plan origin (${origin.storageHash}).`, { meta: {
1263
1327
  markerStorageHash: marker.storageHash,
@@ -1265,7 +1329,7 @@ var MongoMigrationRunner = class {
1265
1329
  } });
1266
1330
  }
1267
1331
  };
1268
-
1269
1332
  //#endregion
1270
1333
  export { CollModCall, CreateCollectionCall, CreateIndexCall, DropCollectionCall, DropIndexCall, FilterEvaluator, MongoMigrationPlanner, MongoMigrationRunner, PlannerProducedMongoMigration, contractToMongoSchemaIR, deserializeMongoOp, deserializeMongoOps, formatMongoOperations, initMarker, readMarker, renderCallsToTypeScript, renderOps, schemaCollectionToCreateCollectionOptions, schemaIndexToCreateIndexOptions, serializeMongoOps, updateMarker, writeLedgerEntry };
1334
+
1271
1335
  //# sourceMappingURL=control.mjs.map