@prisma-next/target-mongo 0.5.0-dev.3 → 0.5.0-dev.31

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/README.md CHANGED
@@ -14,6 +14,8 @@ MongoDB target pack for Prisma Next.
14
14
  - `./pack`: pure target pack ref used by `@prisma-next/family-mongo` and `@prisma-next/mongo-contract-ts`
15
15
  - `./codec-types`: base Mongo codec type map
16
16
  - `./migration`: factory functions (the `Migration` base class is in `@prisma-next/family-mongo/migration`)
17
+ - `./control`: `MongoMigrationRunner` and `createMongoRunnerDeps` for runtime migration execution
18
+ - `./schema-verify`: pure `verifyMongoSchema(...)` (no DB I/O); composes `contractToMongoSchemaIR` and `diffMongoSchemas` so the runner's post-apply verify step and `MongoFamilyInstance.schemaVerify` agree on "matches the contract" by construction
17
19
 
18
20
  ## Usage
19
21
 
@@ -1,10 +1,10 @@
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-BjNAcPSF.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-CVgzmLJh.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
+ import { MigrationOperationPolicy, MigrationPlan, MigrationPlanOperation, MigrationPlanWithAuthoringSurface, MigrationPlanner, MigrationPlannerConflict, MigrationPlannerResult, MigrationRunnerExecutionChecks, MigrationRunnerResult, MigrationScaffoldContext, OperationContext } from "@prisma-next/framework-components/control";
6
7
  import { MongoContract } from "@prisma-next/mongo-contract";
7
- import { MigrationOperationPolicy, MigrationPlan, MigrationPlanOperation, MigrationPlanWithAuthoringSurface, MigrationPlanner, MigrationPlannerConflict, MigrationPlannerResult, MigrationRunnerExecutionChecks, MigrationRunnerResult, MigrationScaffoldContext } from "@prisma-next/framework-components/control";
8
8
  import { ContractMarkerRecord } from "@prisma-next/contract/types";
9
9
  import { Db } from "mongodb";
10
10
  import { TargetBoundComponentDescriptor } from "@prisma-next/framework-components/components";
@@ -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,7 @@ 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
+ readonly fromHash: string | null;
72
83
  readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'mongo', 'mongo'>>;
73
84
  }): MigrationPlannerResult;
74
85
  /**
@@ -89,10 +100,12 @@ interface MarkerOperations {
89
100
  initMarker(destination: {
90
101
  readonly storageHash: string;
91
102
  readonly profileHash: string;
103
+ readonly invariants?: readonly string[];
92
104
  }): Promise<void>;
93
105
  updateMarker(expectedFrom: string, destination: {
94
106
  readonly storageHash: string;
95
107
  readonly profileHash: string;
108
+ readonly invariants?: readonly string[];
96
109
  }): Promise<boolean>;
97
110
  writeLedgerEntry(entry: {
98
111
  readonly edgeId: string;
@@ -106,21 +119,31 @@ interface MongoRunnerDependencies {
106
119
  readonly adapter: MongoAdapter;
107
120
  readonly driver: MongoDriver;
108
121
  readonly markerOps: MarkerOperations;
122
+ readonly introspectSchema: () => Promise<MongoSchemaIR>;
123
+ }
124
+ interface MongoMigrationRunnerExecuteOptions {
125
+ readonly plan: MigrationPlan;
126
+ readonly destinationContract: MongoContract;
127
+ readonly policy: MigrationOperationPolicy;
128
+ readonly callbacks?: {
129
+ onOperationStart?(op: MigrationPlanOperation): void;
130
+ onOperationComplete?(op: MigrationPlanOperation): void;
131
+ };
132
+ readonly executionChecks?: MigrationRunnerExecutionChecks;
133
+ readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'mongo', 'mongo'>>;
134
+ readonly strictVerification?: boolean;
135
+ readonly context?: OperationContext;
136
+ /**
137
+ * Invariant ids contributed by this apply (the migration's `providedInvariants`).
138
+ * The runner unions these into `marker.invariants` atomically with the marker write.
139
+ * Defaults to `[]` for marker-only flows.
140
+ */
141
+ readonly invariants?: readonly string[];
109
142
  }
