@prisma-next/family-mongo 0.4.0-dev.6 → 0.4.0-dev.7

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.
@@ -12,6 +12,22 @@ declare function createMongoFamilyInstance(_controlStack: ControlStack): MongoCo
12
12
  declare const mongoFamilyDescriptor: ControlFamilyDescriptor<'mongo', MongoControlFamilyInstance>;
13
13
  //#endregion
14
14
  //#region src/core/mongo-target-descriptor.d.ts
15
+ /**
16
+ * The Mongo target uses the **class-flow** migration authoring strategy.
17
+ *
18
+ * `migration.ts` default-exports a `Migration` subclass whose `operations`
19
+ * getter returns the ordered list of operations and whose `describe()`
20
+ * returns the manifest identity metadata. `MongoMigrationPlanner.plan()`
21
+ * returns a `MigrationPlanWithAuthoringSurface` that knows how to render
22
+ * itself back to such a file; `MongoMigrationPlanner.emptyMigration()`
23
+ * returns the same shape for `migration new`. `migration emit` dispatches
24
+ * to `mongoEmit`, which dynamic-imports the class and writes `ops.json`.
25
+ *
26
+ * The descriptor-flow hooks (`planWithDescriptors`, `resolveDescriptors`,
27
+ * `renderDescriptorTypeScript`) are intentionally omitted — the CLI's
28
+ * `migrationStrategy` selector routes Mongo down the class-flow path by
29
+ * observing their absence.
30
+ */
15
31
  declare const mongoTargetDescriptor: MigratableTargetDescriptor<'mongo', 'mongo', MongoControlFamilyInstance>;
16
32
  //#endregion
17
33
  export { type MongoControlFamilyInstance, createMongoFamilyInstance, mongoFamilyDescriptor, mongoTargetDescriptor };
@@ -1 +1 @@
1
- {"version":3,"file":"control.d.mts","names":[],"sources":["../src/core/control-instance.ts","../src/core/control-descriptor.ts","../src/core/mongo-target-descriptor.ts"],"sourcesContent":[],"mappings":";;;;;UAgCiB,0BAAA,SACP,+BAA+B,gBACrC,kBAAkB;2CACqB;AAH3C;AACyC,iBAkSzB,yBAAA,CAlSyB,aAAA,EAkSgB,YAlShB,CAAA,EAkS+B,0BAlS/B;;;cCV5B,uBAAuB,iCAAiC;;;cCTxD,uBAAuB,6CAGlC"}
1
+ {"version":3,"file":"control.d.mts","names":[],"sources":["../src/core/control-instance.ts","../src/core/control-descriptor.ts","../src/core/mongo-target-descriptor.ts"],"sourcesContent":[],"mappings":";;;;;UAgCiB,0BAAA,SACP,+BAA+B,gBACrC,kBAAkB;2CACqB;AAH3C;AACyC,iBAkSzB,yBAAA,CAlSyB,aAAA,EAkSgB,YAlShB,CAAA,EAkS+B,0BAlS/B;;;cCV5B,uBAAuB,iCAAiC;;;;;;ADSrE;;;;;;;AAmSA;;;;AC5SA;;cCOa,uBAAuB,6CAGlC"}
package/dist/control.mjs CHANGED
@@ -630,42 +630,55 @@ const mongoFamilyDescriptor = new MongoFamilyDescriptor();
630
630
  //#region src/core/mongo-emit.ts
631
631
  /**
632
632
  * Mongo's in-process implementation of the `emit` capability on
633
- * `TargetMigrationsCapability`.
633
+ * `TargetMigrationsCapability`. Invoked by the framework's class-flow emit
634
+ * dispatcher in `@prisma-next/cli/lib/migration-emit` — see that module's
635
+ * preamble for the cross-cutting story (when the CLI dispatches here, who
636
+ * attests `migration.json`, why both flows produce byte-identical artifacts,
637
+ * and the relationship to the self-emitting `Migration.run` shebang path).
634
638
  *
635
- * The CLI's `migration emit` (and `migration plan`'s inline emit) dispatches
636
- * here for any target that does not implement `resolveDescriptors`. Two
637
- * authoring shapes are accepted:
639
+ * Mongo-specific responsibilities of this helper:
638
640
  *
639
- * 1. Class subclass (canonical):
640
- * class M extends Migration { override plan() { return [...] } }
641
- * export default M;
642
- * Migration.run(import.meta.url, M);
641
+ * - Accept two authoring shapes for `migration.ts`'s default export, both
642
+ * adhering to the `MigrationPlan` interface:
643
643
  *
644
- * 2. Factory function returning a Migration-satisfying object:
645
- * export default () => ({ plan() { return [createCollection("users")] } });
644
+ * 1. Class subclass (canonical, scaffolded form):
645
+ * class M extends Migration {
646
+ * override get operations() { return [...]; }
647
+ * override describe() { return { from, to }; }
648
+ * }
649
+ * export default M;
650
+ * Migration.run(import.meta.url, M);
646
651
  *
647
- * We dynamic-import the file (so that any structured errors thrown by
648
- * `placeholder(...)` propagate as real exceptions to the CLI), dispatch on
649
- * the export's shape (class subclass vs. callable function), and persist
650
- * `ops.json` via the framework I/O helper. `Migration.run` already guards
651
- * itself against firing when the file is imported rather than run as the
652
- * main module, so this is safe to call from inside the CLI process.
652
+ * 2. Factory function returning a MigrationPlan-shaped object:
653
+ * export default () => ({
654
+ * targetId: 'mongo',
655
+ * destination: { storageHash: '...' },
656
+ * operations: [createCollection("users")],
657
+ * });
653
658
  *
654
- * Attestation (computing and writing `migrationId` to `manifest.json`) is
655
- * owned by the framework's `emitMigration` helper, not this capability.
659
+ * Only the class form is scaffolded; the factory form is supported for
660
+ * authors who prefer it.
661
+ * - Dynamic-import the file so structured errors thrown during evaluation
662
+ * (notably `placeholder(...)`) surface to the CLI as real exceptions.
663
+ * - Dispatch on the default export's shape and validate the factory return
664
+ * is `MigrationPlan`-shaped.
665
+ * - Persist `ops.json` via the framework I/O helper and return the
666
+ * operations to the caller (which performs attestation).
656
667
  */
657
668
  const MIGRATION_TS_FILE = "migration.ts";
658
669
  /**
659
670
  * Implementation of `TargetMigrationsCapability.emit` for Mongo.
660
671
  *
661
672
  * Loads `<dir>/migration.ts` and dispatches on the default export's shape:
662
- * if it is a `Migration` subclass, instantiates it and calls `plan()`;
663
- * otherwise invokes it as a factory function, validates the returned value
664
- * has a `plan()` method, and calls it.
665
- * Writes `ops.json` and returns the operations for the framework helper to
666
- * render. Attestation (`migrationId` in `manifest.json`) is the framework
667
- * helper's responsibility; this capability MUST NOT call `attestMigration`
668
- * itself.
673
+ * if it is a `Migration` subclass, instantiates it; otherwise invokes it as a
674
+ * factory function (sync or async) and validates the returned value is
675
+ * `MigrationPlan`-shaped. In both cases reads `.operations` to produce the
676
+ * operations list, writes `ops.json`, and returns the operations for the
677
+ * framework helper to render. Attestation of `migration.json` is the
678
+ * caller's responsibility: the framework's `emitMigration` helper calls
679
+ * `attestMigration` after this function returns. This capability MUST NOT
680
+ * call `attestMigration` itself, to avoid double-attestation when the helper
681
+ * drives emit.
669
682
  */
