@prisma-next/family-mongo 0.12.0-dev.1 → 0.12.0-dev.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/control-adapter.d.mts +9 -1
- package/dist/control-adapter.d.mts.map +1 -1
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +4 -6
- package/dist/control.mjs.map +1 -1
- package/package.json +15 -15
- package/src/core/control-adapter.ts +18 -2
- package/src/core/control-instance.ts +10 -21
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { MongoSchemaIR } from "@prisma-next/mongo-schema-ir";
|
|
2
2
|
import { ControlAdapterDescriptor, ControlAdapterInstance, ControlDriverInstance } from "@prisma-next/framework-components/control";
|
|
3
|
-
import { ContractMarkerRecord } from "@prisma-next/contract/types";
|
|
3
|
+
import { ContractMarkerRecord, LedgerEntryRecord } from "@prisma-next/contract/types";
|
|
4
4
|
|
|
5
5
|
//#region src/core/control-adapter.d.ts
|
|
6
6
|
/**
|
|
@@ -58,7 +58,15 @@ interface MongoControlAdapter<TTarget extends string = string> extends ControlAd
|
|
|
58
58
|
readonly edgeId: string;
|
|
59
59
|
readonly from: string;
|
|
60
60
|
readonly to: string;
|
|
61
|
+
readonly migrationName: string;
|
|
62
|
+
readonly migrationHash: string;
|
|
63
|
+
readonly operations: readonly unknown[];
|
|
61
64
|
}): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Reads the per-migration ledger journal for `space` in apply order.
|
|
67
|
+
* Returns an empty array when no ledger entries exist for that space.
|
|
68
|
+
*/
|
|
69
|
+
readLedger(driver: ControlDriverInstance<'mongo', TTarget>, space: string): Promise<readonly LedgerEntryRecord[]>;
|
|
62
70
|
/**
|
|
63
71
|
* Introspects the live database and returns a `MongoSchemaIR`.
|
|
64
72
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control-adapter.d.mts","names":[],"sources":["../src/core/control-adapter.ts"],"mappings":";;;;;;;AAqBA;;;;;;;;;;;UAAiB,mBAAA,0CACP,sBAAA,UAAgC,OAAA;EAoBrC;;;;;;EAbH,UAAA,CACE,MAAA,EAAQ,qBAAA,UAA+B,OAAA,GACvC,KAAA,WACC,OAAA,CAAQ,oBAAA;EA+C8B;;;;;;EAvCzC,cAAA,CACE,MAAA,EAAQ,qBAAA,UAA+B,OAAA,IACtC,OAAA,CAAQ,WAAA,SAAoB,oBAAA;
|
|
1
|
+
{"version":3,"file":"control-adapter.d.mts","names":[],"sources":["../src/core/control-adapter.ts"],"mappings":";;;;;;;AAqBA;;;;;;;;;;;UAAiB,mBAAA,0CACP,sBAAA,UAAgC,OAAA;EAoBrC;;;;;;EAbH,UAAA,CACE,MAAA,EAAQ,qBAAA,UAA+B,OAAA,GACvC,KAAA,WACC,OAAA,CAAQ,oBAAA;EA+C8B;;;;;;EAvCzC,cAAA,CACE,MAAA,EAAQ,qBAAA,UAA+B,OAAA,IACtC,OAAA,CAAQ,WAAA,SAAoB,oBAAA;EA6DyB;;;EAxDxD,UAAA,CACE,MAAA,EAAQ,qBAAA,UAA+B,OAAA,GACvC,KAAA,UACA,WAAA;IAAA,SACW,WAAA;IAAA,SACA,WAAA;IAAA,SACA,UAAA;EAAA,IAEV,OAAA;EAjCK;;;;;EAwCR,YAAA,CACE,MAAA,EAAQ,qBAAA,UAA+B,OAAA,GACvC,KAAA,UACA,YAAA,UACA,WAAA;IAAA,SACW,WAAA;IAAA,SACA,WAAA;IAAA,SACA,UAAA;EAAA,IAEV,OAAA;EA9BO;;;;;EAqCV,gBAAA,CACE,MAAA,EAAQ,qBAAA,UAA+B,OAAA,GACvC,KAAA,UACA,KAAA;IAAA,SACW,MAAA;IAAA,SACA,IAAA;IAAA,SACA,EAAA;IAAA,SACA,aAAA;IAAA,SACA,aAAA;IAAA,SACA,UAAA;EAAA,IAEV,OAAA;EApCU;;;;EA0Cb,UAAA,CACE,MAAA,EAAQ,qBAAA,UAA+B,OAAA,GACvC,KAAA,WACC,OAAA,UAAiB,iBAAA;EAnCqB;;;EAwCzC,gBAAA,CAAiB,MAAA,EAAQ,qBAAA,UAA+B,OAAA,IAAW,OAAA,CAAQ,aAAA;AAAA;;;;;;UAQ5D,6BAAA,0CACP,wBAAA,UAAkC,OAAA,EAAS,mBAAA,CAAoB,OAAA"}
|
package/dist/control.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control.d.mts","names":[],"sources":["../src/core/contract-to-schema.ts","../src/core/control-instance.ts","../src/core/control-descriptor.ts","../src/core/control-target-descriptor.ts","../src/core/control-types.ts","../src/core/operation-preview.ts","../src/core/schema-diff.ts","../src/core/schema-verify/canonicalize-introspection.ts"],"mappings":";;;;;;iBAyEgB,uBAAA,CAAwB,QAAA,EAAU,aAAA,UAAuB,aAAa;;;
|
|
1
|
+
{"version":3,"file":"control.d.mts","names":[],"sources":["../src/core/contract-to-schema.ts","../src/core/control-instance.ts","../src/core/control-descriptor.ts","../src/core/control-target-descriptor.ts","../src/core/control-types.ts","../src/core/operation-preview.ts","../src/core/schema-diff.ts","../src/core/schema-verify/canonicalize-introspection.ts"],"mappings":";;;;;;iBAyEgB,uBAAA,CAAwB,QAAA,EAAU,aAAA,UAAuB,aAAa;;;UCpCrE,0BAAA,SACP,qBAAA,UAA+B,aAAA,GACrC,iBAAA,CAAkB,aAAA,GAClB,uBAAA;;;ADiCJ;;;;;;;;ECtBE,mBAAA,CAAoB,YAAA,YAAwB,QAAA;AAAA;AAAA,iBAsE9B,yBAAA,CAA0B,YAAA,EAAc,YAAA,GAAe,0BAA0B;;;cClGpF,qBAAA,EAAuB,uBAAuB,UAAU,0BAAA;;;;;AFkDrE;;;;;;;;AAAsF;;UGpDrE,4BAAA,mBAA+C,aAAA,GAAgB,aAAA,UACtE,0BAAA,mBAA6C,0BAAA;EAAA,SAC5C,kBAAA,EAAoB,kBAAA,CAAmB,SAAA;EAAA,SACvC,cAAA,EAAgB,cAAA,CAAe,SAAA,EAAW,aAAA;AAAA;;;;;;;AHiDrD;;;;;;;;AAAsF;;;UIpDrE,+BAAA,SACP,0BAAA;EAAA,SACC,aAAA,GAAgB,aAAA,CAAc,aAAA,CAAc,iBAAA;AAAA;;;iBC6EvC,qBAAA,CAAsB,UAA6C,WAAxB,sBAAsB;;;;;AL3BjF;iBKgDgB,wBAAA,CACd,UAAA,WAAqB,sBAAA,KACpB,gBAAgB;;;iBC/GH,gBAAA,CACd,IAAA,EAAM,aAAA,EACN,QAAA,EAAU,aAAA,EACV,MAAA;EAEA,IAAA,EAAM,sBAAA;EACN,MAAA,EAAQ,WAAA;EACR,MAAA;IAAU,IAAA;IAAc,IAAA;IAAc,IAAA;IAAc,UAAA;EAAA;AAAA;;;UCWrC,oBAAA;EAAA,SACN,IAAA,EAAM,aAAA;EAAA,SACN,QAAA,EAAU,aAAa;AAAA;AAAA,iBAGlB,kCAAA,CACd,IAAA,EAAM,aAAA,EACN,QAAA,EAAU,aAAA,GACT,oBAAA"}
|
package/dist/control.mjs
CHANGED
|
@@ -199,9 +199,6 @@ function deserializeMongoContract(contractJson) {
|
|
|
199
199
|
function asValidatedMongoContract(contract) {
|
|
200
200
|
return contract;
|
|
201
201
|
}
|
|
202
|
-
function isMongoControlAdapter(value) {
|
|
203
|
-
return typeof value === "object" && value !== null && "readMarker" in value && typeof value.readMarker === "function" && "readAllMarkers" in value && typeof value.readAllMarkers === "function" && "introspectSchema" in value && typeof value.introspectSchema === "function";
|
|
204
|
-
}
|
|
205
202
|
function buildVerifyResult(opts) {
|
|
206
203
|
return {
|
|
207
204
|
ok: opts.ok,
|
|
@@ -242,9 +239,7 @@ function createMongoFamilyInstance(controlStack) {
|
|
|
242
239
|
const adapter = controlStack.adapter;
|
|
243
240
|
const getControlAdapter = () => {
|
|
244
241
|
if (!adapter) throw new Error("Mongo family requires an adapter descriptor in ControlStack");
|
|
245
|
-
|
|
246
|
-
if (!isMongoControlAdapter(controlAdapter)) throw new Error("Adapter does not implement MongoControlAdapter (missing readMarker, readAllMarkers, or introspectSchema)");
|
|
247
|
-
return controlAdapter;
|
|
242
|
+
return adapter.create(controlStack);
|
|
248
243
|
};
|
|
249
244
|
const asMongoDriver = (driver) => driver;
|
|
250
245
|
return {
|
|
@@ -380,6 +375,9 @@ function createMongoFamilyInstance(controlStack) {
|
|
|
380
375
|
async readAllMarkers(options) {
|
|
381
376
|
return getControlAdapter().readAllMarkers(asMongoDriver(options.driver));
|
|
382
377
|
},
|
|
378
|
+
async readLedger(options) {
|
|
379
|
+
return getControlAdapter().readLedger(asMongoDriver(options.driver), options.space);
|
|
380
|
+
},
|
|
383
381
|
async introspect(options) {
|
|
384
382
|
return getControlAdapter().introspectSchema(asMongoDriver(options.driver));
|
|
385
383
|
},
|
package/dist/control.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control.mjs","names":[],"sources":["../src/core/operation-preview.ts","../src/core/schema-to-view.ts","../src/core/control-instance.ts","../src/core/control-descriptor.ts"],"sourcesContent":["import type {\n MigrationPlanOperation,\n OperationPreview,\n} from '@prisma-next/framework-components/control';\nimport type {\n CollModCommand,\n CreateCollectionCommand,\n CreateIndexCommand,\n DropCollectionCommand,\n DropIndexCommand,\n MongoDdlCommandVisitor,\n MongoIndexKey,\n} from '@prisma-next/mongo-query-ast/control';\n\nfunction formatKeySpec(keys: ReadonlyArray<MongoIndexKey>): string {\n const entries = keys.map((k) => `${JSON.stringify(k.field)}: ${JSON.stringify(k.direction)}`);\n return `{ ${entries.join(', ')} }`;\n}\n\nfunction formatOptions(cmd: CreateIndexCommand): string | undefined {\n const parts: string[] = [];\n if (cmd.unique) parts.push('unique: true');\n if (cmd.sparse) parts.push('sparse: true');\n if (cmd.expireAfterSeconds !== undefined)\n parts.push(`expireAfterSeconds: ${cmd.expireAfterSeconds}`);\n if (cmd.name) parts.push(`name: ${JSON.stringify(cmd.name)}`);\n if (cmd.collation) parts.push(`collation: ${JSON.stringify(cmd.collation)}`);\n if (cmd.weights) parts.push(`weights: ${JSON.stringify(cmd.weights)}`);\n if (cmd.default_language) parts.push(`default_language: ${JSON.stringify(cmd.default_language)}`);\n if (cmd.language_override)\n parts.push(`language_override: ${JSON.stringify(cmd.language_override)}`);\n if (cmd.wildcardProjection)\n parts.push(`wildcardProjection: ${JSON.stringify(cmd.wildcardProjection)}`);\n if (cmd.partialFilterExpression)\n parts.push(`partialFilterExpression: ${JSON.stringify(cmd.partialFilterExpression)}`);\n if (parts.length === 0) return undefined;\n return `{ ${parts.join(', ')} }`;\n}\n\nfunction formatCreateCollectionOptions(cmd: CreateCollectionCommand): string | undefined {\n const parts: string[] = [];\n if (cmd.capped) parts.push('capped: true');\n if (cmd.size !== undefined) parts.push(`size: ${cmd.size}`);\n if (cmd.max !== undefined) parts.push(`max: ${cmd.max}`);\n if (cmd.timeseries) parts.push(`timeseries: ${JSON.stringify(cmd.timeseries)}`);\n if (cmd.collation) parts.push(`collation: ${JSON.stringify(cmd.collation)}`);\n if (cmd.clusteredIndex) parts.push(`clusteredIndex: ${JSON.stringify(cmd.clusteredIndex)}`);\n if (cmd.validator) parts.push(`validator: ${JSON.stringify(cmd.validator)}`);\n if (cmd.validationLevel) parts.push(`validationLevel: ${JSON.stringify(cmd.validationLevel)}`);\n if (cmd.validationAction) parts.push(`validationAction: ${JSON.stringify(cmd.validationAction)}`);\n if (cmd.changeStreamPreAndPostImages)\n parts.push(`changeStreamPreAndPostImages: ${JSON.stringify(cmd.changeStreamPreAndPostImages)}`);\n if (parts.length === 0) return undefined;\n return `{ ${parts.join(', ')} }`;\n}\n\nclass MongoDdlCommandFormatter implements MongoDdlCommandVisitor<string> {\n createIndex(cmd: CreateIndexCommand): string {\n const keySpec = formatKeySpec(cmd.keys);\n const opts = formatOptions(cmd);\n return opts\n ? `db.${cmd.collection}.createIndex(${keySpec}, ${opts})`\n : `db.${cmd.collection}.createIndex(${keySpec})`;\n }\n\n dropIndex(cmd: DropIndexCommand): string {\n return `db.${cmd.collection}.dropIndex(${JSON.stringify(cmd.name)})`;\n }\n\n createCollection(cmd: CreateCollectionCommand): string {\n const opts = formatCreateCollectionOptions(cmd);\n return opts\n ? `db.createCollection(${JSON.stringify(cmd.collection)}, ${opts})`\n : `db.createCollection(${JSON.stringify(cmd.collection)})`;\n }\n\n dropCollection(cmd: DropCollectionCommand): string {\n return `db.${cmd.collection}.drop()`;\n }\n\n collMod(cmd: CollModCommand): string {\n const parts: string[] = [`collMod: ${JSON.stringify(cmd.collection)}`];\n if (cmd.validator) parts.push(`validator: ${JSON.stringify(cmd.validator)}`);\n if (cmd.validationLevel) parts.push(`validationLevel: ${JSON.stringify(cmd.validationLevel)}`);\n if (cmd.validationAction)\n parts.push(`validationAction: ${JSON.stringify(cmd.validationAction)}`);\n if (cmd.changeStreamPreAndPostImages)\n parts.push(\n `changeStreamPreAndPostImages: ${JSON.stringify(cmd.changeStreamPreAndPostImages)}`,\n );\n return `db.runCommand({ ${parts.join(', ')} })`;\n }\n}\n\nconst formatter = new MongoDdlCommandFormatter();\n\ninterface MongoExecuteStep {\n readonly command: { readonly accept: <R>(visitor: MongoDdlCommandVisitor<R>) => R };\n}\n\nexport function formatMongoOperations(operations: readonly MigrationPlanOperation[]): string[] {\n const statements: string[] = [];\n for (const operation of operations) {\n const candidate = operation as unknown as Record<string, unknown>;\n if (!('execute' in candidate) || !Array.isArray(candidate['execute'])) {\n continue;\n }\n for (const step of candidate['execute'] as MongoExecuteStep[]) {\n if (step.command && typeof step.command.accept === 'function') {\n statements.push(step.command.accept(formatter));\n }\n }\n }\n return statements;\n}\n\n/**\n * Wraps `formatMongoOperations` into the family-agnostic\n * `OperationPreview` shape. Each statement carries\n * `language: 'mongodb-shell'`. Mirrors `sqlOperationsToPreview`.\n */\nexport function mongoOperationsToPreview(\n operations: readonly MigrationPlanOperation[],\n): OperationPreview {\n return {\n statements: formatMongoOperations(operations).map((text) => ({\n text,\n language: 'mongodb-shell',\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 type { Contract, ContractMarkerRecord } from '@prisma-next/contract/types';\nimport type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';\nimport type {\n ControlDriverInstance,\n ControlFamilyInstance,\n ControlStack,\n CoreSchemaView,\n MigrationPlanOperation,\n OperationPreview,\n OperationPreviewCapable,\n SchemaViewCapable,\n SignDatabaseResult,\n VerifyDatabaseResult,\n VerifyDatabaseSchemaResult,\n} from '@prisma-next/framework-components/control';\nimport {\n APP_SPACE_ID,\n VERIFY_CODE_HASH_MISMATCH,\n VERIFY_CODE_MARKER_MISSING,\n VERIFY_CODE_TARGET_MISMATCH,\n} from '@prisma-next/framework-components/control';\nimport { assertDescriptorSelfConsistency } from '@prisma-next/migration-tools/spaces';\nimport type { MongoContract } from '@prisma-next/mongo-contract';\nimport { mongoContractCanonicalizationHooks } from '@prisma-next/mongo-contract/canonicalization-hooks';\nimport type { MongoSchemaIR } from '@prisma-next/mongo-schema-ir';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { MongoControlAdapter, MongoControlAdapterDescriptor } from './control-adapter';\nimport type { MongoControlExtensionDescriptor } from './control-types';\nimport { MongoContractSerializer } from './ir/mongo-contract-serializer';\nimport { mongoOperationsToPreview } from './operation-preview';\nimport { mongoSchemaToView } from './schema-to-view';\nimport { verifyMongoSchema } from './schema-verify/verify-mongo-schema';\n\nexport interface MongoControlFamilyInstance\n extends ControlFamilyInstance<'mongo', MongoSchemaIR>,\n SchemaViewCapable<MongoSchemaIR>,\n OperationPreviewCapable {\n /**\n * The family seam-of-record for on-disk contract reads. Structurally\n * validates the JSON envelope, then casts to the framework `Contract`\n * shape; the per-target serializer (held on the Mongo target\n * descriptor) does the class-form wrap for downstream consumers, so\n * the family only needs the validated data. The single named entry\n * point every CLI on-disk read crosses (TML-2536) — `as Contract`\n * casts in production package sources are a serializer-bypass smell\n * guarded by `pnpm lint:no-contract-cast`.\n */\n deserializeContract(contractJson: unknown): Contract;\n}\n\nfunction deserializeMongoContract(contractJson: unknown): MongoContract {\n // Structural validation only — the per-target serializer wraps the\n // result in a class-form `MongoTargetContract` for downstream\n // consumers (CLI, runner). The family-instance methods only read\n // hash/target fields off the validated shape, so the unwrapped\n // `MongoContract` is sufficient here and avoids a family→target\n // runtime dep.\n return new MongoContractSerializer().deserializeContract(contractJson);\n}\n\n/**\n * Family-method contract input. By the time control-plane methods\n * (`verify`, `verifySchema`, `sign`, …) are invoked through the CLI\n * control client (`client.ts`), the input has already been threaded\n * through `familyInstance.deserializeContract`. The value is therefore a\n * class-form `MongoTargetContract` (or a structurally-equivalent\n * envelope post-deserialization) and must NOT be re-fed through\n * structural validation (arktype rejects extra keys like `namespaces`).\n *\n * The parameter type on the framework SPI is `unknown` for variance\n * reasons (so the family can express its own contract type without\n * leaking it to the framework). This helper recovers the validated\n * shape with a single narrow cast.\n */\nfunction asValidatedMongoContract(contract: unknown): MongoContract {\n return contract as MongoContract;\n}\n\nfunction isMongoControlAdapter(value: unknown): value is MongoControlAdapter<'mongo'> {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'readMarker' in value &&\n typeof (value as { readMarker: unknown }).readMarker === 'function' &&\n 'readAllMarkers' in value &&\n typeof (value as { readAllMarkers: unknown }).readAllMarkers === 'function' &&\n 'introspectSchema' in value &&\n typeof (value as { introspectSchema: unknown }).introspectSchema === 'function'\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 // Descriptor self-consistency check.\n // Each extension that exposes a `contractSpace` must publish a\n // `headRef.hash` that matches the canonical hash recomputed from its\n // `contractJson`. A stale value would silently corrupt every downstream\n // boundary that trusts `headRef.hash` as the canonical identity (drift\n // detection, on-disk artefact emission, runner marker writes). Failing\n // fast at descriptor-load time turns \"extension author shipped an\n // inconsistent descriptor\" into an explicit, actionable error\n // (`MIGRATION.DESCRIPTOR_HEAD_HASH_MISMATCH`) rather than a confusing\n // mismatch surfacing several layers downstream. Mirrors the SQL family.\n const extensions = (controlStack.extensionPacks ??\n []) as readonly MongoControlExtensionDescriptor[];\n for (const extension of extensions) {\n if (extension.contractSpace) {\n const { contractJson, headRef } = extension.contractSpace;\n assertDescriptorSelfConsistency({\n extensionId: extension.id,\n target: contractJson.target,\n targetFamily: contractJson.targetFamily,\n storage: contractJson.storage,\n headRefHash: headRef.hash,\n ...mongoContractCanonicalizationHooks,\n });\n }\n }\n\n // Mongo dispatch surface. Every wire-level operation routes through\n // the adapter resolved from the control stack; the family carries no\n // direct imports of target/adapter/driver internals. Mirrors the SQL\n // family's `getControlAdapter()` helper.\n const adapter = controlStack.adapter as MongoControlAdapterDescriptor<'mongo'> | undefined;\n const getControlAdapter = (): MongoControlAdapter<'mongo'> => {\n if (!adapter) {\n throw new Error('Mongo family requires an adapter descriptor in ControlStack');\n }\n const controlAdapter = adapter.create(controlStack as ControlStack<'mongo', 'mongo'>);\n if (!isMongoControlAdapter(controlAdapter)) {\n throw new Error(\n 'Adapter does not implement MongoControlAdapter (missing readMarker, readAllMarkers, or introspectSchema)',\n );\n }\n return controlAdapter;\n };\n\n // The family-level driver type is `ControlDriverInstance<'mongo', string>`,\n // but the SPI methods are typed against `<'mongo', 'mongo'>`. Today's only\n // Mongo target is `'mongo'`, so the runtime values are identical; the cast\n // satisfies the structural type-system mismatch on `targetId`.\n const asMongoDriver = (\n driver: ControlDriverInstance<'mongo', string>,\n ): ControlDriverInstance<'mongo', 'mongo'> => driver as ControlDriverInstance<'mongo', 'mongo'>;\n\n return {\n familyId: 'mongo' as const,\n\n deserializeContract(contractJson: unknown): Contract {\n // The deserialized class form (MongoTargetContract, owned by\n // target-mongo) and the framework Contract are structurally\n // compatible — same fields, just a class instance on the storage\n // envelope. The cast preserves the framework signature.\n return deserializeMongoContract(contractJson) as unknown as Contract;\n },\n\n async verify(options): Promise<VerifyDatabaseResult> {\n const { driver, contract: rawContract, expectedTargetId, contractPath, configPath } = options;\n const startTime = Date.now();\n\n const contract = asValidatedMongoContract(rawContract);\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 marker = await getControlAdapter().readMarker(asMongoDriver(driver), APP_SPACE_ID);\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 verifySchema(options: {\n readonly contract: unknown;\n readonly schema: MongoSchemaIR;\n readonly strict: boolean;\n readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'mongo', string>>;\n }): VerifyDatabaseSchemaResult {\n const contract = asValidatedMongoContract(options.contract);\n return verifyMongoSchema({\n contract,\n schema: options.schema,\n strict: options.strict,\n frameworkComponents: options.frameworkComponents,\n });\n },\n\n async sign(options): Promise<SignDatabaseResult> {\n const { driver, contract: rawContract, contractPath, configPath } = options;\n const startTime = Date.now();\n\n const contract = asValidatedMongoContract(rawContract);\n\n const contractStorageHash = contract.storage.storageHash;\n const contractProfileHash = contract.profileHash;\n\n const controlAdapter = getControlAdapter();\n const mongoDriver = asMongoDriver(driver);\n\n const existingMarker = await controlAdapter.readMarker(mongoDriver, APP_SPACE_ID);\n\n let markerCreated = false;\n let markerUpdated = false;\n let previousHashes: { storageHash?: string; profileHash?: string } | undefined;\n\n if (!existingMarker) {\n await controlAdapter.initMarker(mongoDriver, APP_SPACE_ID, {\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 controlAdapter.updateMarker(\n mongoDriver,\n APP_SPACE_ID,\n existingMarker.storageHash,\n {\n storageHash: contractStorageHash,\n profileHash: contractProfileHash,\n },\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): Promise<ContractMarkerRecord | null> {\n return getControlAdapter().readMarker(asMongoDriver(options.driver), options.space);\n },\n\n async readAllMarkers(options): Promise<ReadonlyMap<string, ContractMarkerRecord>> {\n return getControlAdapter().readAllMarkers(asMongoDriver(options.driver));\n },\n\n async introspect(options): Promise<MongoSchemaIR> {\n return getControlAdapter().introspectSchema(asMongoDriver(options.driver));\n },\n\n toSchemaView(schema: MongoSchemaIR): CoreSchemaView {\n return mongoSchemaToView(schema);\n },\n\n toOperationPreview(operations: readonly MigrationPlanOperation[]): OperationPreview {\n return mongoOperationsToPreview(operations);\n },\n };\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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"control.mjs","names":[],"sources":["../src/core/operation-preview.ts","../src/core/schema-to-view.ts","../src/core/control-instance.ts","../src/core/control-descriptor.ts"],"sourcesContent":["import type {\n MigrationPlanOperation,\n OperationPreview,\n} from '@prisma-next/framework-components/control';\nimport type {\n CollModCommand,\n CreateCollectionCommand,\n CreateIndexCommand,\n DropCollectionCommand,\n DropIndexCommand,\n MongoDdlCommandVisitor,\n MongoIndexKey,\n} from '@prisma-next/mongo-query-ast/control';\n\nfunction formatKeySpec(keys: ReadonlyArray<MongoIndexKey>): string {\n const entries = keys.map((k) => `${JSON.stringify(k.field)}: ${JSON.stringify(k.direction)}`);\n return `{ ${entries.join(', ')} }`;\n}\n\nfunction formatOptions(cmd: CreateIndexCommand): string | undefined {\n const parts: string[] = [];\n if (cmd.unique) parts.push('unique: true');\n if (cmd.sparse) parts.push('sparse: true');\n if (cmd.expireAfterSeconds !== undefined)\n parts.push(`expireAfterSeconds: ${cmd.expireAfterSeconds}`);\n if (cmd.name) parts.push(`name: ${JSON.stringify(cmd.name)}`);\n if (cmd.collation) parts.push(`collation: ${JSON.stringify(cmd.collation)}`);\n if (cmd.weights) parts.push(`weights: ${JSON.stringify(cmd.weights)}`);\n if (cmd.default_language) parts.push(`default_language: ${JSON.stringify(cmd.default_language)}`);\n if (cmd.language_override)\n parts.push(`language_override: ${JSON.stringify(cmd.language_override)}`);\n if (cmd.wildcardProjection)\n parts.push(`wildcardProjection: ${JSON.stringify(cmd.wildcardProjection)}`);\n if (cmd.partialFilterExpression)\n parts.push(`partialFilterExpression: ${JSON.stringify(cmd.partialFilterExpression)}`);\n if (parts.length === 0) return undefined;\n return `{ ${parts.join(', ')} }`;\n}\n\nfunction formatCreateCollectionOptions(cmd: CreateCollectionCommand): string | undefined {\n const parts: string[] = [];\n if (cmd.capped) parts.push('capped: true');\n if (cmd.size !== undefined) parts.push(`size: ${cmd.size}`);\n if (cmd.max !== undefined) parts.push(`max: ${cmd.max}`);\n if (cmd.timeseries) parts.push(`timeseries: ${JSON.stringify(cmd.timeseries)}`);\n if (cmd.collation) parts.push(`collation: ${JSON.stringify(cmd.collation)}`);\n if (cmd.clusteredIndex) parts.push(`clusteredIndex: ${JSON.stringify(cmd.clusteredIndex)}`);\n if (cmd.validator) parts.push(`validator: ${JSON.stringify(cmd.validator)}`);\n if (cmd.validationLevel) parts.push(`validationLevel: ${JSON.stringify(cmd.validationLevel)}`);\n if (cmd.validationAction) parts.push(`validationAction: ${JSON.stringify(cmd.validationAction)}`);\n if (cmd.changeStreamPreAndPostImages)\n parts.push(`changeStreamPreAndPostImages: ${JSON.stringify(cmd.changeStreamPreAndPostImages)}`);\n if (parts.length === 0) return undefined;\n return `{ ${parts.join(', ')} }`;\n}\n\nclass MongoDdlCommandFormatter implements MongoDdlCommandVisitor<string> {\n createIndex(cmd: CreateIndexCommand): string {\n const keySpec = formatKeySpec(cmd.keys);\n const opts = formatOptions(cmd);\n return opts\n ? `db.${cmd.collection}.createIndex(${keySpec}, ${opts})`\n : `db.${cmd.collection}.createIndex(${keySpec})`;\n }\n\n dropIndex(cmd: DropIndexCommand): string {\n return `db.${cmd.collection}.dropIndex(${JSON.stringify(cmd.name)})`;\n }\n\n createCollection(cmd: CreateCollectionCommand): string {\n const opts = formatCreateCollectionOptions(cmd);\n return opts\n ? `db.createCollection(${JSON.stringify(cmd.collection)}, ${opts})`\n : `db.createCollection(${JSON.stringify(cmd.collection)})`;\n }\n\n dropCollection(cmd: DropCollectionCommand): string {\n return `db.${cmd.collection}.drop()`;\n }\n\n collMod(cmd: CollModCommand): string {\n const parts: string[] = [`collMod: ${JSON.stringify(cmd.collection)}`];\n if (cmd.validator) parts.push(`validator: ${JSON.stringify(cmd.validator)}`);\n if (cmd.validationLevel) parts.push(`validationLevel: ${JSON.stringify(cmd.validationLevel)}`);\n if (cmd.validationAction)\n parts.push(`validationAction: ${JSON.stringify(cmd.validationAction)}`);\n if (cmd.changeStreamPreAndPostImages)\n parts.push(\n `changeStreamPreAndPostImages: ${JSON.stringify(cmd.changeStreamPreAndPostImages)}`,\n );\n return `db.runCommand({ ${parts.join(', ')} })`;\n }\n}\n\nconst formatter = new MongoDdlCommandFormatter();\n\ninterface MongoExecuteStep {\n readonly command: { readonly accept: <R>(visitor: MongoDdlCommandVisitor<R>) => R };\n}\n\nexport function formatMongoOperations(operations: readonly MigrationPlanOperation[]): string[] {\n const statements: string[] = [];\n for (const operation of operations) {\n const candidate = operation as unknown as Record<string, unknown>;\n if (!('execute' in candidate) || !Array.isArray(candidate['execute'])) {\n continue;\n }\n for (const step of candidate['execute'] as MongoExecuteStep[]) {\n if (step.command && typeof step.command.accept === 'function') {\n statements.push(step.command.accept(formatter));\n }\n }\n }\n return statements;\n}\n\n/**\n * Wraps `formatMongoOperations` into the family-agnostic\n * `OperationPreview` shape. Each statement carries\n * `language: 'mongodb-shell'`. Mirrors `sqlOperationsToPreview`.\n */\nexport function mongoOperationsToPreview(\n operations: readonly MigrationPlanOperation[],\n): OperationPreview {\n return {\n statements: formatMongoOperations(operations).map((text) => ({\n text,\n language: 'mongodb-shell',\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 type {\n Contract,\n ContractMarkerRecord,\n LedgerEntryRecord,\n} from '@prisma-next/contract/types';\nimport type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';\nimport type {\n ControlDriverInstance,\n ControlFamilyInstance,\n ControlStack,\n CoreSchemaView,\n MigrationPlanOperation,\n OperationPreview,\n OperationPreviewCapable,\n SchemaViewCapable,\n SignDatabaseResult,\n VerifyDatabaseResult,\n VerifyDatabaseSchemaResult,\n} from '@prisma-next/framework-components/control';\nimport {\n APP_SPACE_ID,\n VERIFY_CODE_HASH_MISMATCH,\n VERIFY_CODE_MARKER_MISSING,\n VERIFY_CODE_TARGET_MISMATCH,\n} from '@prisma-next/framework-components/control';\nimport { assertDescriptorSelfConsistency } from '@prisma-next/migration-tools/spaces';\nimport type { MongoContract } from '@prisma-next/mongo-contract';\nimport { mongoContractCanonicalizationHooks } from '@prisma-next/mongo-contract/canonicalization-hooks';\nimport type { MongoSchemaIR } from '@prisma-next/mongo-schema-ir';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { MongoControlAdapter, MongoControlAdapterDescriptor } from './control-adapter';\nimport type { MongoControlExtensionDescriptor } from './control-types';\nimport { MongoContractSerializer } from './ir/mongo-contract-serializer';\nimport { mongoOperationsToPreview } from './operation-preview';\nimport { mongoSchemaToView } from './schema-to-view';\nimport { verifyMongoSchema } from './schema-verify/verify-mongo-schema';\n\nexport interface MongoControlFamilyInstance\n extends ControlFamilyInstance<'mongo', MongoSchemaIR>,\n SchemaViewCapable<MongoSchemaIR>,\n OperationPreviewCapable {\n /**\n * The family seam-of-record for on-disk contract reads. Structurally\n * validates the JSON envelope, then casts to the framework `Contract`\n * shape; the per-target serializer (held on the Mongo target\n * descriptor) does the class-form wrap for downstream consumers, so\n * the family only needs the validated data. The single named entry\n * point every CLI on-disk read crosses (TML-2536) — `as Contract`\n * casts in production package sources are a serializer-bypass smell\n * guarded by `pnpm lint:no-contract-cast`.\n */\n deserializeContract(contractJson: unknown): Contract;\n}\n\nfunction deserializeMongoContract(contractJson: unknown): MongoContract {\n // Structural validation only — the per-target serializer wraps the\n // result in a class-form `MongoTargetContract` for downstream\n // consumers (CLI, runner). The family-instance methods only read\n // hash/target fields off the validated shape, so the unwrapped\n // `MongoContract` is sufficient here and avoids a family→target\n // runtime dep.\n return new MongoContractSerializer().deserializeContract(contractJson);\n}\n\n/**\n * Family-method contract input. By the time control-plane methods\n * (`verify`, `verifySchema`, `sign`, …) are invoked through the CLI\n * control client (`client.ts`), the input has already been threaded\n * through `familyInstance.deserializeContract`. The value is therefore a\n * class-form `MongoTargetContract` (or a structurally-equivalent\n * envelope post-deserialization) and must NOT be re-fed through\n * structural validation (arktype rejects extra keys like `namespaces`).\n *\n * The parameter type on the framework SPI is `unknown` for variance\n * reasons (so the family can express its own contract type without\n * leaking it to the framework). This helper recovers the validated\n * shape with a single narrow cast.\n */\nfunction asValidatedMongoContract(contract: unknown): MongoContract {\n return contract as MongoContract;\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 // Descriptor self-consistency check.\n // Each extension that exposes a `contractSpace` must publish a\n // `headRef.hash` that matches the canonical hash recomputed from its\n // `contractJson`. A stale value would silently corrupt every downstream\n // boundary that trusts `headRef.hash` as the canonical identity (drift\n // detection, on-disk artefact emission, runner marker writes). Failing\n // fast at descriptor-load time turns \"extension author shipped an\n // inconsistent descriptor\" into an explicit, actionable error\n // (`MIGRATION.DESCRIPTOR_HEAD_HASH_MISMATCH`) rather than a confusing\n // mismatch surfacing several layers downstream. Mirrors the SQL family.\n const extensions = (controlStack.extensionPacks ??\n []) as readonly MongoControlExtensionDescriptor[];\n for (const extension of extensions) {\n if (extension.contractSpace) {\n const { contractJson, headRef } = extension.contractSpace;\n assertDescriptorSelfConsistency({\n extensionId: extension.id,\n target: contractJson.target,\n targetFamily: contractJson.targetFamily,\n storage: contractJson.storage,\n headRefHash: headRef.hash,\n ...mongoContractCanonicalizationHooks,\n });\n }\n }\n\n // Mongo dispatch surface. Every wire-level operation routes through\n // the adapter resolved from the control stack; the family carries no\n // direct imports of target/adapter/driver internals. Mirrors the SQL\n // family's `getControlAdapter()` helper.\n const adapter = controlStack.adapter as MongoControlAdapterDescriptor<'mongo'> | undefined;\n const getControlAdapter = (): MongoControlAdapter<'mongo'> => {\n if (!adapter) {\n throw new Error('Mongo family requires an adapter descriptor in ControlStack');\n }\n return adapter.create(controlStack as ControlStack<'mongo', 'mongo'>);\n };\n\n // The family-level driver type is `ControlDriverInstance<'mongo', string>`,\n // but the SPI methods are typed against `<'mongo', 'mongo'>`. Today's only\n // Mongo target is `'mongo'`, so the runtime values are identical; the cast\n // satisfies the structural type-system mismatch on `targetId`.\n const asMongoDriver = (\n driver: ControlDriverInstance<'mongo', string>,\n ): ControlDriverInstance<'mongo', 'mongo'> => driver as ControlDriverInstance<'mongo', 'mongo'>;\n\n return {\n familyId: 'mongo' as const,\n\n deserializeContract(contractJson: unknown): Contract {\n // The deserialized class form (MongoTargetContract, owned by\n // target-mongo) and the framework Contract are structurally\n // compatible — same fields, just a class instance on the storage\n // envelope. The cast preserves the framework signature.\n return deserializeMongoContract(contractJson) as unknown as Contract;\n },\n\n async verify(options): Promise<VerifyDatabaseResult> {\n const { driver, contract: rawContract, expectedTargetId, contractPath, configPath } = options;\n const startTime = Date.now();\n\n const contract = asValidatedMongoContract(rawContract);\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 marker = await getControlAdapter().readMarker(asMongoDriver(driver), APP_SPACE_ID);\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 verifySchema(options: {\n readonly contract: unknown;\n readonly schema: MongoSchemaIR;\n readonly strict: boolean;\n readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'mongo', string>>;\n }): VerifyDatabaseSchemaResult {\n const contract = asValidatedMongoContract(options.contract);\n return verifyMongoSchema({\n contract,\n schema: options.schema,\n strict: options.strict,\n frameworkComponents: options.frameworkComponents,\n });\n },\n\n async sign(options): Promise<SignDatabaseResult> {\n const { driver, contract: rawContract, contractPath, configPath } = options;\n const startTime = Date.now();\n\n const contract = asValidatedMongoContract(rawContract);\n\n const contractStorageHash = contract.storage.storageHash;\n const contractProfileHash = contract.profileHash;\n\n const controlAdapter = getControlAdapter();\n const mongoDriver = asMongoDriver(driver);\n\n const existingMarker = await controlAdapter.readMarker(mongoDriver, APP_SPACE_ID);\n\n let markerCreated = false;\n let markerUpdated = false;\n let previousHashes: { storageHash?: string; profileHash?: string } | undefined;\n\n if (!existingMarker) {\n await controlAdapter.initMarker(mongoDriver, APP_SPACE_ID, {\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 controlAdapter.updateMarker(\n mongoDriver,\n APP_SPACE_ID,\n existingMarker.storageHash,\n {\n storageHash: contractStorageHash,\n profileHash: contractProfileHash,\n },\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): Promise<ContractMarkerRecord | null> {\n return getControlAdapter().readMarker(asMongoDriver(options.driver), options.space);\n },\n\n async readAllMarkers(options): Promise<ReadonlyMap<string, ContractMarkerRecord>> {\n return getControlAdapter().readAllMarkers(asMongoDriver(options.driver));\n },\n\n async readLedger(options): Promise<readonly LedgerEntryRecord[]> {\n return getControlAdapter().readLedger(asMongoDriver(options.driver), options.space);\n },\n\n async introspect(options): Promise<MongoSchemaIR> {\n return getControlAdapter().introspectSchema(asMongoDriver(options.driver));\n },\n\n toSchemaView(schema: MongoSchemaIR): CoreSchemaView {\n return mongoSchemaToView(schema);\n },\n\n toOperationPreview(operations: readonly MigrationPlanOperation[]): OperationPreview {\n return mongoOperationsToPreview(operations);\n },\n };\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"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/family-mongo",
|
|
3
|
-
"version": "0.12.0-dev.
|
|
3
|
+
"version": "0.12.0-dev.11",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"description": "Mongo family descriptor for Prisma Next",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@prisma-next/contract": "0.12.0-dev.
|
|
10
|
-
"@prisma-next/emitter": "0.12.0-dev.
|
|
11
|
-
"@prisma-next/errors": "0.12.0-dev.
|
|
12
|
-
"@prisma-next/framework-components": "0.12.0-dev.
|
|
13
|
-
"@prisma-next/migration-tools": "0.12.0-dev.
|
|
14
|
-
"@prisma-next/mongo-contract": "0.12.0-dev.
|
|
15
|
-
"@prisma-next/mongo-emitter": "0.12.0-dev.
|
|
16
|
-
"@prisma-next/mongo-query-ast": "0.12.0-dev.
|
|
17
|
-
"@prisma-next/mongo-schema-ir": "0.12.0-dev.
|
|
18
|
-
"@prisma-next/utils": "0.12.0-dev.
|
|
9
|
+
"@prisma-next/contract": "0.12.0-dev.11",
|
|
10
|
+
"@prisma-next/emitter": "0.12.0-dev.11",
|
|
11
|
+
"@prisma-next/errors": "0.12.0-dev.11",
|
|
12
|
+
"@prisma-next/framework-components": "0.12.0-dev.11",
|
|
13
|
+
"@prisma-next/migration-tools": "0.12.0-dev.11",
|
|
14
|
+
"@prisma-next/mongo-contract": "0.12.0-dev.11",
|
|
15
|
+
"@prisma-next/mongo-emitter": "0.12.0-dev.11",
|
|
16
|
+
"@prisma-next/mongo-query-ast": "0.12.0-dev.11",
|
|
17
|
+
"@prisma-next/mongo-schema-ir": "0.12.0-dev.11",
|
|
18
|
+
"@prisma-next/utils": "0.12.0-dev.11",
|
|
19
19
|
"arktype": "^2.2.0",
|
|
20
20
|
"pathe": "^2.0.3"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"@prisma-next/mongo-contract-ts": "0.12.0-dev.
|
|
24
|
-
"@prisma-next/test-utils": "0.12.0-dev.
|
|
25
|
-
"@prisma-next/tsconfig": "0.12.0-dev.
|
|
26
|
-
"@prisma-next/tsdown": "0.12.0-dev.
|
|
23
|
+
"@prisma-next/mongo-contract-ts": "0.12.0-dev.11",
|
|
24
|
+
"@prisma-next/test-utils": "0.12.0-dev.11",
|
|
25
|
+
"@prisma-next/tsconfig": "0.12.0-dev.11",
|
|
26
|
+
"@prisma-next/tsdown": "0.12.0-dev.11",
|
|
27
27
|
"tsdown": "0.22.0",
|
|
28
28
|
"typescript": "5.9.3",
|
|
29
29
|
"vitest": "4.1.6"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ContractMarkerRecord } from '@prisma-next/contract/types';
|
|
1
|
+
import type { ContractMarkerRecord, LedgerEntryRecord } from '@prisma-next/contract/types';
|
|
2
2
|
import type {
|
|
3
3
|
ControlAdapterDescriptor,
|
|
4
4
|
ControlAdapterInstance,
|
|
@@ -79,9 +79,25 @@ export interface MongoControlAdapter<TTarget extends string = string>
|
|
|
79
79
|
writeLedgerEntry(
|
|
80
80
|
driver: ControlDriverInstance<'mongo', TTarget>,
|
|
81
81
|
space: string,
|
|
82
|
-
entry: {
|
|
82
|
+
entry: {
|
|
83
|
+
readonly edgeId: string;
|
|
84
|
+
readonly from: string;
|
|
85
|
+
readonly to: string;
|
|
86
|
+
readonly migrationName: string;
|
|
87
|
+
readonly migrationHash: string;
|
|
88
|
+
readonly operations: readonly unknown[];
|
|
89
|
+
},
|
|
83
90
|
): Promise<void>;
|
|
84
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Reads the per-migration ledger journal for `space` in apply order.
|
|
94
|
+
* Returns an empty array when no ledger entries exist for that space.
|
|
95
|
+
*/
|
|
96
|
+
readLedger(
|
|
97
|
+
driver: ControlDriverInstance<'mongo', TTarget>,
|
|
98
|
+
space: string,
|
|
99
|
+
): Promise<readonly LedgerEntryRecord[]>;
|
|
100
|
+
|
|
85
101
|
/**
|
|
86
102
|
* Introspects the live database and returns a `MongoSchemaIR`.
|
|
87
103
|
*/
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
Contract,
|
|
3
|
+
ContractMarkerRecord,
|
|
4
|
+
LedgerEntryRecord,
|
|
5
|
+
} from '@prisma-next/contract/types';
|
|
2
6
|
import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
|
|
3
7
|
import type {
|
|
4
8
|
ControlDriverInstance,
|
|
@@ -76,19 +80,6 @@ function asValidatedMongoContract(contract: unknown): MongoContract {
|
|
|
76
80
|
return contract as MongoContract;
|
|
77
81
|
}
|
|
78
82
|
|
|
79
|
-
function isMongoControlAdapter(value: unknown): value is MongoControlAdapter<'mongo'> {
|
|
80
|
-
return (
|
|
81
|
-
typeof value === 'object' &&
|
|
82
|
-
value !== null &&
|
|
83
|
-
'readMarker' in value &&
|
|
84
|
-
typeof (value as { readMarker: unknown }).readMarker === 'function' &&
|
|
85
|
-
'readAllMarkers' in value &&
|
|
86
|
-
typeof (value as { readAllMarkers: unknown }).readAllMarkers === 'function' &&
|
|
87
|
-
'introspectSchema' in value &&
|
|
88
|
-
typeof (value as { introspectSchema: unknown }).introspectSchema === 'function'
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
83
|
function buildVerifyResult(opts: {
|
|
93
84
|
ok: boolean;
|
|
94
85
|
code?: string;
|
|
@@ -164,13 +155,7 @@ export function createMongoFamilyInstance(controlStack: ControlStack): MongoCont
|
|
|
164
155
|
if (!adapter) {
|
|
165
156
|
throw new Error('Mongo family requires an adapter descriptor in ControlStack');
|
|
166
157
|
}
|
|
167
|
-
|
|
168
|
-
if (!isMongoControlAdapter(controlAdapter)) {
|
|
169
|
-
throw new Error(
|
|
170
|
-
'Adapter does not implement MongoControlAdapter (missing readMarker, readAllMarkers, or introspectSchema)',
|
|
171
|
-
);
|
|
172
|
-
}
|
|
173
|
-
return controlAdapter;
|
|
158
|
+
return adapter.create(controlStack as ControlStack<'mongo', 'mongo'>);
|
|
174
159
|
};
|
|
175
160
|
|
|
176
161
|
// The family-level driver type is `ControlDriverInstance<'mongo', string>`,
|
|
@@ -371,6 +356,10 @@ export function createMongoFamilyInstance(controlStack: ControlStack): MongoCont
|
|
|
371
356
|
return getControlAdapter().readAllMarkers(asMongoDriver(options.driver));
|
|
372
357
|
},
|
|
373
358
|
|
|
359
|
+
async readLedger(options): Promise<readonly LedgerEntryRecord[]> {
|
|
360
|
+
return getControlAdapter().readLedger(asMongoDriver(options.driver), options.space);
|
|
361
|
+
},
|
|
362
|
+
|
|
374
363
|
async introspect(options): Promise<MongoSchemaIR> {
|
|
375
364
|
return getControlAdapter().introspectSchema(asMongoDriver(options.driver));
|
|
376
365
|
},
|