110
143
  declare class MongoMigrationRunner {
111
144
  private readonly deps;
112
145
  constructor(deps: MongoRunnerDependencies);
113
- execute(options: {
114
- readonly plan: MigrationPlan;
115
- readonly destinationContract: unknown;
116
- readonly policy: MigrationOperationPolicy;
117
- readonly callbacks?: {
118
- onOperationStart?(op: MigrationPlanOperation): void;
119
- onOperationComplete?(op: MigrationPlanOperation): void;
120
- };
121
- readonly executionChecks?: MigrationRunnerExecutionChecks;
122
- readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'mongo', 'mongo'>>;
123
- }): Promise<MigrationRunnerResult>;
146
+ execute(options: MongoMigrationRunnerExecuteOptions): Promise<MigrationRunnerResult>;
124
147
  private executeDataTransform;
125
148
  private evaluateDataTransformChecks;
126
149
  private evaluateChecks;
@@ -161,9 +184,8 @@ declare function renderOps(calls: ReadonlyArray<OpFactoryCall>): MongoMigrationP
161
184
  //#endregion
162
185
  //#region src/core/render-typescript.d.ts
163
186
  interface RenderMigrationMeta {
164
- readonly from: string;
187
+ readonly from: string | null;
165
188
  readonly to: string;
166
- readonly kind?: string;
167
189
  readonly labels?: readonly string[];
168
190
  }
169
191
  /**
@@ -172,8 +194,8 @@ interface RenderMigrationMeta {
172
194
  * `Migration` (i.e. `MongoMigration`) from `@prisma-next/family-mongo`, and
173
195
  * implements the abstract `operations` and `describe` members. `meta` is
174
196
  * always rendered — `describe()` is part of the `Migration` contract, so
175
- * even an empty stub must satisfy it; callers pass empty strings for a
176
- * migration-new scaffold.
197
+ * even an empty stub must satisfy it; callers pass `from: null` for a
198
+ * baseline `migration-new` scaffold (and a real `to` hash either way).
177
199
  *
178
200
  * The walk is polymorphic: each call node contributes its own
179
201
  * `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":";;;;;;;;;;;;;iBAoDgB,uBAAA,WAAkC,uBAAuB;;;iBC6CzD,qBAAA,sBAA2C;;;cC/C9C,eAAA,YAA2B;;mBAGrB,sBAAsB;cAK3B;YAKF;WAID;YAIC;eAIG;cAKD;;;;iBCjDQ,UAAA,KAAe,KAAK,QAAQ;iBAgB5B,UAAA,KAChB;;;IAEH;iBAcmB,YAAA,KAChB;;;IAGH;iBAiBmB,gBAAA,KAChB;;EHlCU,SAAA,IAAA,EAAA,MAAA;;IGoCb;;;iBC8ea,kBAAA,iBAAmC;iBAOnC,mBAAA,4BAA+C;iBAI/C,iBAAA,eAAgC;;;KC7epC,eAAA;;kBACoC;;;sBACI;;cAEvC,qBAAA,YAAiC;;;ILpD9B,SAAA,MAAA,EAAA,OAAuB;qBKwDlB;kCACa,cAAc;MAC1C;EJbU,IAAA,CAAA,OAAA,EAAA;;;qBIiIK;IHhLR,SAAA,QAAgB,EAAA,MAAA;IAGV,SAAA,mBAAA,EG+Ke,aH/Kf,CG+K6B,8BH/K7B,CAAA,OAAA,EAAA,OAAA,CAAA,CAAA;EAAsB,CAAA,CAAA,EGgLnC,sBHhLmC;EAK3B;;;;;;;;;0BGiMY,2BAA2B;;;;UCtNpC,gBAAA;gBACD,QAAQ;;;;MAIlB;;;INUU,SAAA,WAAA,EAAuB,MAAA;MMNlC;;;ILmDW,SAAA,IAAA,EAAA,MAAqB;;MK9C/B;;AJDO,UIII,uBAAA,CJJY;EAGV,SAAA,eAAA,EIES,sBJFT,CIEgC,OJFhC,CAAA,IAAA,CAAA,CAAA;EAAsB,SAAA,kBAAA,EIGV,6BJHU,CIGoB,OJHpB,CIG4B,MJH5B,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,CAAA,CAAA;EAK3B,SAAA,OAAA,EIDM,YJCN;EAKF,SAAA,MAAA,EILO,WJKP;EAID,SAAA,SAAA,EIRW,gBJQX;;AAQI,cIDF,oBAAA,CJCE;EAKD,iBAAA,IAAA;EA9B0B,WAAA,CAAA,IAAA,EIyBH,uBJzBG;EAAkB,OAAA,CAAA,OAAA,EAAA;mBI4BvC;;qBAEE;IHjDC,SAAU,SAAA,CAAA,EAAA;MAAK,gBAAA,EAAA,EAAA,EGmDT,sBHnDS,CAAA,EAAA,IAAA;MAAa,mBAAA,EAAA,EAAA,EGoDnB,sBHpDmB,CAAA,EAAA,IAAA;IAAR,CAAA;IAAO,SAAA,eAAA,CAAA,EGsDlB,8BHtDkB;IAgB3B,SAAU,mBAG7B,EGoC+B,aHpCxB,CGoCsC,8BHpCtC,CAAA,OAAA,EAAA,OAAA,CAAA,CAAA;EAcY,CAAA,CAAA,EGuBhB,OHvBgB,CGuBR,qBHnBX,CAAA;EAiBmB,QAAA,oBAAgB;;;;ECiftB,QAAA,0BAAmC;EAOnC,QAAA,yBAAmB;AAInC;;;;;;;;;;;;AJ7hBA;;;;AC6CA;;;cMzEa,6BAAA,SACH,UAAU,uCACP;ELwBA,iBAAA,KAAgB;EAGV,iBAAA,IAAA;EAAsB,SAAA,QAAA,EAAA,OAAA;EAK3B,WAAA,CAAA,KAAA,EAAA,SK3BuB,aL2BvB,EAAA,EAAA,IAAA,EK1Ba,aL0Bb;EAKF,IAAA,UAAA,CAAA,CAAA,EAAA,SK1B0B,0BL0B1B,EAAA;EAID,QAAA,CAAA,CAAA,EK1BY,aL0BZ;EAIC,gBAAA,CAAA,CAAA,EAAA,MAAA;;;;iBMpEI,SAAA,QAAiB,cAAc,iBAAiB;;;UCC/C,mBAAA;;;;;;;;;;;;ATgDjB;;;;AC6CA;;;;AC/CA;;;AAQc,iBOTE,uBAAA,CPSF,KAAA,EORL,aPQK,CORS,aPQT,CAAA,EAAA,IAAA,EOPN,mBPOM,CAAA,EAAA,MAAA"}
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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"}
package/dist/control.mjs CHANGED
@@ -1,54 +1,16 @@
1
- import { a as dropCollection, n as createCollection, o as dropIndex, r as createIndex, t as collMod } from "./migration-factories-gwi81C8u.mjs";
2
- import { MongoSchemaCollection, MongoSchemaCollectionOptions, MongoSchemaIR, MongoSchemaIndex, MongoSchemaValidator, canonicalize, deepEqual } from "@prisma-next/mongo-schema-ir";
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-IG0vjM_u.mjs";
3
+ import { canonicalize, deepEqual } from "@prisma-next/mongo-schema-ir";
3
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";
4
6
  import { CollModCommand, CreateCollectionCommand, CreateIndexCommand, DropCollectionCommand, DropIndexCommand, ListCollectionsCommand, ListIndexesCommand, MongoAndExpr, MongoExistsExpr, MongoFieldFilter, MongoNotExpr, MongoOrExpr } from "@prisma-next/mongo-query-ast/control";
5
7
  import { ifDefined } from "@prisma-next/utils/defined";
6
- import { type } from "arktype";
7
8
  import { TsExpression, jsonToTsSource, renderImports } from "@prisma-next/ts-render";
8
9
  import { Migration } from "@prisma-next/migration-tools/migration";
9
10
  import { detectScaffoldRuntime, shebangLineFor } from "@prisma-next/migration-tools/migration-ts";
10
11
  import { errorRunnerFailed } from "@prisma-next/errors/execution";
11
12
  import { notOk, ok } from "@prisma-next/utils/result";
12
13
 
13
- //#region src/core/contract-to-schema.ts
14
- function convertIndex(index) {
15
- return new MongoSchemaIndex({
16
- keys: index.keys,
17
- unique: index.unique,
18
- sparse: index.sparse,
19
- expireAfterSeconds: index.expireAfterSeconds,
20
- partialFilterExpression: index.partialFilterExpression,
21
- wildcardProjection: index.wildcardProjection,
22
- collation: index.collation,
23
- weights: index.weights,
24
- default_language: index.default_language,
25
- language_override: index.language_override
26
- });
27
- }
28
- function convertValidator(v) {
29
- return new MongoSchemaValidator({
30
- jsonSchema: v.jsonSchema,
31
- validationLevel: v.validationLevel,
32
- validationAction: v.validationAction
33
- });
34
- }
35
- function convertOptions(o) {
36
- return new MongoSchemaCollectionOptions(o);
37
- }
38
- function convertCollection(name, def) {
39
- return new MongoSchemaCollection({
40
- name,
41
- indexes: (def.indexes ?? []).map(convertIndex),
42
- ...def.validator != null && { validator: convertValidator(def.validator) },
43
- ...def.options != null && { options: convertOptions(def.options) }
44
- });
45
- }
46
- function contractToMongoSchemaIR(contract) {
47
- if (!contract) return new MongoSchemaIR([]);
48
- return new MongoSchemaIR(Object.entries(contract.storage.collections).map(([name, def]) => convertCollection(name, def)));
49
- }
50
-
51
- //#endregion
52
14
  //#region src/core/ddl-formatter.ts
53
15
  function formatKeySpec(keys) {
54
16
  return `{ ${keys.map((k) => `${JSON.stringify(k.field)}: ${JSON.stringify(k.direction)}`).join(", ")} }`;
@@ -176,6 +138,31 @@ var FilterEvaluator = class {
176
138
  //#region src/core/marker-ledger.ts
177
139
  const COLLECTION = "_prisma_migrations";
178
140
  const MARKER_ID = "marker";
141
+ const MongoMarkerDocSchema = type({
142
+ storageHash: "string",
143
+ profileHash: "string",
144
+ "contractJson?": "unknown | null",
145
+ "canonicalVersion?": "number | null",
146
+ "updatedAt?": "Date",
147
+ "appTag?": "string | null",
148
+ "meta?": type({ "[string]": "unknown" }).or("null"),
149
+ "invariants?": type("string").array(),
150
+ "+": "delete"
151
+ });
152
+ function parseMongoMarkerDoc(doc) {
153
+ const result = MongoMarkerDocSchema(doc);
154
+ if (result instanceof type.errors) throw new Error(`Invalid marker doc on ${COLLECTION}: ${result.summary}`);
155
+ return {
156
+ storageHash: result.storageHash,
157
+ profileHash: result.profileHash,
158
+ contractJson: result.contractJson ?? null,
159
+ canonicalVersion: result.canonicalVersion ?? null,
160
+ updatedAt: result.updatedAt ?? /* @__PURE__ */ new Date(),
161
+ appTag: result.appTag ?? null,
162
+ meta: result.meta ?? {},
163
+ invariants: result.invariants ?? []
164
+ };
165
+ }
179
166
  async function executeAggregate(db, cmd) {
180
167
  return db.collection(cmd.collection).aggregate(cmd.pipeline).toArray();
181
168
  }