670
683
  async function mongoEmit(options) {
671
684
  const filePath = join(options.dir, MIGRATION_TS_FILE);
@@ -676,8 +689,8 @@ async function mongoEmit(options) {
676
689
  }
677
690
  const MigrationExport = (await import(pathToFileURL(filePath).href)).default;
678
691
  if (typeof MigrationExport !== "function") throw errorMigrationInvalidDefaultExport(options.dir, `default export of type ${typeof MigrationExport}`);
679
- let migration;
680
- if (MigrationExport.prototype instanceof Migration) migration = new MigrationExport();
692
+ let plan;
693
+ if (MigrationExport.prototype instanceof Migration) plan = new MigrationExport();
681
694
  else {
682
695
  let factoryResult;
683
696
  try {
@@ -686,10 +699,10 @@ async function mongoEmit(options) {
686
699
  if (error instanceof TypeError && /cannot be invoked without 'new'/i.test(error.message)) throw errorMigrationInvalidDefaultExport(options.dir, "a default export that does not extend Migration (from @prisma-next/migration-tools/migration)");
687
700
  throw error;
688
701
  }
689
- if (typeof factoryResult !== "object" || factoryResult === null || typeof factoryResult.plan !== "function") throw errorMigrationInvalidDefaultExport(options.dir, `factory must return an object with a plan() method; got ${describeValue(factoryResult)}`);
690
- migration = factoryResult;
702
+ if (typeof factoryResult !== "object" || factoryResult === null || !("operations" in factoryResult)) throw errorMigrationInvalidDefaultExport(options.dir, `factory must return a MigrationPlan-shaped object; got ${describeValue(factoryResult)}`);
703
+ plan = factoryResult;
691
704
  }
692
- const operations = migration.plan();
705
+ const operations = plan.operations;
693
706
  if (!Array.isArray(operations)) throw errorMigrationPlanNotArray(options.dir, describeValue(operations));
694
707
  await writeMigrationOps(options.dir, operations);
695
708
  return operations;
@@ -701,6 +714,22 @@ function describeValue(value) {
701
714
 
702
715
  //#endregion
703
716
  //#region src/core/mongo-target-descriptor.ts
717
+ /**
718
+ * The Mongo target uses the **class-flow** migration authoring strategy.
719
+ *
720
+ * `migration.ts` default-exports a `Migration` subclass whose `operations`
721
+ * getter returns the ordered list of operations and whose `describe()`
722
+ * returns the manifest identity metadata. `MongoMigrationPlanner.plan()`
723
+ * returns a `MigrationPlanWithAuthoringSurface` that knows how to render
724
+ * itself back to such a file; `MongoMigrationPlanner.emptyMigration()`
725
+ * returns the same shape for `migration new`. `migration emit` dispatches
726
+ * to `mongoEmit`, which dynamic-imports the class and writes `ops.json`.
727
+ *
728
+ * The descriptor-flow hooks (`planWithDescriptors`, `resolveDescriptors`,
729
+ * `renderDescriptorTypeScript`) are intentionally omitted — the CLI's
730
+ * `migrationStrategy` selector routes Mongo down the class-flow path by
731
+ * observing their absence.
732
+ */
704
733
  const mongoTargetDescriptor = {
705
734
  ...mongoTargetDescriptorMeta,
706
735
  migrations: {
@@ -1 +1 @@
1
- {"version":3,"file":"control.mjs","names":["issues: SchemaIssue[]","collectionChildren: SchemaVerificationNode[]","nodes: SchemaVerificationNode[]","children: SchemaTreeNode[]","options: string[]","validatorChildren: SchemaTreeNode[]","optLabels: string[]","previousHashes: { storageHash?: string; profileHash?: string } | undefined","summary: string","mongoFamilyDescriptor: ControlFamilyDescriptor<'mongo', MongoControlFamilyInstance>","migration: { plan(): unknown }","factoryResult: unknown","operations: unknown","mongoTargetDescriptor: MigratableTargetDescriptor<\n 'mongo',\n 'mongo',\n MongoControlFamilyInstance\n>","cachedDeps: MongoRunnerDependencies | undefined"],"sources":["../src/core/schema-diff.ts","../src/core/schema-to-view.ts","../src/core/control-instance.ts","../src/core/control-descriptor.ts","../src/core/mongo-emit.ts","../src/core/mongo-target-descriptor.ts"],"sourcesContent":["import type {\n SchemaIssue,\n SchemaVerificationNode,\n} from '@prisma-next/framework-components/control';\nimport type {\n MongoSchemaCollection,\n MongoSchemaIndex,\n MongoSchemaIR,\n} from '@prisma-next/mongo-schema-ir';\nimport { canonicalize, deepEqual } from '@prisma-next/mongo-schema-ir';\n\nexport function diffMongoSchemas(\n live: MongoSchemaIR,\n expected: MongoSchemaIR,\n strict: boolean,\n): {\n root: SchemaVerificationNode;\n issues: SchemaIssue[];\n counts: { pass: number; warn: number; fail: number; totalNodes: number };\n} {\n const issues: SchemaIssue[] = [];\n const collectionChildren: SchemaVerificationNode[] = [];\n let pass = 0;\n let warn = 0;\n let fail = 0;\n\n const allNames = new Set([...live.collectionNames, ...expected.collectionNames]);\n\n for (const name of [...allNames].sort()) {\n const liveColl = live.collection(name);\n const expectedColl = expected.collection(name);\n\n if (!liveColl && expectedColl) {\n issues.push({\n kind: 'missing_table',\n table: name,\n message: `Collection \"${name}\" is missing from the database`,\n });\n collectionChildren.push({\n status: 'fail',\n kind: 'collection',\n name,\n contractPath: `storage.collections.${name}`,\n code: 'MISSING_COLLECTION',\n message: `Collection \"${name}\" is missing`,\n expected: name,\n actual: null,\n children: [],\n });\n fail++;\n continue;\n }\n\n if (liveColl && !expectedColl) {\n const status = strict ? 'fail' : 'warn';\n issues.push({\n kind: 'extra_table',\n table: name,\n message: `Extra collection \"${name}\" exists in the database but not in the contract`,\n });\n collectionChildren.push({\n status,\n kind: 'collection',\n name,\n contractPath: `storage.collections.${name}`,\n code: 'EXTRA_COLLECTION',\n message: `Extra collection \"${name}\" found`,\n expected: null,\n actual: name,\n children: [],\n });\n if (status === 'fail') fail++;\n else warn++;\n continue;\n }\n\n const lc = liveColl as MongoSchemaCollection;\n const ec = expectedColl as MongoSchemaCollection;\n const indexChildren = diffIndexes(name, lc, ec, strict, issues);\n const validatorChildren = diffValidator(name, lc, ec, strict, issues);\n const optionsChildren = diffOptions(name, lc, ec, strict, issues);\n const children = [...indexChildren, ...validatorChildren, ...optionsChildren];\n\n const worstStatus = children.reduce<'pass' | 'warn' | 'fail'>(\n (s, c) => (c.status === 'fail' ? 'fail' : c.status === 'warn' && s !== 'fail' ? 'warn' : s),\n 'pass',\n );\n\n for (const c of children) {\n if (c.status === 'pass') pass++;\n else if (c.status === 'warn') warn++;\n else fail++;\n }\n\n if (children.length === 0) {\n pass++;\n }\n\n collectionChildren.push({\n status: worstStatus,\n kind: 'collection',\n name,\n contractPath: `storage.collections.${name}`,\n code: worstStatus === 'pass' ? 'MATCH' : 'DRIFT',\n message:\n worstStatus === 'pass' ? `Collection \"${name}\" matches` : `Collection \"${name}\" has drift`,\n expected: name,\n actual: name,\n children,\n });\n }\n\n const rootStatus = fail > 0 ? 'fail' : warn > 0 ? 'warn' : 'pass';\n const totalNodes = pass + warn + fail + collectionChildren.length;\n\n const root: SchemaVerificationNode = {\n status: rootStatus,\n kind: 'root',\n name: 'mongo-schema',\n contractPath: 'storage',\n code: rootStatus === 'pass' ? 'MATCH' : 'DRIFT',\n message: rootStatus === 'pass' ? 'Schema matches' : 'Schema has drift',\n expected: null,\n actual: null,\n children: collectionChildren,\n };\n\n return { root, issues, counts: { pass, warn, fail, totalNodes } };\n}\n\nfunction buildIndexLookupKey(index: MongoSchemaIndex): string {\n const keys = index.keys.map((k) => `${k.field}:${k.direction}`).join(',');\n const opts = [\n index.unique ? 'unique' : '',\n index.sparse ? 'sparse' : '',\n index.expireAfterSeconds != null ? `ttl:${index.expireAfterSeconds}` : '',\n index.partialFilterExpression ? `pfe:${canonicalize(index.partialFilterExpression)}` : '',\n index.wildcardProjection ? `wp:${canonicalize(index.wildcardProjection)}` : '',\n index.collation ? `col:${canonicalize(index.collation)}` : '',\n index.weights ? `wt:${canonicalize(index.weights)}` : '',\n index.default_language ? `dl:${index.default_language}` : '',\n index.language_override ? `lo:${index.language_override}` : '',\n ]\n .filter(Boolean)\n .join(';');\n return opts ? `${keys}|${opts}` : keys;\n}\n\nfunction formatIndexName(index: MongoSchemaIndex): string {\n return index.keys.map((k) => `${k.field}:${k.direction}`).join(', ');\n}\n\nfunction diffIndexes(\n collName: string,\n live: MongoSchemaCollection,\n expected: MongoSchemaCollection,\n strict: boolean,\n issues: SchemaIssue[],\n): SchemaVerificationNode[] {\n const nodes: SchemaVerificationNode[] = [];\n const liveLookup = new Map<string, MongoSchemaIndex>();\n for (const idx of live.indexes) liveLookup.set(buildIndexLookupKey(idx), idx);\n\n const expectedLookup = new Map<string, MongoSchemaIndex>();\n for (const idx of expected.indexes) expectedLookup.set(buildIndexLookupKey(idx), idx);\n\n for (const [key, idx] of expectedLookup) {\n if (liveLookup.has(key)) {\n nodes.push({\n status: 'pass',\n kind: 'index',\n name: formatIndexName(idx),\n contractPath: `storage.collections.${collName}.indexes`,\n code: 'MATCH',\n message: `Index ${formatIndexName(idx)} matches`,\n expected: key,\n actual: key,\n children: [],\n });\n } else {\n issues.push({\n kind: 'index_mismatch',\n table: collName,\n indexOrConstraint: formatIndexName(idx),\n message: `Index ${formatIndexName(idx)} missing on collection \"${collName}\"`,\n });\n nodes.push({\n status: 'fail',\n kind: 'index',\n name: formatIndexName(idx),\n contractPath: `storage.collections.${collName}.indexes`,\n code: 'MISSING_INDEX',\n message: `Index ${formatIndexName(idx)} missing`,\n expected: key,\n actual: null,\n children: [],\n });\n }\n }\n\n for (const [key, idx] of liveLookup) {\n if (!expectedLookup.has(key)) {\n const status = strict ? 'fail' : 'warn';\n issues.push({\n kind: 'extra_index',\n table: collName,\n indexOrConstraint: formatIndexName(idx),\n message: `Extra index ${formatIndexName(idx)} on collection \"${collName}\"`,\n });\n nodes.push({\n status,\n kind: 'index',\n name: formatIndexName(idx),\n contractPath: `storage.collections.${collName}.indexes`,\n code: 'EXTRA_INDEX',\n message: `Extra index ${formatIndexName(idx)}`,\n expected: null,\n actual: key,\n children: [],\n });\n }\n }\n\n return nodes;\n}\n\nfunction diffValidator(\n collName: string,\n live: MongoSchemaCollection,\n expected: MongoSchemaCollection,\n strict: boolean,\n issues: SchemaIssue[],\n): SchemaVerificationNode[] {\n if (!live.validator && !expected.validator) return [];\n\n if (expected.validator && !live.validator) {\n issues.push({\n kind: 'type_missing',\n table: collName,\n message: `Validator missing on collection \"${collName}\"`,\n });\n return [\n {\n status: 'fail',\n kind: 'validator',\n name: 'validator',\n contractPath: `storage.collections.${collName}.validator`,\n code: 'MISSING_VALIDATOR',\n message: 'Validator missing',\n expected: canonicalize(expected.validator.jsonSchema),\n actual: null,\n children: [],\n },\n ];\n }\n\n if (!expected.validator && live.validator) {\n const status = strict ? 'fail' : 'warn';\n issues.push({\n kind: 'extra_validator',\n table: collName,\n message: `Extra validator on collection \"${collName}\"`,\n });\n return [\n {\n status,\n kind: 'validator',\n name: 'validator',\n contractPath: `storage.collections.${collName}.validator`,\n code: 'EXTRA_VALIDATOR',\n message: 'Extra validator found',\n expected: null,\n actual: canonicalize(live.validator.jsonSchema),\n children: [],\n },\n ];\n }\n\n const liveVal = live.validator as NonNullable<typeof live.validator>;\n const expectedVal = expected.validator as NonNullable<typeof expected.validator>;\n const liveSchema = canonicalize(liveVal.jsonSchema);\n const expectedSchema = canonicalize(expectedVal.jsonSchema);\n\n if (\n liveSchema !== expectedSchema ||\n liveVal.validationLevel !== expectedVal.validationLevel ||\n liveVal.validationAction !== expectedVal.validationAction\n ) {\n issues.push({\n kind: 'type_mismatch',\n table: collName,\n expected: expectedSchema,\n actual: liveSchema,\n message: `Validator mismatch on collection \"${collName}\"`,\n });\n return [\n {\n status: 'fail',\n kind: 'validator',\n name: 'validator',\n contractPath: `storage.collections.${collName}.validator`,\n code: 'VALIDATOR_MISMATCH',\n message: 'Validator mismatch',\n expected: {\n jsonSchema: expectedVal.jsonSchema,\n validationLevel: expectedVal.validationLevel,\n validationAction: expectedVal.validationAction,\n },\n actual: {\n jsonSchema: liveVal.jsonSchema,\n validationLevel: liveVal.validationLevel,\n validationAction: liveVal.validationAction,\n },\n children: [],\n },\n ];\n }\n\n return [\n {\n status: 'pass',\n kind: 'validator',\n name: 'validator',\n contractPath: `storage.collections.${collName}.validator`,\n code: 'MATCH',\n message: 'Validator matches',\n expected: expectedSchema,\n actual: liveSchema,\n children: [],\n },\n ];\n}\n\nfunction diffOptions(\n collName: string,\n live: MongoSchemaCollection,\n expected: MongoSchemaCollection,\n strict: boolean,\n issues: SchemaIssue[],\n): SchemaVerificationNode[] {\n if (!live.options && !expected.options) return [];\n\n if (!expected.options && live.options) {\n const status = strict ? 'fail' : 'warn';\n issues.push({\n kind: 'type_mismatch',\n table: collName,\n actual: canonicalize(live.options),\n message: `Extra collection options on \"${collName}\"`,\n });\n return [\n {\n status,\n kind: 'options',\n name: 'options',\n contractPath: `storage.collections.${collName}.options`,\n code: 'EXTRA_OPTIONS',\n message: 'Extra collection options found',\n expected: null,\n actual: live.options,\n children: [],\n },\n ];\n }\n\n if (deepEqual(live.options, expected.options)) {\n return [\n {\n status: 'pass',\n kind: 'options',\n name: 'options',\n contractPath: `storage.collections.${collName}.options`,\n code: 'MATCH',\n message: 'Collection options match',\n expected: canonicalize(expected.options),\n actual: canonicalize(live.options),\n children: [],\n },\n ];\n }\n\n issues.push({\n kind: 'type_mismatch',\n table: collName,\n expected: canonicalize(expected.options),\n actual: canonicalize(live.options),\n message: `Collection options mismatch on \"${collName}\"`,\n });\n return [\n {\n status: 'fail',\n kind: 'options',\n name: 'options',\n contractPath: `storage.collections.${collName}.options`,\n code: 'OPTIONS_MISMATCH',\n message: 'Collection options mismatch',\n expected: expected.options,\n actual: live.options,\n children: [],\n },\n ];\n}\n","import type { CoreSchemaView } from '@prisma-next/framework-components/control';\nimport { SchemaTreeNode } from '@prisma-next/framework-components/control';\nimport type { MongoSchemaCollection, MongoSchemaIR } from '@prisma-next/mongo-schema-ir';\nimport { ifDefined } from '@prisma-next/utils/defined';\n\nexport function mongoSchemaToView(schema: MongoSchemaIR): CoreSchemaView {\n const collectionNodes = schema.collections.map((collection) =>\n collectionToSchemaNode(collection.name, collection),\n );\n\n return {\n root: new SchemaTreeNode({\n kind: 'root',\n id: 'mongo-schema',\n label: 'database',\n ...ifDefined('children', collectionNodes.length > 0 ? collectionNodes : undefined),\n }),\n };\n}\n\nfunction collectionToSchemaNode(name: string, collection: MongoSchemaCollection): SchemaTreeNode {\n const children: SchemaTreeNode[] = [];\n\n for (const index of collection.indexes) {\n const keysSummary = index.keys\n .map((k) => {\n if (k.direction === 1) return k.field;\n if (k.direction === -1) return `${k.field} desc`;\n return `${k.field} ${k.direction}`;\n })\n .join(', ');\n const prefix = index.unique ? 'unique index' : 'index';\n const options: string[] = [];\n if (index.sparse) options.push('sparse');\n if (index.expireAfterSeconds != null) options.push(`ttl: ${index.expireAfterSeconds}s`);\n if (index.partialFilterExpression) options.push('partial');\n const optsSuffix = options.length > 0 ? ` (${options.join(', ')})` : '';\n\n children.push(\n new SchemaTreeNode({\n kind: 'index',\n id: `index-${name}-${index.keys.map((k) => `${k.field}_${k.direction}`).join('_')}`,\n label: `${prefix} (${keysSummary})${optsSuffix}`,\n meta: {\n keys: index.keys,\n unique: index.unique,\n ...ifDefined('sparse', index.sparse || undefined),\n ...ifDefined('expireAfterSeconds', index.expireAfterSeconds ?? undefined),\n ...ifDefined('partialFilterExpression', index.partialFilterExpression ?? undefined),\n },\n }),\n );\n }\n\n if (collection.validator) {\n const validatorChildren: SchemaTreeNode[] = [];\n const jsonSchema = collection.validator.jsonSchema as Record<string, unknown>;\n const properties = jsonSchema['properties'] as\n | Record<string, Record<string, unknown>>\n | undefined;\n const required = new Set((jsonSchema['required'] as string[] | undefined) ?? []);\n\n if (properties) {\n for (const [propName, propDef] of Object.entries(properties)) {\n const bsonType = (propDef['bsonType'] as string) ?? 'unknown';\n const suffix = required.has(propName) ? ' (required)' : '';\n validatorChildren.push(\n new SchemaTreeNode({\n kind: 'field',\n id: `field-${name}-${propName}`,\n label: `${propName}: ${bsonType}${suffix}`,\n }),\n );\n }\n }\n\n children.push(\n new SchemaTreeNode({\n kind: 'field',\n id: `validator-${name}`,\n label: `validator (level: ${collection.validator.validationLevel}, action: ${collection.validator.validationAction})`,\n meta: {\n validationLevel: collection.validator.validationLevel,\n validationAction: collection.validator.validationAction,\n jsonSchema: collection.validator.jsonSchema,\n },\n ...ifDefined('children', validatorChildren.length > 0 ? validatorChildren : undefined),\n }),\n );\n }\n\n if (collection.options) {\n const opts = collection.options;\n const optLabels: string[] = [];\n if (opts.capped) optLabels.push('capped');\n if (opts.timeseries) optLabels.push('timeseries');\n if (opts.collation) optLabels.push('collation');\n if (opts.changeStreamPreAndPostImages) optLabels.push('changeStreamPreAndPostImages');\n if (opts.clusteredIndex) optLabels.push('clusteredIndex');\n\n if (optLabels.length > 0) {\n children.push(\n new SchemaTreeNode({\n kind: 'field',\n id: `options-${name}`,\n label: `options (${optLabels.join(', ')})`,\n meta: {\n ...ifDefined('capped', opts.capped ?? undefined),\n ...ifDefined('timeseries', opts.timeseries ?? undefined),\n ...ifDefined('collation', opts.collation ?? undefined),\n ...ifDefined(\n 'changeStreamPreAndPostImages',\n opts.changeStreamPreAndPostImages ?? undefined,\n ),\n ...ifDefined('clusteredIndex', opts.clusteredIndex ?? undefined),\n },\n }),\n );\n }\n }\n\n return new SchemaTreeNode({\n kind: 'collection',\n id: `collection-${name}`,\n label: `collection ${name}`,\n ...ifDefined('children', children.length > 0 ? children : undefined),\n });\n}\n","import { introspectSchema } from '@prisma-next/adapter-mongo/control';\nimport type { Contract, ContractMarkerRecord } from '@prisma-next/contract/types';\nimport type {\n ControlDriverInstance,\n ControlFamilyInstance,\n ControlStack,\n CoreSchemaView,\n SchemaViewCapable,\n SignDatabaseResult,\n VerifyDatabaseResult,\n VerifyDatabaseSchemaResult,\n} from '@prisma-next/framework-components/control';\nimport {\n VERIFY_CODE_HASH_MISMATCH,\n VERIFY_CODE_MARKER_MISSING,\n VERIFY_CODE_SCHEMA_FAILURE,\n VERIFY_CODE_TARGET_MISMATCH,\n} from '@prisma-next/framework-components/control';\nimport type { MongoContract } from '@prisma-next/mongo-contract';\nimport { validateMongoContract } from '@prisma-next/mongo-contract';\nimport type { MongoSchemaIR } from '@prisma-next/mongo-schema-ir';\nimport {\n contractToMongoSchemaIR,\n initMarker,\n readMarker,\n updateMarker,\n} from '@prisma-next/target-mongo/control';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { Db } from 'mongodb';\nimport { diffMongoSchemas } from './schema-diff';\nimport { mongoSchemaToView } from './schema-to-view';\n\nexport interface MongoControlFamilyInstance\n extends ControlFamilyInstance<'mongo', MongoSchemaIR>,\n SchemaViewCapable<MongoSchemaIR> {\n validateContract(contractJson: unknown): Contract;\n}\n\nfunction extractDb(driver: ControlDriverInstance<'mongo', string>): Db {\n const mongoDriver = driver as ControlDriverInstance<'mongo', string> & { db?: Db };\n if (!mongoDriver.db) {\n throw new Error(\n 'Mongo control driver does not expose a db property. ' +\n 'Use createMongoControlDriver() from @prisma-next/adapter-mongo/control.',\n );\n }\n return mongoDriver.db;\n}\n\nclass MongoFamilyInstance implements MongoControlFamilyInstance {\n readonly familyId = 'mongo' as const;\n\n validateContract(contractJson: unknown): Contract {\n const validated = validateMongoContract<MongoContract>(contractJson);\n // MongoContract and Contract share structure but are typed independently;\n // validateMongoContract guarantees the shape, so the double cast is safe.\n return validated.contract as unknown as Contract;\n }\n\n async verify(options: {\n readonly driver: ControlDriverInstance<'mongo', string>;\n readonly contract: unknown;\n readonly expectedTargetId: string;\n readonly contractPath: string;\n readonly configPath?: string;\n }): Promise<VerifyDatabaseResult> {\n const { driver, contract: rawContract, expectedTargetId, contractPath, configPath } = options;\n const startTime = Date.now();\n\n const validated = validateMongoContract<MongoContract>(rawContract);\n const contract = validated.contract;\n\n const contractStorageHash = contract.storage.storageHash;\n const contractProfileHash = contract.profileHash;\n const contractTarget = contract.target;\n\n const baseOpts = {\n contractStorageHash,\n contractProfileHash,\n expectedTargetId,\n contractPath,\n ...ifDefined('configPath', configPath),\n };\n\n if (contractTarget !== expectedTargetId) {\n return buildVerifyResult({\n ...baseOpts,\n ok: false,\n code: VERIFY_CODE_TARGET_MISMATCH,\n summary: 'Target mismatch',\n actualTargetId: contractTarget,\n totalTime: Date.now() - startTime,\n });\n }\n\n const db = extractDb(driver);\n const marker = await readMarker(db);\n\n if (!marker) {\n return buildVerifyResult({\n ...baseOpts,\n ok: false,\n code: VERIFY_CODE_MARKER_MISSING,\n summary: 'Marker missing',\n totalTime: Date.now() - startTime,\n });\n }\n\n if (marker.storageHash !== contractStorageHash) {\n return buildVerifyResult({\n ...baseOpts,\n ok: false,\n code: VERIFY_CODE_HASH_MISMATCH,\n summary: 'Hash mismatch',\n marker,\n totalTime: Date.now() - startTime,\n });\n }\n\n if (contractProfileHash && marker.profileHash !== contractProfileHash) {\n return buildVerifyResult({\n ...baseOpts,\n ok: false,\n code: VERIFY_CODE_HASH_MISMATCH,\n summary: 'Hash mismatch',\n marker,\n totalTime: Date.now() - startTime,\n });\n }\n\n return buildVerifyResult({\n ...baseOpts,\n ok: true,\n summary: 'Database matches contract',\n marker,\n totalTime: Date.now() - startTime,\n });\n }\n\n async schemaVerify(options: {\n readonly driver: ControlDriverInstance<'mongo', string>;\n readonly contract: unknown;\n readonly strict: boolean;\n readonly contractPath: string;\n readonly configPath?: string;\n readonly frameworkComponents: ReadonlyArray<unknown>;\n }): Promise<VerifyDatabaseSchemaResult> {\n const { driver, contract: rawContract, strict, contractPath, configPath } = options;\n const startTime = Date.now();\n\n const validated = validateMongoContract<MongoContract>(rawContract);\n const contract = validated.contract;\n\n const db = extractDb(driver);\n const liveIR = await introspectSchema(db);\n const expectedIR = contractToMongoSchemaIR(contract);\n\n const { root, issues, counts } = diffMongoSchemas(liveIR, expectedIR, strict);\n\n const ok = counts.fail === 0;\n\n return {\n ok,\n ...ifDefined('code', ok ? undefined : VERIFY_CODE_SCHEMA_FAILURE),\n summary: ok ? 'Schema matches contract' : `Schema verification found ${counts.fail} issue(s)`,\n contract: {\n storageHash: contract.storage.storageHash,\n ...ifDefined('profileHash', contract.profileHash),\n },\n target: { expected: contract.target },\n schema: { issues, root, counts },\n meta: {\n ...ifDefined('contractPath', contractPath),\n ...ifDefined('configPath', configPath),\n strict,\n },\n timings: { total: Date.now() - startTime },\n };\n }\n\n async sign(options: {\n readonly driver: ControlDriverInstance<'mongo', string>;\n readonly contract: unknown;\n readonly contractPath: string;\n readonly configPath?: string;\n }): Promise<SignDatabaseResult> {\n const { driver, contract: rawContract, contractPath, configPath } = options;\n const startTime = Date.now();\n\n const validated = validateMongoContract<MongoContract>(rawContract);\n const contract = validated.contract;\n\n const contractStorageHash = contract.storage.storageHash;\n const contractProfileHash = contract.profileHash;\n\n const db = extractDb(driver);\n\n const existingMarker = await readMarker(db);\n\n let markerCreated = false;\n let markerUpdated = false;\n let previousHashes: { storageHash?: string; profileHash?: string } | undefined;\n\n if (!existingMarker) {\n await initMarker(db, {\n storageHash: contractStorageHash,\n profileHash: contractProfileHash,\n });\n markerCreated = true;\n } else {\n const storageHashMatches = existingMarker.storageHash === contractStorageHash;\n const profileHashMatches = existingMarker.profileHash === contractProfileHash;\n\n if (!storageHashMatches || !profileHashMatches) {\n previousHashes = {\n storageHash: existingMarker.storageHash,\n profileHash: existingMarker.profileHash,\n };\n const updated = await updateMarker(db, existingMarker.storageHash, {\n storageHash: contractStorageHash,\n profileHash: contractProfileHash,\n });\n if (!updated) {\n throw new Error('CAS conflict: marker was modified by another process during sign');\n }\n markerUpdated = true;\n }\n }\n\n let summary: string;\n if (markerCreated) {\n summary = 'Database signed (marker created)';\n } else if (markerUpdated) {\n summary = `Database signed (marker updated from ${previousHashes?.storageHash ?? 'unknown'})`;\n } else {\n summary = 'Database already signed with this contract';\n }\n\n return {\n ok: true,\n summary,\n contract: {\n storageHash: contractStorageHash,\n profileHash: contractProfileHash,\n },\n target: {\n expected: contract.target,\n actual: contract.target,\n },\n marker: {\n created: markerCreated,\n updated: markerUpdated,\n ...ifDefined('previous', previousHashes),\n },\n meta: {\n contractPath,\n ...ifDefined('configPath', configPath),\n },\n timings: {\n total: Date.now() - startTime,\n },\n };\n }\n\n async readMarker(options: {\n readonly driver: ControlDriverInstance<'mongo', string>;\n }): Promise<ContractMarkerRecord | null> {\n const db = extractDb(options.driver);\n return readMarker(db);\n }\n\n async introspect(options: {\n readonly driver: ControlDriverInstance<'mongo', string>;\n readonly contract?: unknown;\n }): Promise<MongoSchemaIR> {\n const db = extractDb(options.driver);\n return introspectSchema(db);\n }\n\n toSchemaView(schema: MongoSchemaIR): CoreSchemaView {\n return mongoSchemaToView(schema);\n }\n}\n\nfunction buildVerifyResult(opts: {\n ok: boolean;\n code?: string;\n summary: string;\n contractStorageHash: string;\n contractProfileHash?: string;\n marker?: ContractMarkerRecord;\n expectedTargetId: string;\n actualTargetId?: string;\n contractPath: string;\n configPath?: string;\n totalTime: number;\n}): VerifyDatabaseResult {\n return {\n ok: opts.ok,\n ...ifDefined('code', opts.code),\n summary: opts.summary,\n contract: {\n storageHash: opts.contractStorageHash,\n ...ifDefined('profileHash', opts.contractProfileHash),\n },\n ...ifDefined(\n 'marker',\n opts.marker\n ? { storageHash: opts.marker.storageHash, profileHash: opts.marker.profileHash }\n : undefined,\n ),\n target: {\n expected: opts.expectedTargetId,\n ...ifDefined('actual', opts.actualTargetId),\n },\n meta: {\n contractPath: opts.contractPath,\n ...ifDefined('configPath', opts.configPath),\n },\n timings: { total: opts.totalTime },\n };\n}\n\nexport function createMongoFamilyInstance(_controlStack: ControlStack): MongoControlFamilyInstance {\n return new MongoFamilyInstance();\n}\n","import type {\n ControlFamilyDescriptor,\n ControlStack,\n} from '@prisma-next/framework-components/control';\nimport { mongoEmission } from '@prisma-next/mongo-emitter';\nimport { createMongoFamilyInstance, type MongoControlFamilyInstance } from './control-instance';\n\nclass MongoFamilyDescriptor\n implements ControlFamilyDescriptor<'mongo', MongoControlFamilyInstance>\n{\n readonly kind = 'family' as const;\n readonly id = 'mongo';\n readonly familyId = 'mongo' as const;\n readonly version = '0.0.1';\n readonly emission = mongoEmission;\n\n create<TTargetId extends string>(\n stack: ControlStack<'mongo', TTargetId>,\n ): MongoControlFamilyInstance {\n return createMongoFamilyInstance(stack);\n }\n}\n\nexport const mongoFamilyDescriptor: ControlFamilyDescriptor<'mongo', MongoControlFamilyInstance> =\n new MongoFamilyDescriptor();\n","/**\n * Mongo's in-process implementation of the `emit` capability on\n * `TargetMigrationsCapability`.\n *\n * The CLI's `migration emit` (and `migration plan`'s inline emit) dispatches\n * here for any target that does not implement `resolveDescriptors`. Two\n * authoring shapes are accepted:\n *\n * 1. Class subclass (canonical):\n * class M extends Migration { override plan() { return [...] } }\n * export default M;\n * Migration.run(import.meta.url, M);\n *\n * 2. Factory function returning a Migration-satisfying object:\n * export default () => ({ plan() { return [createCollection(\"users\")] } });\n *\n * We dynamic-import the file (so that any structured errors thrown by\n * `placeholder(...)` propagate as real exceptions to the CLI), dispatch on\n * the export's shape (class subclass vs. callable function), and persist\n * `ops.json` via the framework I/O helper. `Migration.run` already guards\n * itself against firing when the file is imported rather than run as the\n * main module, so this is safe to call from inside the CLI process.\n *\n * Attestation (computing and writing `migrationId` to `manifest.json`) is\n * owned by the framework's `emitMigration` helper, not this capability.\n */\n\nimport { stat } from 'node:fs/promises';\nimport { pathToFileURL } from 'node:url';\nimport {\n errorMigrationFileMissing,\n errorMigrationInvalidDefaultExport,\n errorMigrationPlanNotArray,\n} from '@prisma-next/errors/migration';\nimport type {\n MigrationPlanOperation,\n TargetMigrationsCapability,\n} from '@prisma-next/framework-components/control';\nimport { writeMigrationOps } from '@prisma-next/migration-tools/io';\nimport { Migration } from '@prisma-next/migration-tools/migration';\nimport { join } from 'pathe';\n\nconst MIGRATION_TS_FILE = 'migration.ts';\n\ntype EmitOptions = Parameters<NonNullable<TargetMigrationsCapability['emit']>>[0];\n\n/**\n * Implementation of `TargetMigrationsCapability.emit` for Mongo.\n *\n * Loads `<dir>/migration.ts` and dispatches on the default export's shape:\n * if it is a `Migration` subclass, instantiates it and calls `plan()`;\n * otherwise invokes it as a factory function, validates the returned value\n * has a `plan()` method, and calls it.\n * Writes `ops.json` and returns the operations for the framework helper to\n * render. Attestation (`migrationId` in `manifest.json`) is the framework\n * helper's responsibility; this capability MUST NOT call `attestMigration`\n * itself.\n */\nexport async function mongoEmit(options: EmitOptions): Promise<readonly MigrationPlanOperation[]> {\n const filePath = join(options.dir, MIGRATION_TS_FILE);\n\n try {\n await stat(filePath);\n } catch {\n throw errorMigrationFileMissing(options.dir);\n }\n\n const fileUrl = pathToFileURL(filePath).href;\n const mod = (await import(fileUrl)) as { default?: unknown };\n\n const MigrationExport = mod.default;\n if (typeof MigrationExport !== 'function') {\n throw errorMigrationInvalidDefaultExport(\n options.dir,\n `default export of type ${typeof MigrationExport}`,\n );\n }\n\n let migration: { plan(): unknown };\n if (MigrationExport.prototype instanceof Migration) {\n migration = new (MigrationExport as new () => Migration)();\n } else {\n let factoryResult: unknown;\n try {\n factoryResult = await (MigrationExport as () => unknown | Promise<unknown>)();\n } catch (error) {\n if (error instanceof TypeError && /cannot be invoked without 'new'/i.test(error.message)) {\n throw errorMigrationInvalidDefaultExport(\n options.dir,\n 'a default export that does not extend Migration (from @prisma-next/migration-tools/migration)',\n );\n }\n throw error;\n }\n if (\n typeof factoryResult !== 'object' ||\n factoryResult === null ||\n typeof (factoryResult as { plan?: unknown }).plan !== 'function'\n ) {\n throw errorMigrationInvalidDefaultExport(\n options.dir,\n `factory must return an object with a plan() method; got ${describeValue(factoryResult)}`,\n );\n }\n migration = factoryResult as { plan(): unknown };\n }\n\n const operations: unknown = migration.plan();\n\n if (!Array.isArray(operations)) {\n throw errorMigrationPlanNotArray(options.dir, describeValue(operations));\n }\n\n await writeMigrationOps(options.dir, operations);\n\n return operations;\n}\n\nfunction describeValue(value: unknown): string {\n if (value === null) return 'null';\n return `a value of type ${typeof value}`;\n}\n","import { createMongoRunnerDeps } from '@prisma-next/adapter-mongo/control';\nimport type { Contract } from '@prisma-next/contract/types';\nimport type { MigratableTargetDescriptor } from '@prisma-next/framework-components/control';\nimport type { MongoContract } from '@prisma-next/mongo-contract';\nimport {\n contractToMongoSchemaIR,\n MongoMigrationPlanner,\n MongoMigrationRunner,\n type MongoRunnerDependencies,\n} from '@prisma-next/target-mongo/control';\nimport mongoTargetDescriptorMeta from '@prisma-next/target-mongo/pack';\nimport type { MongoControlFamilyInstance } from './control-instance';\nimport { mongoEmit } from './mongo-emit';\n\nexport const mongoTargetDescriptor: MigratableTargetDescriptor<\n 'mongo',\n 'mongo',\n MongoControlFamilyInstance\n> = {\n ...mongoTargetDescriptorMeta,\n migrations: {\n createPlanner(_family: MongoControlFamilyInstance) {\n return new MongoMigrationPlanner();\n },\n createRunner(_family: MongoControlFamilyInstance) {\n // Deps are bound to the first driver passed to execute() and cached for\n // subsequent calls. Callers must not change the driver between calls.\n let cachedDeps: MongoRunnerDependencies | undefined;\n return {\n async execute(options) {\n cachedDeps ??= createMongoRunnerDeps(options.driver);\n const { driver: _, ...runnerOptions } = options;\n const runner = new MongoMigrationRunner(cachedDeps);\n return runner.execute(runnerOptions);\n },\n };\n },\n contractToSchema(contract: Contract | null) {\n return contractToMongoSchemaIR(contract as MongoContract | null);\n },\n emit: mongoEmit,\n },\n create() {\n return { familyId: 'mongo' as const, targetId: 'mongo' as const };\n },\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"control.mjs","names":["issues: SchemaIssue[]","collectionChildren: SchemaVerificationNode[]","nodes: SchemaVerificationNode[]","children: SchemaTreeNode[]","options: string[]","validatorChildren: SchemaTreeNode[]","optLabels: string[]","previousHashes: { storageHash?: string; profileHash?: string } | undefined","summary: string","mongoFamilyDescriptor: ControlFamilyDescriptor<'mongo', MongoControlFamilyInstance>","plan: MigrationPlan","factoryResult: unknown","operations: unknown","mongoTargetDescriptor: MigratableTargetDescriptor<\n 'mongo',\n 'mongo',\n MongoControlFamilyInstance\n>","cachedDeps: MongoRunnerDependencies | undefined"],"sources":["../src/core/schema-diff.ts","../src/core/schema-to-view.ts","../src/core/control-instance.ts","../src/core/control-descriptor.ts","../src/core/mongo-emit.ts","../src/core/mongo-target-descriptor.ts"],"sourcesContent":["import type {\n SchemaIssue,\n SchemaVerificationNode,\n} from '@prisma-next/framework-components/control';\nimport type {\n MongoSchemaCollection,\n MongoSchemaIndex,\n MongoSchemaIR,\n} from '@prisma-next/mongo-schema-ir';\nimport { canonicalize, deepEqual } from '@prisma-next/mongo-schema-ir';\n\nexport function diffMongoSchemas(\n live: MongoSchemaIR,\n expected: MongoSchemaIR,\n strict: boolean,\n): {\n root: SchemaVerificationNode;\n issues: SchemaIssue[];\n counts: { pass: number; warn: number; fail: number; totalNodes: number };\n} {\n const issues: SchemaIssue[] = [];\n const collectionChildren: SchemaVerificationNode[] = [];\n let pass = 0;\n let warn = 0;\n let fail = 0;\n\n const allNames = new Set([...live.collectionNames, ...expected.collectionNames]);\n\n for (const name of [...allNames].sort()) {\n const liveColl = live.collection(name);\n const expectedColl = expected.collection(name);\n\n if (!liveColl && expectedColl) {\n issues.push({\n kind: 'missing_table',\n table: name,\n message: `Collection \"${name}\" is missing from the database`,\n });\n collectionChildren.push({\n status: 'fail',\n kind: 'collection',\n name,\n contractPath: `storage.collections.${name}`,\n code: 'MISSING_COLLECTION',\n message: `Collection \"${name}\" is missing`,\n expected: name,\n actual: null,\n children: [],\n });\n fail++;\n continue;\n }\n\n if (liveColl && !expectedColl) {\n const status = strict ? 'fail' : 'warn';\n issues.push({\n kind: 'extra_table',\n table: name,\n message: `Extra collection \"${name}\" exists in the database but not in the contract`,\n });\n collectionChildren.push({\n status,\n kind: 'collection',\n name,\n contractPath: `storage.collections.${name}`,\n code: 'EXTRA_COLLECTION',\n message: `Extra collection \"${name}\" found`,\n expected: null,\n actual: name,\n children: [],\n });\n if (status === 'fail') fail++;\n else warn++;\n continue;\n }\n\n const lc = liveColl as MongoSchemaCollection;\n const ec = expectedColl as MongoSchemaCollection;\n const indexChildren = diffIndexes(name, lc, ec, strict, issues);\n const validatorChildren = diffValidator(name, lc, ec, strict, issues);\n const optionsChildren = diffOptions(name, lc, ec, strict, issues);\n const children = [...indexChildren, ...validatorChildren, ...optionsChildren];\n\n const worstStatus = children.reduce<'pass' | 'warn' | 'fail'>(\n (s, c) => (c.status === 'fail' ? 'fail' : c.status === 'warn' && s !== 'fail' ? 'warn' : s),\n 'pass',\n );\n\n for (const c of children) {\n if (c.status === 'pass') pass++;\n else if (c.status === 'warn') warn++;\n else fail++;\n }\n\n if (children.length === 0) {\n pass++;\n }\n\n collectionChildren.push({\n status: worstStatus,\n kind: 'collection',\n name,\n contractPath: `storage.collections.${name}`,\n code: worstStatus === 'pass' ? 'MATCH' : 'DRIFT',\n message:\n worstStatus === 'pass' ? `Collection \"${name}\" matches` : `Collection \"${name}\" has drift`,\n expected: name,\n actual: name,\n children,\n });\n }\n\n const rootStatus = fail > 0 ? 'fail' : warn > 0 ? 'warn' : 'pass';\n const totalNodes = pass + warn + fail + collectionChildren.length;\n\n const root: SchemaVerificationNode = {\n status: rootStatus,\n kind: 'root',\n name: 'mongo-schema',\n contractPath: 'storage',\n code: rootStatus === 'pass' ? 'MATCH' : 'DRIFT',\n message: rootStatus === 'pass' ? 'Schema matches' : 'Schema has drift',\n expected: null,\n actual: null,\n children: collectionChildren,\n };\n\n return { root, issues, counts: { pass, warn, fail, totalNodes } };\n}\n\nfunction buildIndexLookupKey(index: MongoSchemaIndex): string {\n const keys = index.keys.map((k) => `${k.field}:${k.direction}`).join(',');\n const opts = [\n index.unique ? 'unique' : '',\n index.sparse ? 'sparse' : '',\n index.expireAfterSeconds != null ? `ttl:${index.expireAfterSeconds}` : '',\n index.partialFilterExpression ? `pfe:${canonicalize(index.partialFilterExpression)}` : '',\n index.wildcardProjection ? `wp:${canonicalize(index.wildcardProjection)}` : '',\n index.collation ? `col:${canonicalize(index.collation)}` : '',\n index.weights ? `wt:${canonicalize(index.weights)}` : '',\n index.default_language ? `dl:${index.default_language}` : '',\n index.language_override ? `lo:${index.language_override}` : '',\n ]\n .filter(Boolean)\n .join(';');\n return opts ? `${keys}|${opts}` : keys;\n}\n\nfunction formatIndexName(index: MongoSchemaIndex): string {\n return index.keys.map((k) => `${k.field}:${k.direction}`).join(', ');\n}\n\nfunction diffIndexes(\n collName: string,\n live: MongoSchemaCollection,\n expected: MongoSchemaCollection,\n strict: boolean,\n issues: SchemaIssue[],\n): SchemaVerificationNode[] {\n const nodes: SchemaVerificationNode[] = [];\n const liveLookup = new Map<string, MongoSchemaIndex>();\n for (const idx of live.indexes) liveLookup.set(buildIndexLookupKey(idx), idx);\n\n const expectedLookup = new Map<string, MongoSchemaIndex>();\n for (const idx of expected.indexes) expectedLookup.set(buildIndexLookupKey(idx), idx);\n\n for (const [key, idx] of expectedLookup) {\n if (liveLookup.has(key)) {\n nodes.push({\n status: 'pass',\n kind: 'index',\n name: formatIndexName(idx),\n contractPath: `storage.collections.${collName}.indexes`,\n code: 'MATCH',\n message: `Index ${formatIndexName(idx)} matches`,\n expected: key,\n actual: key,\n children: [],\n });\n } else {\n issues.push({\n kind: 'index_mismatch',\n table: collName,\n indexOrConstraint: formatIndexName(idx),\n message: `Index ${formatIndexName(idx)} missing on collection \"${collName}\"`,\n });\n nodes.push({\n status: 'fail',\n kind: 'index',\n name: formatIndexName(idx),\n contractPath: `storage.collections.${collName}.indexes`,\n code: 'MISSING_INDEX',\n message: `Index ${formatIndexName(idx)} missing`,\n expected: key,\n actual: null,\n children: [],\n });\n }\n }\n\n for (const [key, idx] of liveLookup) {\n if (!expectedLookup.has(key)) {\n const status = strict ? 'fail' : 'warn';\n issues.push({\n kind: 'extra_index',\n table: collName,\n indexOrConstraint: formatIndexName(idx),\n message: `Extra index ${formatIndexName(idx)} on collection \"${collName}\"`,\n });\n nodes.push({\n status,\n kind: 'index',\n name: formatIndexName(idx),\n contractPath: `storage.collections.${collName}.indexes`,\n code: 'EXTRA_INDEX',\n message: `Extra index ${formatIndexName(idx)}`,\n expected: null,\n actual: key,\n children: [],\n });\n }\n }\n\n return nodes;\n}\n\nfunction diffValidator(\n collName: string,\n live: MongoSchemaCollection,\n expected: MongoSchemaCollection,\n strict: boolean,\n issues: SchemaIssue[],\n): SchemaVerificationNode[] {\n if (!live.validator && !expected.validator) return [];\n\n if (expected.validator && !live.validator) {\n issues.push({\n kind: 'type_missing',\n table: collName,\n message: `Validator missing on collection \"${collName}\"`,\n });\n return [\n {\n status: 'fail',\n kind: 'validator',\n name: 'validator',\n contractPath: `storage.collections.${collName}.validator`,\n code: 'MISSING_VALIDATOR',\n message: 'Validator missing',\n expected: canonicalize(expected.validator.jsonSchema),\n actual: null,\n children: [],\n },\n ];\n }\n\n if (!expected.validator && live.validator) {\n const status = strict ? 'fail' : 'warn';\n issues.push({\n kind: 'extra_validator',\n table: collName,\n message: `Extra validator on collection \"${collName}\"`,\n });\n return [\n {\n status,\n kind: 'validator',\n name: 'validator',\n contractPath: `storage.collections.${collName}.validator`,\n code: 'EXTRA_VALIDATOR',\n message: 'Extra validator found',\n expected: null,\n actual: canonicalize(live.validator.jsonSchema),\n children: [],\n },\n ];\n }\n\n const liveVal = live.validator as NonNullable<typeof live.validator>;\n const expectedVal = expected.validator as NonNullable<typeof expected.validator>;\n const liveSchema = canonicalize(liveVal.jsonSchema);\n const expectedSchema = canonicalize(expectedVal.jsonSchema);\n\n if (\n liveSchema !== expectedSchema ||\n liveVal.validationLevel !== expectedVal.validationLevel ||\n liveVal.validationAction !== expectedVal.validationAction\n ) {\n issues.push({\n kind: 'type_mismatch',\n table: collName,\n expected: expectedSchema,\n actual: liveSchema,\n message: `Validator mismatch on collection \"${collName}\"`,\n });\n return [\n {\n status: 'fail',\n kind: 'validator',\n name: 'validator',\n contractPath: `storage.collections.${collName}.validator`,\n code: 'VALIDATOR_MISMATCH',\n message: 'Validator mismatch',\n expected: {\n jsonSchema: expectedVal.jsonSchema,\n validationLevel: expectedVal.validationLevel,\n validationAction: expectedVal.validationAction,\n },\n actual: {\n jsonSchema: liveVal.jsonSchema,\n validationLevel: liveVal.validationLevel,\n validationAction: liveVal.validationAction,\n },\n children: [],\n },\n ];\n }\n\n return [\n {\n status: 'pass',\n kind: 'validator',\n name: 'validator',\n contractPath: `storage.collections.${collName}.validator`,\n code: 'MATCH',\n message: 'Validator matches',\n expected: expectedSchema,\n actual: liveSchema,\n children: [],\n },\n ];\n}\n\nfunction diffOptions(\n collName: string,\n live: MongoSchemaCollection,\n expected: MongoSchemaCollection,\n strict: boolean,\n issues: SchemaIssue[],\n): SchemaVerificationNode[] {\n if (!live.options && !expected.options) return [];\n\n if (!expected.options && live.options) {\n const status = strict ? 'fail' : 'warn';\n issues.push({\n kind: 'type_mismatch',\n table: collName,\n actual: canonicalize(live.options),\n message: `Extra collection options on \"${collName}\"`,\n });\n return [\n {\n status,\n kind: 'options',\n name: 'options',\n contractPath: `storage.collections.${collName}.options`,\n code: 'EXTRA_OPTIONS',\n message: 'Extra collection options found',\n expected: null,\n actual: live.options,\n children: [],\n },\n ];\n }\n\n if (deepEqual(live.options, expected.options)) {\n return [\n {\n status: 'pass',\n kind: 'options',\n name: 'options',\n contractPath: `storage.collections.${collName}.options`,\n code: 'MATCH',\n message: 'Collection options match',\n expected: canonicalize(expected.options),\n actual: canonicalize(live.options),\n children: [],\n },\n ];\n }\n\n issues.push({\n kind: 'type_mismatch',\n table: collName,\n expected: canonicalize(expected.options),\n actual: canonicalize(live.options),\n message: `Collection options mismatch on \"${collName}\"`,\n });\n return [\n {\n status: 'fail',\n kind: 'options',\n name: 'options',\n contractPath: `storage.collections.${collName}.options`,\n code: 'OPTIONS_MISMATCH',\n message: 'Collection options mismatch',\n expected: expected.options,\n actual: live.options,\n children: [],\n },\n ];\n}\n","import type { CoreSchemaView } from '@prisma-next/framework-components/control';\nimport { SchemaTreeNode } from '@prisma-next/framework-components/control';\nimport type { MongoSchemaCollection, MongoSchemaIR } from '@prisma-next/mongo-schema-ir';\nimport { ifDefined } from '@prisma-next/utils/defined';\n\nexport function mongoSchemaToView(schema: MongoSchemaIR): CoreSchemaView {\n const collectionNodes = schema.collections.map((collection) =>\n collectionToSchemaNode(collection.name, collection),\n );\n\n return {\n root: new SchemaTreeNode({\n kind: 'root',\n id: 'mongo-schema',\n label: 'database',\n ...ifDefined('children', collectionNodes.length > 0 ? collectionNodes : undefined),\n }),\n };\n}\n\nfunction collectionToSchemaNode(name: string, collection: MongoSchemaCollection): SchemaTreeNode {\n const children: SchemaTreeNode[] = [];\n\n for (const index of collection.indexes) {\n const keysSummary = index.keys\n .map((k) => {\n if (k.direction === 1) return k.field;\n if (k.direction === -1) return `${k.field} desc`;\n return `${k.field} ${k.direction}`;\n })\n .join(', ');\n const prefix = index.unique ? 'unique index' : 'index';\n const options: string[] = [];\n if (index.sparse) options.push('sparse');\n if (index.expireAfterSeconds != null) options.push(`ttl: ${index.expireAfterSeconds}s`);\n if (index.partialFilterExpression) options.push('partial');\n const optsSuffix = options.length > 0 ? ` (${options.join(', ')})` : '';\n\n children.push(\n new SchemaTreeNode({\n kind: 'index',\n id: `index-${name}-${index.keys.map((k) => `${k.field}_${k.direction}`).join('_')}`,\n label: `${prefix} (${keysSummary})${optsSuffix}`,\n meta: {\n keys: index.keys,\n unique: index.unique,\n ...ifDefined('sparse', index.sparse || undefined),\n ...ifDefined('expireAfterSeconds', index.expireAfterSeconds ?? undefined),\n ...ifDefined('partialFilterExpression', index.partialFilterExpression ?? undefined),\n },\n }),\n );\n }\n\n if (collection.validator) {\n const validatorChildren: SchemaTreeNode[] = [];\n const jsonSchema = collection.validator.jsonSchema as Record<string, unknown>;\n const properties = jsonSchema['properties'] as\n | Record<string, Record<string, unknown>>\n | undefined;\n const required = new Set((jsonSchema['required'] as string[] | undefined) ?? []);\n\n if (properties) {\n for (const [propName, propDef] of Object.entries(properties)) {\n const bsonType = (propDef['bsonType'] as string) ?? 'unknown';\n const suffix = required.has(propName) ? ' (required)' : '';\n validatorChildren.push(\n new SchemaTreeNode({\n kind: 'field',\n id: `field-${name}-${propName}`,\n label: `${propName}: ${bsonType}${suffix}`,\n }),\n );\n }\n }\n\n children.push(\n new SchemaTreeNode({\n kind: 'field',\n id: `validator-${name}`,\n label: `validator (level: ${collection.validator.validationLevel}, action: ${collection.validator.validationAction})`,\n meta: {\n validationLevel: collection.validator.validationLevel,\n validationAction: collection.validator.validationAction,\n jsonSchema: collection.validator.jsonSchema,\n },\n ...ifDefined('children', validatorChildren.length > 0 ? validatorChildren : undefined),\n }),\n );\n }\n\n if (collection.options) {\n const opts = collection.options;\n const optLabels: string[] = [];\n if (opts.capped) optLabels.push('capped');\n if (opts.timeseries) optLabels.push('timeseries');\n if (opts.collation) optLabels.push('collation');\n if (opts.changeStreamPreAndPostImages) optLabels.push('changeStreamPreAndPostImages');\n if (opts.clusteredIndex) optLabels.push('clusteredIndex');\n\n if (optLabels.length > 0) {\n children.push(\n new SchemaTreeNode({\n kind: 'field',\n id: `options-${name}`,\n label: `options (${optLabels.join(', ')})`,\n meta: {\n ...ifDefined('capped', opts.capped ?? undefined),\n ...ifDefined('timeseries', opts.timeseries ?? undefined),\n ...ifDefined('collation', opts.collation ?? undefined),\n ...ifDefined(\n 'changeStreamPreAndPostImages',\n opts.changeStreamPreAndPostImages ?? undefined,\n ),\n ...ifDefined('clusteredIndex', opts.clusteredIndex ?? undefined),\n },\n }),\n );\n }\n }\n\n return new SchemaTreeNode({\n kind: 'collection',\n id: `collection-${name}`,\n label: `collection ${name}`,\n ...ifDefined('children', children.length > 0 ? children : undefined),\n });\n}\n","import { introspectSchema } from '@prisma-next/adapter-mongo/control';\nimport type { Contract, ContractMarkerRecord } from '@prisma-next/contract/types';\nimport type {\n ControlDriverInstance,\n ControlFamilyInstance,\n ControlStack,\n CoreSchemaView,\n SchemaViewCapable,\n SignDatabaseResult,\n VerifyDatabaseResult,\n VerifyDatabaseSchemaResult,\n} from '@prisma-next/framework-components/control';\nimport {\n VERIFY_CODE_HASH_MISMATCH,\n VERIFY_CODE_MARKER_MISSING,\n VERIFY_CODE_SCHEMA_FAILURE,\n VERIFY_CODE_TARGET_MISMATCH,\n} from '@prisma-next/framework-components/control';\nimport type { MongoContract } from '@prisma-next/mongo-contract';\nimport { validateMongoContract } from '@prisma-next/mongo-contract';\nimport type { MongoSchemaIR } from '@prisma-next/mongo-schema-ir';\nimport {\n contractToMongoSchemaIR,\n initMarker,\n readMarker,\n updateMarker,\n} from '@prisma-next/target-mongo/control';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { Db } from 'mongodb';\nimport { diffMongoSchemas } from './schema-diff';\nimport { mongoSchemaToView } from './schema-to-view';\n\nexport interface MongoControlFamilyInstance\n extends ControlFamilyInstance<'mongo', MongoSchemaIR>,\n SchemaViewCapable<MongoSchemaIR> {\n validateContract(contractJson: unknown): Contract;\n}\n\nfunction extractDb(driver: ControlDriverInstance<'mongo', string>): Db {\n const mongoDriver = driver as ControlDriverInstance<'mongo', string> & { db?: Db };\n if (!mongoDriver.db) {\n throw new Error(\n 'Mongo control driver does not expose a db property. ' +\n 'Use createMongoControlDriver() from @prisma-next/adapter-mongo/control.',\n );\n }\n return mongoDriver.db;\n}\n\nclass MongoFamilyInstance implements MongoControlFamilyInstance {\n readonly familyId = 'mongo' as const;\n\n validateContract(contractJson: unknown): Contract {\n const validated = validateMongoContract<MongoContract>(contractJson);\n // MongoContract and Contract share structure but are typed independently;\n // validateMongoContract guarantees the shape, so the double cast is safe.\n return validated.contract as unknown as Contract;\n }\n\n async verify(options: {\n readonly driver: ControlDriverInstance<'mongo', string>;\n readonly contract: unknown;\n readonly expectedTargetId: string;\n readonly contractPath: string;\n readonly configPath?: string;\n }): Promise<VerifyDatabaseResult> {\n const { driver, contract: rawContract, expectedTargetId, contractPath, configPath } = options;\n const startTime = Date.now();\n\n const validated = validateMongoContract<MongoContract>(rawContract);\n const contract = validated.contract;\n\n const contractStorageHash = contract.storage.storageHash;\n const contractProfileHash = contract.profileHash;\n const contractTarget = contract.target;\n\n const baseOpts = {\n contractStorageHash,\n contractProfileHash,\n expectedTargetId,\n contractPath,\n ...ifDefined('configPath', configPath),\n };\n\n if (contractTarget !== expectedTargetId) {\n return buildVerifyResult({\n ...baseOpts,\n ok: false,\n code: VERIFY_CODE_TARGET_MISMATCH,\n summary: 'Target mismatch',\n actualTargetId: contractTarget,\n totalTime: Date.now() - startTime,\n });\n }\n\n const db = extractDb(driver);\n const marker = await readMarker(db);\n\n if (!marker) {\n return buildVerifyResult({\n ...baseOpts,\n ok: false,\n code: VERIFY_CODE_MARKER_MISSING,\n summary: 'Marker missing',\n totalTime: Date.now() - startTime,\n });\n }\n\n if (marker.storageHash !== contractStorageHash) {\n return buildVerifyResult({\n ...baseOpts,\n ok: false,\n code: VERIFY_CODE_HASH_MISMATCH,\n summary: 'Hash mismatch',\n marker,\n totalTime: Date.now() - startTime,\n });\n }\n\n if (contractProfileHash && marker.profileHash !== contractProfileHash) {\n return buildVerifyResult({\n ...baseOpts,\n ok: false,\n code: VERIFY_CODE_HASH_MISMATCH,\n summary: 'Hash mismatch',\n marker,\n totalTime: Date.now() - startTime,\n });\n }\n\n return buildVerifyResult({\n ...baseOpts,\n ok: true,\n summary: 'Database matches contract',\n marker,\n totalTime: Date.now() - startTime,\n });\n }\n\n async schemaVerify(options: {\n readonly driver: ControlDriverInstance<'mongo', string>;\n readonly contract: unknown;\n readonly strict: boolean;\n readonly contractPath: string;\n readonly configPath?: string;\n readonly frameworkComponents: ReadonlyArray<unknown>;\n }): Promise<VerifyDatabaseSchemaResult> {\n const { driver, contract: rawContract, strict, contractPath, configPath } = options;\n const startTime = Date.now();\n\n const validated = validateMongoContract<MongoContract>(rawContract);\n const contract = validated.contract;\n\n const db = extractDb(driver);\n const liveIR = await introspectSchema(db);\n const expectedIR = contractToMongoSchemaIR(contract);\n\n const { root, issues, counts } = diffMongoSchemas(liveIR, expectedIR, strict);\n\n const ok = counts.fail === 0;\n\n return {\n ok,\n ...ifDefined('code', ok ? undefined : VERIFY_CODE_SCHEMA_FAILURE),\n summary: ok ? 'Schema matches contract' : `Schema verification found ${counts.fail} issue(s)`,\n contract: {\n storageHash: contract.storage.storageHash,\n ...ifDefined('profileHash', contract.profileHash),\n },\n target: { expected: contract.target },\n schema: { issues, root, counts },\n meta: {\n ...ifDefined('contractPath', contractPath),\n ...ifDefined('configPath', configPath),\n strict,\n },\n timings: { total: Date.now() - startTime },\n };\n }\n\n async sign(options: {\n readonly driver: ControlDriverInstance<'mongo', string>;\n readonly contract: unknown;\n readonly contractPath: string;\n readonly configPath?: string;\n }): Promise<SignDatabaseResult> {\n const { driver, contract: rawContract, contractPath, configPath } = options;\n const startTime = Date.now();\n\n const validated = validateMongoContract<MongoContract>(rawContract);\n const contract = validated.contract;\n\n const contractStorageHash = contract.storage.storageHash;\n const contractProfileHash = contract.profileHash;\n\n const db = extractDb(driver);\n\n const existingMarker = await readMarker(db);\n\n let markerCreated = false;\n let markerUpdated = false;\n let previousHashes: { storageHash?: string; profileHash?: string } | undefined;\n\n if (!existingMarker) {\n await initMarker(db, {\n storageHash: contractStorageHash,\n profileHash: contractProfileHash,\n });\n markerCreated = true;\n } else {\n const storageHashMatches = existingMarker.storageHash === contractStorageHash;\n const profileHashMatches = existingMarker.profileHash === contractProfileHash;\n\n if (!storageHashMatches || !profileHashMatches) {\n previousHashes = {\n storageHash: existingMarker.storageHash,\n profileHash: existingMarker.profileHash,\n };\n const updated = await updateMarker(db, existingMarker.storageHash, {\n storageHash: contractStorageHash,\n profileHash: contractProfileHash,\n });\n if (!updated) {\n throw new Error('CAS conflict: marker was modified by another process during sign');\n }\n markerUpdated = true;\n }\n }\n\n let summary: string;\n if (markerCreated) {\n summary = 'Database signed (marker created)';\n } else if (markerUpdated) {\n summary = `Database signed (marker updated from ${previousHashes?.storageHash ?? 'unknown'})`;\n } else {\n summary = 'Database already signed with this contract';\n }\n\n return {\n ok: true,\n summary,\n contract: {\n storageHash: contractStorageHash,\n profileHash: contractProfileHash,\n },\n target: {\n expected: contract.target,\n actual: contract.target,\n },\n marker: {\n created: markerCreated,\n updated: markerUpdated,\n ...ifDefined('previous', previousHashes),\n },\n meta: {\n contractPath,\n ...ifDefined('configPath', configPath),\n },\n timings: {\n total: Date.now() - startTime,\n },\n };\n }\n\n async readMarker(options: {\n readonly driver: ControlDriverInstance<'mongo', string>;\n }): Promise<ContractMarkerRecord | null> {\n const db = extractDb(options.driver);\n return readMarker(db);\n }\n\n async introspect(options: {\n readonly driver: ControlDriverInstance<'mongo', string>;\n readonly contract?: unknown;\n }): Promise<MongoSchemaIR> {\n const db = extractDb(options.driver);\n return introspectSchema(db);\n }\n\n toSchemaView(schema: MongoSchemaIR): CoreSchemaView {\n return mongoSchemaToView(schema);\n }\n}\n\nfunction buildVerifyResult(opts: {\n ok: boolean;\n code?: string;\n summary: string;\n contractStorageHash: string;\n contractProfileHash?: string;\n marker?: ContractMarkerRecord;\n expectedTargetId: string;\n actualTargetId?: string;\n contractPath: string;\n configPath?: string;\n totalTime: number;\n}): VerifyDatabaseResult {\n return {\n ok: opts.ok,\n ...ifDefined('code', opts.code),\n summary: opts.summary,\n contract: {\n storageHash: opts.contractStorageHash,\n ...ifDefined('profileHash', opts.contractProfileHash),\n },\n ...ifDefined(\n 'marker',\n opts.marker\n ? { storageHash: opts.marker.storageHash, profileHash: opts.marker.profileHash }\n : undefined,\n ),\n target: {\n expected: opts.expectedTargetId,\n ...ifDefined('actual', opts.actualTargetId),\n },\n meta: {\n contractPath: opts.contractPath,\n ...ifDefined('configPath', opts.configPath),\n },\n timings: { total: opts.totalTime },\n };\n}\n\nexport function createMongoFamilyInstance(_controlStack: ControlStack): MongoControlFamilyInstance {\n return new MongoFamilyInstance();\n}\n","import type {\n ControlFamilyDescriptor,\n ControlStack,\n} from '@prisma-next/framework-components/control';\nimport { mongoEmission } from '@prisma-next/mongo-emitter';\nimport { createMongoFamilyInstance, type MongoControlFamilyInstance } from './control-instance';\n\nclass MongoFamilyDescriptor\n implements ControlFamilyDescriptor<'mongo', MongoControlFamilyInstance>\n{\n readonly kind = 'family' as const;\n readonly id = 'mongo';\n readonly familyId = 'mongo' as const;\n readonly version = '0.0.1';\n readonly emission = mongoEmission;\n\n create<TTargetId extends string>(\n stack: ControlStack<'mongo', TTargetId>,\n ): MongoControlFamilyInstance {\n return createMongoFamilyInstance(stack);\n }\n}\n\nexport const mongoFamilyDescriptor: ControlFamilyDescriptor<'mongo', MongoControlFamilyInstance> =\n new MongoFamilyDescriptor();\n","/**\n * Mongo's in-process implementation of the `emit` capability on\n * `TargetMigrationsCapability`. Invoked by the framework's class-flow emit\n * dispatcher in `@prisma-next/cli/lib/migration-emit` — see that module's\n * preamble for the cross-cutting story (when the CLI dispatches here, who\n * attests `migration.json`, why both flows produce byte-identical artifacts,\n * and the relationship to the self-emitting `Migration.run` shebang path).\n *\n * Mongo-specific responsibilities of this helper:\n *\n * - Accept two authoring shapes for `migration.ts`'s default export, both\n * adhering to the `MigrationPlan` interface:\n *\n * 1. Class subclass (canonical, scaffolded form):\n * class M extends Migration {\n * override get operations() { return [...]; }\n * override describe() { return { from, to }; }\n * }\n * export default M;\n * Migration.run(import.meta.url, M);\n *\n * 2. Factory function returning a MigrationPlan-shaped object:\n * export default () => ({\n * targetId: 'mongo',\n * destination: { storageHash: '...' },\n * operations: [createCollection(\"users\")],\n * });\n *\n * Only the class form is scaffolded; the factory form is supported for\n * authors who prefer it.\n * - Dynamic-import the file so structured errors thrown during evaluation\n * (notably `placeholder(...)`) surface to the CLI as real exceptions.\n * - Dispatch on the default export's shape and validate the factory return\n * is `MigrationPlan`-shaped.\n * - Persist `ops.json` via the framework I/O helper and return the\n * operations to the caller (which performs attestation).\n */\n\nimport { stat } from 'node:fs/promises';\nimport { pathToFileURL } from 'node:url';\nimport {\n errorMigrationFileMissing,\n errorMigrationInvalidDefaultExport,\n errorMigrationPlanNotArray,\n} from '@prisma-next/errors/migration';\nimport type {\n MigrationPlan,\n MigrationPlanOperation,\n TargetMigrationsCapability,\n} from '@prisma-next/framework-components/control';\nimport { writeMigrationOps } from '@prisma-next/migration-tools/io';\nimport { Migration } from '@prisma-next/migration-tools/migration';\nimport { join } from 'pathe';\n\nconst MIGRATION_TS_FILE = 'migration.ts';\n\ntype EmitOptions = Parameters<NonNullable<TargetMigrationsCapability['emit']>>[0];\n\n/**\n * Implementation of `TargetMigrationsCapability.emit` for Mongo.\n *\n * Loads `<dir>/migration.ts` and dispatches on the default export's shape:\n * if it is a `Migration` subclass, instantiates it; otherwise invokes it as a\n * factory function (sync or async) and validates the returned value is\n * `MigrationPlan`-shaped. In both cases reads `.operations` to produce the\n * operations list, writes `ops.json`, and returns the operations for the\n * framework helper to render. Attestation of `migration.json` is the\n * caller's responsibility: the framework's `emitMigration` helper calls\n * `attestMigration` after this function returns. This capability MUST NOT\n * call `attestMigration` itself, to avoid double-attestation when the helper\n * drives emit.\n */\nexport async function mongoEmit(options: EmitOptions): Promise<readonly MigrationPlanOperation[]> {\n const filePath = join(options.dir, MIGRATION_TS_FILE);\n\n try {\n await stat(filePath);\n } catch {\n throw errorMigrationFileMissing(options.dir);\n }\n\n const fileUrl = pathToFileURL(filePath).href;\n const mod = (await import(fileUrl)) as { default?: unknown };\n\n const MigrationExport = mod.default;\n if (typeof MigrationExport !== 'function') {\n throw errorMigrationInvalidDefaultExport(\n options.dir,\n `default export of type ${typeof MigrationExport}`,\n );\n }\n\n let plan: MigrationPlan;\n if (MigrationExport.prototype instanceof Migration) {\n plan = new (MigrationExport as new () => Migration)();\n } else {\n let factoryResult: unknown;\n try {\n factoryResult = await (MigrationExport as () => unknown | Promise<unknown>)();\n } catch (error) {\n if (error instanceof TypeError && /cannot be invoked without 'new'/i.test(error.message)) {\n throw errorMigrationInvalidDefaultExport(\n options.dir,\n 'a default export that does not extend Migration (from @prisma-next/migration-tools/migration)',\n );\n }\n throw error;\n }\n if (\n typeof factoryResult !== 'object' ||\n factoryResult === null ||\n !('operations' in factoryResult)\n ) {\n throw errorMigrationInvalidDefaultExport(\n options.dir,\n `factory must return a MigrationPlan-shaped object; got ${describeValue(factoryResult)}`,\n );\n }\n plan = factoryResult as MigrationPlan;\n }\n\n const operations: unknown = plan.operations;\n if (!Array.isArray(operations)) {\n throw errorMigrationPlanNotArray(options.dir, describeValue(operations));\n }\n\n await writeMigrationOps(options.dir, operations);\n\n return operations;\n}\n\nfunction describeValue(value: unknown): string {\n if (value === null) return 'null';\n return `a value of type ${typeof value}`;\n}\n","import { createMongoRunnerDeps } from '@prisma-next/adapter-mongo/control';\nimport type { Contract } from '@prisma-next/contract/types';\nimport type { MigratableTargetDescriptor } from '@prisma-next/framework-components/control';\nimport type { MongoContract } from '@prisma-next/mongo-contract';\nimport {\n contractToMongoSchemaIR,\n MongoMigrationPlanner,\n MongoMigrationRunner,\n type MongoRunnerDependencies,\n} from '@prisma-next/target-mongo/control';\nimport mongoTargetDescriptorMeta from '@prisma-next/target-mongo/pack';\nimport type { MongoControlFamilyInstance } from './control-instance';\nimport { mongoEmit } from './mongo-emit';\n\n/**\n * The Mongo target uses the **class-flow** migration authoring strategy.\n *\n * `migration.ts` default-exports a `Migration` subclass whose `operations`\n * getter returns the ordered list of operations and whose `describe()`\n * returns the manifest identity metadata. `MongoMigrationPlanner.plan()`\n * returns a `MigrationPlanWithAuthoringSurface` that knows how to render\n * itself back to such a file; `MongoMigrationPlanner.emptyMigration()`\n * returns the same shape for `migration new`. `migration emit` dispatches\n * to `mongoEmit`, which dynamic-imports the class and writes `ops.json`.\n *\n * The descriptor-flow hooks (`planWithDescriptors`, `resolveDescriptors`,\n * `renderDescriptorTypeScript`) are intentionally omitted — the CLI's\n * `migrationStrategy` selector routes Mongo down the class-flow path by\n * observing their absence.\n */\nexport const mongoTargetDescriptor: MigratableTargetDescriptor<\n 'mongo',\n 'mongo',\n MongoControlFamilyInstance\n> = {\n ...mongoTargetDescriptorMeta,\n migrations: {\n createPlanner(_family: MongoControlFamilyInstance) {\n return new MongoMigrationPlanner();\n },\n createRunner(_family: MongoControlFamilyInstance) {\n // Deps are bound to the first driver passed to execute() and cached for\n // subsequent calls. Callers must not change the driver between calls.\n let cachedDeps: MongoRunnerDependencies | undefined;\n return {\n async execute(options) {\n cachedDeps ??= createMongoRunnerDeps(options.driver);\n const { driver: _, ...runnerOptions } = options;\n const runner = new MongoMigrationRunner(cachedDeps);\n return runner.execute(runnerOptions);\n },\n };\n },\n contractToSchema(contract: Contract | null) {\n return contractToMongoSchemaIR(contract as MongoContract | null);\n },\n emit: mongoEmit,\n },\n create() {\n return { familyId: 'mongo' as const, targetId: 'mongo' as const };\n },\n};\n"],"mappings":"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"}
@@ -2,7 +2,18 @@ import { Migration } from "@prisma-next/migration-tools/migration";
2
2
  import { MongoMigrationPlanOperation } from "@prisma-next/mongo-query-ast/control";
3
3
 
4
4
  //#region src/core/mongo-migration.d.ts
5
- declare abstract class MongoMigration extends Migration<MongoMigrationPlanOperation> {}
5
+
6
+ /**
7
+ * Family-owned base class for class-flow Mongo migrations.
8
+ *
9
+ * Provides the fixed `targetId = 'mongo'` so that user-authored migrations
10
+ * and renderer-generated scaffolds (e.g. the output of
11
+ * `renderCallsToTypeScript`) inherit it directly and don't have to re-declare
12
+ * the abstract `targetId` member from `Migration`.
13
+ */
14
+ declare abstract class MongoMigration extends Migration<MongoMigrationPlanOperation> {
15
+ readonly targetId: "mongo";
16
+ }
6
17
  //#endregion
7
18
  export { MongoMigration as Migration };
8
19
  //# sourceMappingURL=migration.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"migration.d.mts","names":[],"sources":["../src/core/mongo-migration.ts"],"sourcesContent":[],"mappings":";;;;uBAGsB,cAAA,SAAuB,UAAU"}
1
+ {"version":3,"file":"migration.d.mts","names":[],"sources":["../src/core/mongo-migration.ts"],"sourcesContent":[],"mappings":";;;;;;;AAWA;;;;;;uBAAsB,cAAA,SAAuB,UAAU"}
@@ -1,7 +1,17 @@
1
1
  import { Migration } from "@prisma-next/migration-tools/migration";
2
2
 
3
3
  //#region src/core/mongo-migration.ts
4
- var MongoMigration = class extends Migration {};
4
+ /**
5
+ * Family-owned base class for class-flow Mongo migrations.
6
+ *
7
+ * Provides the fixed `targetId = 'mongo'` so that user-authored migrations
8
+ * and renderer-generated scaffolds (e.g. the output of
9
+ * `renderCallsToTypeScript`) inherit it directly and don't have to re-declare
10
+ * the abstract `targetId` member from `Migration`.
11
+ */
12
+ var MongoMigration = class extends Migration {
13
+ targetId = "mongo";
14
+ };
5
15
 
6
16
  //#endregion
7
17
  export { MongoMigration as Migration };
@@ -1 +1 @@
1
- {"version":3,"file":"migration.mjs","names":[],"sources":["../src/core/mongo-migration.ts"],"sourcesContent":["import { Migration } from '@prisma-next/migration-tools/migration';\nimport type { MongoMigrationPlanOperation } from '@prisma-next/mongo-query-ast/control';\n\nexport abstract class MongoMigration extends Migration<MongoMigrationPlanOperation> {}\n"],"mappings":";;;AAGA,IAAsB,iBAAtB,cAA6C,UAAuC"}
1
+ {"version":3,"file":"migration.mjs","names":[],"sources":["../src/core/mongo-migration.ts"],"sourcesContent":["import { Migration } from '@prisma-next/migration-tools/migration';\nimport type { MongoMigrationPlanOperation } from '@prisma-next/mongo-query-ast/control';\n\n/**\n * Family-owned base class for class-flow Mongo migrations.\n *\n * Provides the fixed `targetId = 'mongo'` so that user-authored migrations\n * and renderer-generated scaffolds (e.g. the output of\n * `renderCallsToTypeScript`) inherit it directly and don't have to re-declare\n * the abstract `targetId` member from `Migration`.\n */\nexport abstract class MongoMigration extends Migration<MongoMigrationPlanOperation> {\n readonly targetId = 'mongo' as const;\n}\n"],"mappings":";;;;;;;;;;;AAWA,IAAsB,iBAAtB,cAA6C,UAAuC;CAClF,AAAS,WAAW"}
package/package.json CHANGED
@@ -1,30 +1,30 @@
1
1
  {
2
2
  "name": "@prisma-next/family-mongo",
3
- "version": "0.4.0-dev.6",
3
+ "version": "0.4.0-dev.7",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "Mongo family descriptor for Prisma Next",
7
7
  "dependencies": {
8
8
  "mongodb": "^6.16.0",
9
9
  "pathe": "^2.0.3",
10
- "@prisma-next/adapter-mongo": "0.4.0-dev.6",
11
- "@prisma-next/errors": "0.4.0-dev.6",
12
- "@prisma-next/emitter": "0.4.0-dev.6",
13
- "@prisma-next/framework-components": "0.4.0-dev.6",
14
- "@prisma-next/migration-tools": "0.4.0-dev.6",
15
- "@prisma-next/mongo-contract": "0.4.0-dev.6",
16
- "@prisma-next/mongo-emitter": "0.4.0-dev.6",
17
- "@prisma-next/mongo-query-ast": "0.4.0-dev.6",
18
- "@prisma-next/mongo-schema-ir": "0.4.0-dev.6",
19
- "@prisma-next/target-mongo": "0.4.0-dev.6",
20
- "@prisma-next/contract": "0.4.0-dev.6",
21
- "@prisma-next/utils": "0.4.0-dev.6"
10
+ "@prisma-next/contract": "0.4.0-dev.7",
11
+ "@prisma-next/adapter-mongo": "0.4.0-dev.7",
12
+ "@prisma-next/errors": "0.4.0-dev.7",
13
+ "@prisma-next/framework-components": "0.4.0-dev.7",
14
+ "@prisma-next/emitter": "0.4.0-dev.7",
15
+ "@prisma-next/migration-tools": "0.4.0-dev.7",
16
+ "@prisma-next/mongo-contract": "0.4.0-dev.7",
17
+ "@prisma-next/mongo-emitter": "0.4.0-dev.7",
18
+ "@prisma-next/mongo-query-ast": "0.4.0-dev.7",
19
+ "@prisma-next/mongo-schema-ir": "0.4.0-dev.7",
20
+ "@prisma-next/target-mongo": "0.4.0-dev.7",
21
+ "@prisma-next/utils": "0.4.0-dev.7"
22
22
  },
23
23
  "devDependencies": {
24
24
  "tsdown": "0.18.4",
25
25
  "typescript": "5.9.3",
26
26
  "vitest": "4.0.17",
27
- "@prisma-next/mongo-contract-ts": "0.4.0-dev.6",
27
+ "@prisma-next/mongo-contract-ts": "0.4.0-dev.7",
28
28
  "@prisma-next/tsconfig": "0.0.0",
29
29
  "@prisma-next/tsdown": "0.0.0"
30
30
  },
@@ -1,28 +1,39 @@
1
1
  /**
2
2
  * Mongo's in-process implementation of the `emit` capability on
3
- * `TargetMigrationsCapability`.
3
+ * `TargetMigrationsCapability`. Invoked by the framework's class-flow emit
4
+ * dispatcher in `@prisma-next/cli/lib/migration-emit` — see that module's
5
+ * preamble for the cross-cutting story (when the CLI dispatches here, who
6
+ * attests `migration.json`, why both flows produce byte-identical artifacts,
7
+ * and the relationship to the self-emitting `Migration.run` shebang path).
4
8
  *
5
- * The CLI's `migration emit` (and `migration plan`'s inline emit) dispatches
6
- * here for any target that does not implement `resolveDescriptors`. Two
7
- * authoring shapes are accepted:
9
+ * Mongo-specific responsibilities of this helper:
8
10
  *
9
- * 1. Class subclass (canonical):
10
- * class M extends Migration { override plan() { return [...] } }
11
- * export default M;
12
- * Migration.run(import.meta.url, M);
11
+ * - Accept two authoring shapes for `migration.ts`'s default export, both
12
+ * adhering to the `MigrationPlan` interface:
13
13
  *
14
- * 2. Factory function returning a Migration-satisfying object:
15
- * export default () => ({ plan() { return [createCollection("users")] } });
14
+ * 1. Class subclass (canonical, scaffolded form):
15
+ * class M extends Migration {
16
+ * override get operations() { return [...]; }
17
+ * override describe() { return { from, to }; }
18
+ * }
19
+ * export default M;
20
+ * Migration.run(import.meta.url, M);
16
21
  *
17
- * We dynamic-import the file (so that any structured errors thrown by
18
- * `placeholder(...)` propagate as real exceptions to the CLI), dispatch on
19
- * the export's shape (class subclass vs. callable function), and persist
20
- * `ops.json` via the framework I/O helper. `Migration.run` already guards
21
- * itself against firing when the file is imported rather than run as the
22
- * main module, so this is safe to call from inside the CLI process.
22
+ * 2. Factory function returning a MigrationPlan-shaped object:
23
+ * export default () => ({
24
+ * targetId: 'mongo',
25
+ * destination: { storageHash: '...' },
26
+ * operations: [createCollection("users")],
27
+ * });
23
28
  *
24
- * Attestation (computing and writing `migrationId` to `manifest.json`) is
25
- * owned by the framework's `emitMigration` helper, not this capability.
29
+ * Only the class form is scaffolded; the factory form is supported for
30
+ * authors who prefer it.
31
+ * - Dynamic-import the file so structured errors thrown during evaluation
32
+ * (notably `placeholder(...)`) surface to the CLI as real exceptions.
33
+ * - Dispatch on the default export's shape and validate the factory return
34
+ * is `MigrationPlan`-shaped.
35
+ * - Persist `ops.json` via the framework I/O helper and return the
36
+ * operations to the caller (which performs attestation).
26
37
  */
27
38
 
28
39
  import { stat } from 'node:fs/promises';
@@ -33,6 +44,7 @@ import {
33
44
  errorMigrationPlanNotArray,
34
45
  } from '@prisma-next/errors/migration';
35
46
  import type {
47
+ MigrationPlan,
36
48
  MigrationPlanOperation,
37
49
  TargetMigrationsCapability,
38
50
  } from '@prisma-next/framework-components/control';
@@ -48,13 +60,15 @@ type EmitOptions = Parameters<NonNullable<TargetMigrationsCapability['emit']>>[0
48
60
  * Implementation of `TargetMigrationsCapability.emit` for Mongo.
49
61
  *
50
62
  * Loads `<dir>/migration.ts` and dispatches on the default export's shape:
51
- * if it is a `Migration` subclass, instantiates it and calls `plan()`;
52
- * otherwise invokes it as a factory function, validates the returned value
53
- * has a `plan()` method, and calls it.
54
- * Writes `ops.json` and returns the operations for the framework helper to
55
- * render. Attestation (`migrationId` in `manifest.json`) is the framework
56
- * helper's responsibility; this capability MUST NOT call `attestMigration`
57
- * itself.
63
+ * if it is a `Migration` subclass, instantiates it; otherwise invokes it as a
64
+ * factory function (sync or async) and validates the returned value is
65
+ * `MigrationPlan`-shaped. In both cases reads `.operations` to produce the
66
+ * operations list, writes `ops.json`, and returns the operations for the
67
+ * framework helper to render. Attestation of `migration.json` is the
68
+ * caller's responsibility: the framework's `emitMigration` helper calls
69
+ * `attestMigration` after this function returns. This capability MUST NOT
70
+ * call `attestMigration` itself, to avoid double-attestation when the helper
71
+ * drives emit.
58
72
  */
59
73
  export async function mongoEmit(options: EmitOptions): Promise<readonly MigrationPlanOperation[]> {
60
74
  const filePath = join(options.dir, MIGRATION_TS_FILE);
@@ -76,9 +90,9 @@ export async function mongoEmit(options: EmitOptions): Promise<readonly Migratio
76
90
  );
77
91
  }
78
92
 
79
- let migration: { plan(): unknown };
93
+ let plan: MigrationPlan;
80
94
  if (MigrationExport.prototype instanceof Migration) {
81
- migration = new (MigrationExport as new () => Migration)();
95
+ plan = new (MigrationExport as new () => Migration)();
82
96
  } else {
83
97
  let factoryResult: unknown;
84
98
  try {
@@ -95,18 +109,17 @@ export async function mongoEmit(options: EmitOptions): Promise<readonly Migratio
95
109
  if (
96
110
  typeof factoryResult !== 'object' ||
97
111
  factoryResult === null ||
98
- typeof (factoryResult as { plan?: unknown }).plan !== 'function'
112
+ !('operations' in factoryResult)
99
113
  ) {
100
114
  throw errorMigrationInvalidDefaultExport(
101
115
  options.dir,
102
- `factory must return an object with a plan() method; got ${describeValue(factoryResult)}`,
116
+ `factory must return a MigrationPlan-shaped object; got ${describeValue(factoryResult)}`,
103
117
  );
104
118
  }
105
- migration = factoryResult as { plan(): unknown };
119
+ plan = factoryResult as MigrationPlan;
106
120
  }
107
121
 
108
- const operations: unknown = migration.plan();
109
-
122
+ const operations: unknown = plan.operations;
110
123
  if (!Array.isArray(operations)) {
111
124
  throw errorMigrationPlanNotArray(options.dir, describeValue(operations));
112
125
  }
@@ -1,4 +1,14 @@
1
1
  import { Migration } from '@prisma-next/migration-tools/migration';
2
2
  import type { MongoMigrationPlanOperation } from '@prisma-next/mongo-query-ast/control';
3
3
 
4
- export abstract class MongoMigration extends Migration<MongoMigrationPlanOperation> {}
4
+ /**
5
+ * Family-owned base class for class-flow Mongo migrations.
6
+ *
7
+ * Provides the fixed `targetId = 'mongo'` so that user-authored migrations
8
+ * and renderer-generated scaffolds (e.g. the output of
9
+ * `renderCallsToTypeScript`) inherit it directly and don't have to re-declare
10
+ * the abstract `targetId` member from `Migration`.
11
+ */
12
+ export abstract class MongoMigration extends Migration<MongoMigrationPlanOperation> {
13
+ readonly targetId = 'mongo' as const;
14
+ }
@@ -12,6 +12,22 @@ import mongoTargetDescriptorMeta from '@prisma-next/target-mongo/pack';
12
12
  import type { MongoControlFamilyInstance } from './control-instance';
13
13
  import { mongoEmit } from './mongo-emit';
14
14
 
15
+ /**
16
+ * The Mongo target uses the **class-flow** migration authoring strategy.
17
+ *
18
+ * `migration.ts` default-exports a `Migration` subclass whose `operations`
19
+ * getter returns the ordered list of operations and whose `describe()`
20
+ * returns the manifest identity metadata. `MongoMigrationPlanner.plan()`
21
+ * returns a `MigrationPlanWithAuthoringSurface` that knows how to render
22
+ * itself back to such a file; `MongoMigrationPlanner.emptyMigration()`
23
+ * returns the same shape for `migration new`. `migration emit` dispatches
24
+ * to `mongoEmit`, which dynamic-imports the class and writes `ops.json`.
25
+ *
26
+ * The descriptor-flow hooks (`planWithDescriptors`, `resolveDescriptors`,
27
+ * `renderDescriptorTypeScript`) are intentionally omitted — the CLI's
28
+ * `migrationStrategy` selector routes Mongo down the class-flow path by
29
+ * observing their absence.
30
+ */
15
31
  export const mongoTargetDescriptor: MigratableTargetDescriptor<
16
32
  'mongo',
17
33
  'mongo',