@@ -188,15 +175,7 @@ async function executeFindOneAndUpdate(db, cmd) {
188
175
  async function readMarker(db) {
189
176
  const doc = (await executeAggregate(db, new RawAggregateCommand(COLLECTION, [{ $match: { _id: MARKER_ID } }, { $limit: 1 }])))[0];
190
177
  if (!doc) return null;
191
- return {
192
- storageHash: doc["storageHash"],
193
- profileHash: doc["profileHash"],
194
- contractJson: doc["contractJson"] ?? null,
195
- canonicalVersion: doc["canonicalVersion"] ?? null,
196
- updatedAt: doc["updatedAt"],
197
- appTag: doc["appTag"] ?? null,
198
- meta: doc["meta"] ?? {}
199
- };
178
+ return parseMongoMarkerDoc(doc);
200
179
  }
201
180
  async function initMarker(db, destination) {
202
181
  await executeInsertOne(db, new RawInsertOneCommand(COLLECTION, {
@@ -207,18 +186,36 @@ async function initMarker(db, destination) {
207
186
  canonicalVersion: null,
208
187
  updatedAt: /* @__PURE__ */ new Date(),
209
188
  appTag: null,
210
- meta: {}
189
+ meta: {},
190
+ invariants: destination.invariants ?? []
211
191
  }));
212
192
  }
193
+ /**
194
+ * Updates the marker doc atomically (CAS on `expectedFrom`).
195
+ *
196
+ * `destination.invariants`:
197
+ * - `undefined` → existing field left untouched.
198
+ * - explicit value → merged into the existing field server-side via an
199
+ * aggregation pipeline (`$setUnion + $sortArray`), atomic at the
200
+ * document level. `[]` is a no-op merge.
201
+ */
213
202
  async function updateMarker(db, expectedFrom, destination) {
214
- return await executeFindOneAndUpdate(db, new RawFindOneAndUpdateCommand(COLLECTION, {
215
- _id: MARKER_ID,
216
- storageHash: expectedFrom
217
- }, { $set: {
203
+ const setBase = {
218
204
  storageHash: destination.storageHash,
219
205
  profileHash: destination.profileHash,
220
206
  updatedAt: /* @__PURE__ */ new Date()
221
- } }, false)) !== null;
207
+ };
208
+ const update = destination.invariants === void 0 ? { $set: setBase } : [{ $set: {
209
+ ...setBase,
210
+ invariants: { $sortArray: {
211
+ input: { $setUnion: [{ $ifNull: ["$invariants", []] }, destination.invariants] },
212
+ sortBy: 1
213
+ } }
214
+ } }];
215
+ return await executeFindOneAndUpdate(db, new RawFindOneAndUpdateCommand(COLLECTION, {
216
+ _id: MARKER_ID,
217
+ storageHash: expectedFrom
218
+ }, update, false)) !== null;
222
219
  }
223
220
  async function writeLedgerEntry(db, entry) {
224
221
  await executeInsertOne(db, new RawInsertOneCommand(COLLECTION, {
@@ -358,13 +355,9 @@ const QueryPlanJson = type({
358
355
  target: "string",
359
356
  storageHash: "string",
360
357
  lane: "string",
361
- paramDescriptors: "unknown[]",
362
358
  "targetFamily?": "string",
363
359
  "profileHash?": "string",
364
- "annotations?": "Record<string, unknown>",
365
- "refs?": "Record<string, unknown>",
366
- "projection?": "Record<string, string> | string[]",
367
- "projectionTypes?": "Record<string, string>"
360
+ "annotations?": "Record<string, unknown>"
368
361
  })
369
362
  });
370
363
  const CheckJson = type({
@@ -528,13 +521,9 @@ function deserializeMongoQueryPlan(json) {
528
521
  target: m.target,
529
522
  storageHash: m.storageHash,
530
523
  lane: m.lane,
531
- paramDescriptors: m.paramDescriptors,
532
524
  ...ifDefined("targetFamily", m.targetFamily),
533
525
  ...ifDefined("profileHash", m.profileHash),
534
- ...ifDefined("annotations", m.annotations),
535
- ...ifDefined("refs", m.refs),
536
- ...ifDefined("projection", m.projection),
537
- ...ifDefined("projectionTypes", m.projectionTypes)
526
+ ...ifDefined("annotations", m.annotations)
538
527
  };
539
528
  return {
540
529
  collection: data.collection,
@@ -856,8 +845,8 @@ const BASE_IMPORTS = [{
856
845
  * `Migration` (i.e. `MongoMigration`) from `@prisma-next/family-mongo`, and
857
846
  * implements the abstract `operations` and `describe` members. `meta` is
858
847
  * always rendered — `describe()` is part of the `Migration` contract, so
859
- * even an empty stub must satisfy it; callers pass empty strings for a
860
- * migration-new scaffold.
848
+ * even an empty stub must satisfy it; callers pass `from: null` for a
849
+ * baseline `migration-new` scaffold (and a real `to` hash either way).
861
850
  *
862
851
  * The walk is polymorphic: each call node contributes its own
863
852
  * `renderTypeScript()` expression and declares its own
@@ -899,7 +888,6 @@ function buildDescribeMethod(meta) {
899
888
  lines.push(" return {");
900
889
  lines.push(` from: ${JSON.stringify(meta.from)},`);
901
890
  lines.push(` to: ${JSON.stringify(meta.to)},`);
902
- if (meta.kind) lines.push(` kind: ${JSON.stringify(meta.kind)},`);
903
891
  if (meta.labels && meta.labels.length > 0) lines.push(` labels: ${jsonToTsSource(meta.labels)},`);
904
892
  lines.push(" };");
905
893
  lines.push(" }");
@@ -946,7 +934,6 @@ var PlannerProducedMongoMigration = class extends Migration {
946
934
  return renderCallsToTypeScript(this.calls, {
947
935
  from: this.meta.from,
948
936
  to: this.meta.to,
949
- ...ifDefined("kind", this.meta.kind),
950
937
  ...ifDefined("labels", this.meta.labels)
951
938
  });
952
939
  }
@@ -1128,9 +1115,6 @@ function planMutableOptionsDiffCall(collName, origin, dest) {
1128
1115
  //#endregion
1129
1116
  //#region src/core/mongo-runner.ts
1130
1117
  const READ_ONLY_CHECK_COMMAND_KINDS = new Set(["aggregate", "rawAggregate"]);
1131
- function hasProfileHash(value) {
1132
- return typeof value === "object" && value !== null && Object.hasOwn(value, "profileHash") && typeof value.profileHash === "string";
1133
- }
1134
1118
  function runnerFailure(code, summary, opts) {
1135
1119
  return notOk({
1136
1120
  code,
@@ -1182,22 +1166,40 @@ var MongoMigrationRunner = class {
1182
1166
  }
1183
1167
  }
1184
1168
  const destination = options.plan.destination;
1185
- const profileHash = hasProfileHash(options.destinationContract) ? options.destinationContract.profileHash : destination.storageHash;
1186
- if (operationsExecuted === 0 && existingMarker?.storageHash === destination.storageHash && existingMarker.profileHash === profileHash) return ok({
1169
+ const profileHash = options.destinationContract.profileHash ?? destination.storageHash;
1170
+ const incomingInvariants = Array.from(new Set(options.invariants ?? [])).sort();
1171
+ const existingInvariantSet = new Set(existingMarker?.invariants ?? []);
1172
+ const incomingIsSubsetOfExisting = incomingInvariants.every((id) => existingInvariantSet.has(id));
1173
+ const markerAlreadyAtDestination = existingMarker !== null && existingMarker.storageHash === destination.storageHash && existingMarker.profileHash === profileHash;
1174
+ if (operationsExecuted === 0 && markerAlreadyAtDestination && incomingIsSubsetOfExisting) return ok({
1187
1175
  operationsPlanned: operations.length,
1188
1176
  operationsExecuted
1189
1177
  });
1178
+ const liveSchema = await this.deps.introspectSchema();
1179
+ const verifyResult = verifyMongoSchema({
1180
+ contract: options.destinationContract,
1181
+ schema: liveSchema,
1182
+ strict: options.strictVerification ?? true,
1183
+ frameworkComponents: options.frameworkComponents,
1184
+ ...options.context ? { context: options.context } : {}
1185
+ });
1186
+ if (!verifyResult.ok) return runnerFailure("SCHEMA_VERIFY_FAILED", verifyResult.summary, {
1187
+ why: "The resulting database schema does not satisfy the destination contract.",
1188
+ meta: { issues: verifyResult.schema.issues }
1189
+ });
1190
1190
  if (existingMarker) {
1191
1191
  if (!await markerOps.updateMarker(existingMarker.storageHash, {
1192
1192
  storageHash: destination.storageHash,
1193
- profileHash
1193
+ profileHash,
1194
+ invariants: incomingInvariants
1194
1195
  })) return runnerFailure("MARKER_CAS_FAILURE", "Marker was modified by another process during migration execution.", { meta: {
1195
1196
  expectedStorageHash: existingMarker.storageHash,
1196
1197
  destinationStorageHash: destination.storageHash
1197
1198
  } });
1198
1199
  } else await markerOps.initMarker({
1199
1200
  storageHash: destination.storageHash,
1200
- profileHash
1201
+ profileHash,
1202
+ invariants: incomingInvariants
1201
1203
  });
1202
1204
  const originHash = existingMarker?.storageHash ?? "";
1203
1205
  await markerOps.writeLedgerEntry({
@@ -1224,7 +1226,7 @@ var MongoMigrationRunner = class {
1224
1226
  };
1225
1227
  }
1226
1228
  for (const plan of op.run) {
1227
- const wireCommand = adapter.lower(plan);
1229
+ const wireCommand = await adapter.lower(plan, {});
1228
1230
  for await (const _ of driver.execute(wireCommand));
1229
1231
  }
1230
1232
  if (runPostchecks && op.postcheck.length > 0) {
@@ -1250,7 +1252,7 @@ var MongoMigrationRunner = class {
1250
1252
  collection: check.source.collection
1251
1253
  }
1252
1254
  });
1253
- const wireCommand = adapter.lower(check.source);
1255
+ const wireCommand = await adapter.lower(check.source, {});
1254
1256
  let matchFound = false;
1255
1257
  for await (const row of driver.execute(wireCommand)) if (filterEvaluator.evaluate(check.filter, row)) {
1256
1258
  matchFound = true;
@@ -1283,10 +1285,7 @@ var MongoMigrationRunner = class {
1283
1285
  }
1284
1286
  ensureMarkerCompatibility(marker, plan) {
1285
1287
  const origin = plan.origin ?? null;
1286
- if (!origin) {
1287
- 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 } });
1288
- return;
1289
- }
1288
+ if (!origin) return;
1290
1289
  if (!marker) return runnerFailure("MARKER_ORIGIN_MISMATCH", `Missing contract marker: expected origin storage hash ${origin.storageHash}.`, { meta: { expectedOriginStorageHash: origin.storageHash } });
1291
1290
  if (marker.storageHash !== origin.storageHash) return runnerFailure("MARKER_ORIGIN_MISMATCH", `Existing contract marker (${marker.storageHash}) does not match plan origin (${origin.storageHash}).`, { meta: {
1292
1291
  markerStorageHash: marker.storageHash,