@prisma-next/family-mongo 0.12.0-dev.16 → 0.12.0-dev.17

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.
@@ -1,7 +1,7 @@
1
1
  import { MongoSchemaIR } from "@prisma-next/mongo-schema-ir";
2
2
  import { ContractSerializer, ContractSpace, ControlExtensionDescriptor, ControlFamilyDescriptor, ControlFamilyInstance, ControlStack, MigratableTargetDescriptor, MigrationPlanOperation, OperationPreview, OperationPreviewCapable, SchemaIssue, SchemaVerificationNode, SchemaVerifier, SchemaViewCapable } from "@prisma-next/framework-components/control";
3
3
  import { MongoContract, MongoStorageShape } from "@prisma-next/mongo-contract";
4
- import { Contract } from "@prisma-next/contract/types";
4
+ import { Contract, ControlPolicy } from "@prisma-next/contract/types";
5
5
 
6
6
  //#region src/core/contract-to-schema.d.ts
7
7
  declare function contractToMongoSchemaIR(contract: MongoContract | null): MongoSchemaIR;
@@ -73,7 +73,7 @@ declare function formatMongoOperations(operations: readonly MigrationPlanOperati
73
73
  declare function mongoOperationsToPreview(operations: readonly MigrationPlanOperation[]): OperationPreview;
74
74
  //#endregion
75
75
  //#region src/core/schema-diff.d.ts
76
- declare function diffMongoSchemas(live: MongoSchemaIR, expected: MongoSchemaIR, strict: boolean): {
76
+ declare function diffMongoSchemas(live: MongoSchemaIR, expected: MongoSchemaIR, strict: boolean, collectionControlPolicy: (collectionName: string) => ControlPolicy): {
77
77
  root: SchemaVerificationNode;
78
78
  issues: SchemaIssue[];
79
79
  counts: {
@@ -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;;;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"}
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;;;iBC7GH,gBAAA,CACd,IAAA,EAAM,aAAA,EACN,QAAA,EAAU,aAAA,EACV,MAAA,WACA,uBAAA,GAA0B,cAAA,aAA2B,aAAA;EAErD,IAAA,EAAM,sBAAA;EACN,MAAA,EAAQ,WAAA;EACR,MAAA;IAAU,IAAA;IAAc,IAAA;IAAc,IAAA;IAAc,UAAA;EAAA;AAAA;;;UCQrC,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
@@ -1,4 +1,4 @@
1
- import { i as contractToMongoSchemaIR, n as canonicalizeSchemasForVerification, r as diffMongoSchemas, t as verifyMongoSchema } from "./verify-mongo-schema-Bhxvdah3.mjs";
1
+ import { i as contractToMongoSchemaIR, n as canonicalizeSchemasForVerification, r as diffMongoSchemas, t as verifyMongoSchema } from "./verify-mongo-schema-BXJqoE59.mjs";
2
2
  import { t as MongoContractSerializer } from "./mongo-contract-serializer-DAoKJxiP.mjs";
3
3
  import { mongoEmission } from "@prisma-next/mongo-emitter";
4
4
  import { APP_SPACE_ID, SchemaTreeNode, VERIFY_CODE_HASH_MISMATCH, VERIFY_CODE_MARKER_MISSING, VERIFY_CODE_TARGET_MISMATCH } from "@prisma-next/framework-components/control";
package/dist/ir.d.mts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { ContractSerializer, SchemaIssue, SchemaVerifier, SchemaVerifyOptions, SchemaVerifyResult } from "@prisma-next/framework-components/control";
2
- import { MongoContract, MongoStorage } from "@prisma-next/mongo-contract";
2
+ import { MongoCollection, MongoContract, MongoStorage } from "@prisma-next/mongo-contract";
3
3
  import { Type } from "arktype";
4
+ import { ControlPolicy } from "@prisma-next/contract/types";
4
5
  import { Namespace } from "@prisma-next/framework-components/ir";
5
6
  import * as _$_prisma_next_contract_hashing0 from "@prisma-next/contract/hashing";
6
7
  import { JsonObject } from "@prisma-next/utils/json";
@@ -113,8 +114,11 @@ declare class MongoContractSerializer extends MongoContractSerializerBase<MongoC
113
114
  */
114
115
  declare abstract class MongoSchemaVerifierBase<TContract extends {
115
116
  readonly storage: MongoStorage;
117
+ readonly defaultControl?: ControlPolicy;
116
118
  }, TSchema> implements SchemaVerifier<TContract, TSchema> {
117
119
  verifySchema(options: SchemaVerifyOptions<TContract, TSchema>): SchemaVerifyResult;
120
+ protected effectiveCollectionControlPolicy(contract: TContract, collection: MongoCollection | undefined): ControlPolicy;
121
+ protected collectionControlPolicyForName(contract: TContract, collectionName: string): ControlPolicy;
118
122
  protected verifyCommonMongoSchema(options: SchemaVerifyOptions<TContract, TSchema>): readonly SchemaIssue[];
119
123
  /**
120
124
  * Per-namespace verification hook. Receives the namespace metadata plus
package/dist/ir.d.mts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ir.d.mts","names":[],"sources":["../src/core/ir/mongo-contract-serializer-base.ts","../src/core/ir/mongo-contract-serializer.ts","../src/core/ir/mongo-schema-verifier-base.ts"],"mappings":";;;;;;;;;;;;AAmCA;;;;;;;;;;;;;;;;;uBAAsB,2BAAA,uBACT,kBAAA,CAAmB,SAAA;EAAA,iBAEb,cAAA;cAEL,kBAAA,GAAqB,WAAA,SAAoB,IAAA;EAUrD,mBAAA,WAA8B,SAAA,GAAY,SAAA,CAAA,CAAW,IAAA,YAAgB,CAAA;EAKrE,iBAAA,CAAkB,QAAA,EAAU,SAAA,GAAY,UAAA;EAnBV;;;;;;EAgC9B,mBAAA,EAbkD,gCAAA,CAa/B,sBAAA;EAlBC;;;;;;;;;;;;;;;;EAAA,UAoCV,2BAAA,CAA4B,IAAA,YAAgB,aAAA;EAmCG;;;;;;EAAA,UAA/C,oBAAA,CAAqB,QAAA,EAAU,aAAA,GAAgB,aAAA;;;;AC5G3D;;;;;qBDkJqB,uBAAA,CAAwB,SAAA,EAAW,aAAA,GAAgB,SAAA;AAAA;;;;;;;;;AA5HxE;;;;cCtBa,uBAAA,SAAgC,2BAAA,CAA4B,aAAA;EAAA,UAC7D,uBAAA,CAAwB,SAAA,EAAW,aAAA,GAAgB,aAAA;AAAA;;;;;;;;ADqB/D;;;;;;;;;;;;;;;;uBELsB,uBAAA;EAAA,SACS,OAAA,EAAS,YAAA;AAAA,uBAE3B,cAAA,CAAe,SAAA,EAAW,OAAA;EAErC,YAAA,CAAa,OAAA,EAAS,mBAAA,CAAoB,SAAA,EAAW,OAAA,IAAW,kBAAA;EAAA,UAOtD,uBAAA,CACR,OAAA,EAAS,mBAAA,CAAoB,SAAA,EAAW,OAAA,aAC9B,WAAA;EFRD;;;;;;;;EAAA,mBEmCQ,eAAA,CAAgB,OAAA;IAAA,SACxB,QAAA,EAAU,SAAA;IAAA,SACV,MAAA,EAAQ,OAAA;IAAA,SACR,WAAA;IAAA,SACA,SAAA,EAAW,SAAA;EAAA,aACT,WAAA;EFrBe;;;;;EAAA,mBE4BT,sBAAA,CACjB,OAAA,EAAS,mBAAA,CAAoB,SAAA,EAAW,OAAA,aAC9B,WAAA;AAAA"}
1
+ {"version":3,"file":"ir.d.mts","names":[],"sources":["../src/core/ir/mongo-contract-serializer-base.ts","../src/core/ir/mongo-contract-serializer.ts","../src/core/ir/mongo-schema-verifier-base.ts"],"mappings":";;;;;;;;;;;;;;AAmCA;;;;;;;;;;;;;;;;uBAAsB,2BAAA,uBACT,kBAAA,CAAmB,SAAA;EAAA,iBAEb,cAAA;cAEL,kBAAA,GAAqB,WAAA,SAAoB,IAAA;EAUrD,mBAAA,WAA8B,SAAA,GAAY,SAAA,CAAA,CAAW,IAAA,YAAgB,CAAA;EAKrE,iBAAA,CAAkB,QAAA,EAAU,SAAA,GAAY,UAAA;EAnB7B;;;;;;EAgCX,mBAAA,EAbkD,gCAAA,CAa/B,sBAAA;EAlBnB;;;;;;;;;;;;;;;;EAAA,UAoCU,2BAAA,CAA4B,IAAA,YAAgB,aAAA;EAmCvB;;;;;;EAAA,UAArB,oBAAA,CAAqB,QAAA,EAAU,aAAA,GAAgB,aAAA;EAsCsB;;;;AClJjF;;;;EDkJiF,mBAA5D,uBAAA,CAAwB,SAAA,EAAW,aAAA,GAAgB,SAAA;AAAA;;;;;;;;;;AA5HxE;;;cCtBa,uBAAA,SAAgC,2BAAA,CAA4B,aAAA;EAAA,UAC7D,uBAAA,CAAwB,SAAA,EAAW,aAAA,GAAgB,aAAA;AAAA;;;;;;;;ADqB/D;;;;;;;;;;;;;;;;uBEFsB,uBAAA;EAAA,SACS,OAAA,EAAS,YAAA;EAAA,SAAuB,cAAA,GAAiB,aAAA;AAAA,uBAEnE,cAAA,CAAe,SAAA,EAAW,OAAA;EAErC,YAAA,CAAa,OAAA,EAAS,mBAAA,CAAoB,SAAA,EAAW,OAAA,IAAW,kBAAA;EAAA,UAOtD,gCAAA,CACR,QAAA,EAAU,SAAA,EACV,UAAA,EAAY,eAAA,eACX,aAAA;EAAA,UAIO,8BAAA,CACR,QAAA,EAAU,SAAA,EACV,cAAA,WACC,aAAA;EAAA,UAMO,uBAAA,CACR,OAAA,EAAS,mBAAA,CAAoB,SAAA,EAAW,OAAA,aAC9B,WAAA;;;;;;;;;qBA2BO,eAAA,CAAgB,OAAA;IAAA,SACxB,QAAA,EAAU,SAAA;IAAA,SACV,MAAA,EAAQ,OAAA;IAAA,SACR,WAAA;IAAA,SACA,SAAA,EAAW,SAAA;EAAA,aACT,WAAA;EF3Bb;;;;;EAAA,mBEkCmB,sBAAA,CACjB,OAAA,EAAS,mBAAA,CAAoB,SAAA,EAAW,OAAA,aAC9B,WAAA;AAAA"}
package/dist/ir.mjs CHANGED
@@ -1,4 +1,6 @@
1
1
  import { n as MongoContractSerializerBase, t as MongoContractSerializer } from "./mongo-contract-serializer-DAoKJxiP.mjs";
2
+ import { effectiveControlPolicy } from "@prisma-next/contract/types";
3
+ import { UNBOUND_NAMESPACE_ID } from "@prisma-next/framework-components/ir";
2
4
  //#region src/core/ir/mongo-schema-verifier-base.ts
3
5
  /**
4
6
  * Mongo family `SchemaVerifier` abstract base. Commits the Mongo family
@@ -31,6 +33,13 @@ var MongoSchemaVerifierBase = class {
31
33
  issues
32
34
  };
33
35
  }
36
+ effectiveCollectionControlPolicy(contract, collection) {
37
+ return effectiveControlPolicy(collection?.control, contract.defaultControl);
38
+ }
39
+ collectionControlPolicyForName(contract, collectionName) {
40
+ const collection = contract.storage.namespaces[UNBOUND_NAMESPACE_ID]?.collections[collectionName];
41
+ return this.effectiveCollectionControlPolicy(contract, collection);
42
+ }
34
43
  verifyCommonMongoSchema(options) {
35
44
  const issues = [];
36
45
  const { namespaces } = options.contract.storage;
package/dist/ir.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ir.mjs","names":[],"sources":["../src/core/ir/mongo-schema-verifier-base.ts"],"sourcesContent":["import type {\n SchemaIssue,\n SchemaVerifier,\n SchemaVerifyOptions,\n SchemaVerifyResult,\n} from '@prisma-next/framework-components/control';\nimport type { Namespace } from '@prisma-next/framework-components/ir';\nimport type { MongoStorage } from '@prisma-next/mongo-contract';\n\n/**\n * Mongo family `SchemaVerifier` abstract base. Commits the Mongo family\n * to namespace-keyed verification: the family-shared walk iterates\n * `storage.namespaces` in sorted order and dispatches per-namespace\n * through the protected `verifyNamespace` hook, then aggregates\n * target-extension issues from `verifyTargetExtensions`.\n *\n * Per-element diff work (collection / index / validator comparisons)\n * lives on the target inside `verifyNamespace`. The family's structural\n * commitment is \"verification is namespaced\"; the target's commitment is\n * \"verification of a given namespace's collections is the existing\n * diff/canonicalize pipeline\". The split keeps target-mongo's\n * introspection-side helpers (`contractToMongoSchemaIR`,\n * `canonicalizeSchemasForVerification`, `diffMongoSchemas`) in the target\n * layer where they belong, while the family base owns the iteration\n * scaffolding that makes namespaces a first-class verifier concept.\n *\n * Target-specific issue kinds (Atlas-only, future RLS-equivalents)\n * surface through `verifyTargetExtensions`; that hook returns the empty\n * list when no extensions exist over the Mongo family alphabet.\n */\nexport abstract class MongoSchemaVerifierBase<\n TContract extends { readonly storage: MongoStorage },\n TSchema,\n> implements SchemaVerifier<TContract, TSchema>\n{\n verifySchema(options: SchemaVerifyOptions<TContract, TSchema>): SchemaVerifyResult {\n const issues: SchemaIssue[] = [];\n issues.push(...this.verifyCommonMongoSchema(options));\n issues.push(...this.verifyTargetExtensions(options));\n return { ok: issues.length === 0, issues };\n }\n\n protected verifyCommonMongoSchema(\n options: SchemaVerifyOptions<TContract, TSchema>,\n ): readonly SchemaIssue[] {\n const issues: SchemaIssue[] = [];\n const { namespaces } = options.contract.storage;\n const namespaceIds = Object.keys(namespaces).sort();\n for (const namespaceId of namespaceIds) {\n const namespace = namespaces[namespaceId];\n if (!namespace) continue;\n issues.push(\n ...this.verifyNamespace({\n contract: options.contract,\n schema: options.schema,\n namespaceId,\n namespace,\n }),\n );\n }\n return issues;\n }\n\n /**\n * Per-namespace verification hook. Receives the namespace metadata plus\n * the full contract + schema pair; the target's implementation owns the\n * per-collection diff using its existing introspection-side helpers.\n * Slice the schema by namespace at the call site (or compute the full\n * diff once and dispatch per namespace) — the family base does not\n * prescribe the per-namespace shape.\n */\n protected abstract verifyNamespace(options: {\n readonly contract: TContract;\n readonly schema: TSchema;\n readonly namespaceId: string;\n readonly namespace: Namespace;\n }): readonly SchemaIssue[];\n\n /**\n * Target-specific extensions — Atlas-only kinds, target-only\n * namespace-mismatch issues that don't fit the family-shared walk.\n * Returns the empty list when the target ships no extensions.\n */\n protected abstract verifyTargetExtensions(\n options: SchemaVerifyOptions<TContract, TSchema>,\n ): readonly SchemaIssue[];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AA8BA,IAAsB,0BAAtB,MAIA;CACE,aAAa,SAAsE;EACjF,MAAM,SAAwB,CAAC;EAC/B,OAAO,KAAK,GAAG,KAAK,wBAAwB,OAAO,CAAC;EACpD,OAAO,KAAK,GAAG,KAAK,uBAAuB,OAAO,CAAC;EACnD,OAAO;GAAE,IAAI,OAAO,WAAW;GAAG;EAAO;CAC3C;CAEA,wBACE,SACwB;EACxB,MAAM,SAAwB,CAAC;EAC/B,MAAM,EAAE,eAAe,QAAQ,SAAS;EACxC,MAAM,eAAe,OAAO,KAAK,UAAU,EAAE,KAAK;EAClD,KAAK,MAAM,eAAe,cAAc;GACtC,MAAM,YAAY,WAAW;GAC7B,IAAI,CAAC,WAAW;GAChB,OAAO,KACL,GAAG,KAAK,gBAAgB;IACtB,UAAU,QAAQ;IAClB,QAAQ,QAAQ;IAChB;IACA;GACF,CAAC,CACH;EACF;EACA,OAAO;CACT;AAyBF"}
1
+ {"version":3,"file":"ir.mjs","names":[],"sources":["../src/core/ir/mongo-schema-verifier-base.ts"],"sourcesContent":["import type { ControlPolicy } from '@prisma-next/contract/types';\nimport { effectiveControlPolicy } from '@prisma-next/contract/types';\nimport type {\n SchemaIssue,\n SchemaVerifier,\n SchemaVerifyOptions,\n SchemaVerifyResult,\n} from '@prisma-next/framework-components/control';\nimport type { Namespace } from '@prisma-next/framework-components/ir';\nimport { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';\nimport type { MongoCollection, MongoStorage } from '@prisma-next/mongo-contract';\n\n/**\n * Mongo family `SchemaVerifier` abstract base. Commits the Mongo family\n * to namespace-keyed verification: the family-shared walk iterates\n * `storage.namespaces` in sorted order and dispatches per-namespace\n * through the protected `verifyNamespace` hook, then aggregates\n * target-extension issues from `verifyTargetExtensions`.\n *\n * Per-element diff work (collection / index / validator comparisons)\n * lives on the target inside `verifyNamespace`. The family's structural\n * commitment is \"verification is namespaced\"; the target's commitment is\n * \"verification of a given namespace's collections is the existing\n * diff/canonicalize pipeline\". The split keeps target-mongo's\n * introspection-side helpers (`contractToMongoSchemaIR`,\n * `canonicalizeSchemasForVerification`, `diffMongoSchemas`) in the target\n * layer where they belong, while the family base owns the iteration\n * scaffolding that makes namespaces a first-class verifier concept.\n *\n * Target-specific issue kinds (Atlas-only, future RLS-equivalents)\n * surface through `verifyTargetExtensions`; that hook returns the empty\n * list when no extensions exist over the Mongo family alphabet.\n */\nexport abstract class MongoSchemaVerifierBase<\n TContract extends { readonly storage: MongoStorage; readonly defaultControl?: ControlPolicy },\n TSchema,\n> implements SchemaVerifier<TContract, TSchema>\n{\n verifySchema(options: SchemaVerifyOptions<TContract, TSchema>): SchemaVerifyResult {\n const issues: SchemaIssue[] = [];\n issues.push(...this.verifyCommonMongoSchema(options));\n issues.push(...this.verifyTargetExtensions(options));\n return { ok: issues.length === 0, issues };\n }\n\n protected effectiveCollectionControlPolicy(\n contract: TContract,\n collection: MongoCollection | undefined,\n ): ControlPolicy {\n return effectiveControlPolicy(collection?.control, contract.defaultControl);\n }\n\n protected collectionControlPolicyForName(\n contract: TContract,\n collectionName: string,\n ): ControlPolicy {\n const namespace = contract.storage.namespaces[UNBOUND_NAMESPACE_ID];\n const collection = namespace?.collections[collectionName];\n return this.effectiveCollectionControlPolicy(contract, collection);\n }\n\n protected verifyCommonMongoSchema(\n options: SchemaVerifyOptions<TContract, TSchema>,\n ): readonly SchemaIssue[] {\n const issues: SchemaIssue[] = [];\n const { namespaces } = options.contract.storage;\n const namespaceIds = Object.keys(namespaces).sort();\n for (const namespaceId of namespaceIds) {\n const namespace = namespaces[namespaceId];\n if (!namespace) continue;\n issues.push(\n ...this.verifyNamespace({\n contract: options.contract,\n schema: options.schema,\n namespaceId,\n namespace,\n }),\n );\n }\n return issues;\n }\n\n /**\n * Per-namespace verification hook. Receives the namespace metadata plus\n * the full contract + schema pair; the target's implementation owns the\n * per-collection diff using its existing introspection-side helpers.\n * Slice the schema by namespace at the call site (or compute the full\n * diff once and dispatch per namespace) — the family base does not\n * prescribe the per-namespace shape.\n */\n protected abstract verifyNamespace(options: {\n readonly contract: TContract;\n readonly schema: TSchema;\n readonly namespaceId: string;\n readonly namespace: Namespace;\n }): readonly SchemaIssue[];\n\n /**\n * Target-specific extensions — Atlas-only kinds, target-only\n * namespace-mismatch issues that don't fit the family-shared walk.\n * Returns the empty list when the target ships no extensions.\n */\n protected abstract verifyTargetExtensions(\n options: SchemaVerifyOptions<TContract, TSchema>,\n ): readonly SchemaIssue[];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAiCA,IAAsB,0BAAtB,MAIA;CACE,aAAa,SAAsE;EACjF,MAAM,SAAwB,CAAC;EAC/B,OAAO,KAAK,GAAG,KAAK,wBAAwB,OAAO,CAAC;EACpD,OAAO,KAAK,GAAG,KAAK,uBAAuB,OAAO,CAAC;EACnD,OAAO;GAAE,IAAI,OAAO,WAAW;GAAG;EAAO;CAC3C;CAEA,iCACE,UACA,YACe;EACf,OAAO,uBAAuB,YAAY,SAAS,SAAS,cAAc;CAC5E;CAEA,+BACE,UACA,gBACe;EAEf,MAAM,aADY,SAAS,QAAQ,WAAW,uBAChB,YAAY;EAC1C,OAAO,KAAK,iCAAiC,UAAU,UAAU;CACnE;CAEA,wBACE,SACwB;EACxB,MAAM,SAAwB,CAAC;EAC/B,MAAM,EAAE,eAAe,QAAQ,SAAS;EACxC,MAAM,eAAe,OAAO,KAAK,UAAU,EAAE,KAAK;EAClD,KAAK,MAAM,eAAe,cAAc;GACtC,MAAM,YAAY,WAAW;GAC7B,IAAI,CAAC,WAAW;GAChB,OAAO,KACL,GAAG,KAAK,gBAAgB;IACtB,UAAU,QAAQ;IAClB,QAAQ,QAAQ;IAChB;IACA;GACF,CAAC,CACH;EACF;EACA,OAAO;CACT;AAyBF"}
@@ -1 +1 @@
1
- {"version":3,"file":"schema-verify.d.mts","names":[],"sources":["../src/core/schema-verify/verify-mongo-schema.ts"],"mappings":";;;;;;UAaiB,wBAAA;EAAA,SACN,QAAA,EAAU,aAAA;EAAA,SACV,MAAA,EAAQ,aAAA;EAAA,SACR,MAAA;EAAA,SACA,OAAA,GAAU,gBAAA;EAHA;;;;;EAAA,SASV,mBAAA,EAAqB,aAAA,CAAc,8BAAA;AAAA;AAAA,iBAG9B,iBAAA,CAAkB,OAAA,EAAS,wBAAA,GAA2B,0BAA0B"}
1
+ {"version":3,"file":"schema-verify.d.mts","names":[],"sources":["../src/core/schema-verify/verify-mongo-schema.ts"],"mappings":";;;;;;UAeiB,wBAAA;EAAA,SACN,QAAA,EAAU,aAAA;EAAA,SACV,MAAA,EAAQ,aAAA;EAAA,SACR,MAAA;EAAA,SACA,OAAA,GAAU,gBAAA;EAHA;;;;;EAAA,SASV,mBAAA,EAAqB,aAAA,CAAc,8BAAA;AAAA;AAAA,iBAG9B,iBAAA,CAAkB,OAAA,EAAS,wBAAA,GAA2B,0BAA0B"}
@@ -1,2 +1,2 @@
1
- import { t as verifyMongoSchema } from "./verify-mongo-schema-Bhxvdah3.mjs";
1
+ import { t as verifyMongoSchema } from "./verify-mongo-schema-BXJqoE59.mjs";
2
2
  export { verifyMongoSchema };
@@ -1,6 +1,7 @@
1
1
  import { MongoSchemaCollection, MongoSchemaCollectionOptions, MongoSchemaIR, MongoSchemaIndex, MongoSchemaValidator, canonicalize, deepEqual } from "@prisma-next/mongo-schema-ir";
2
- import { VERIFY_CODE_SCHEMA_FAILURE } from "@prisma-next/framework-components/control";
2
+ import { VERIFY_CODE_SCHEMA_FAILURE, dispositionForCategory } from "@prisma-next/framework-components/control";
3
3
  import { ifDefined } from "@prisma-next/utils/defined";
4
+ import { effectiveControlPolicy } from "@prisma-next/contract/types";
4
5
  import { UNBOUND_NAMESPACE_ID } from "@prisma-next/framework-components/ir";
5
6
  //#region src/core/contract-to-schema.ts
6
7
  function stripIrKind(node) {
@@ -56,8 +57,72 @@ function contractToMongoSchemaIR(contract) {
56
57
  return new MongoSchemaIR(collections);
57
58
  }
58
59
  //#endregion
60
+ //#region src/core/schema-verify/verifier-disposition.ts
61
+ /**
62
+ * Classifies the verifier issue kinds the Mongo schema differ emits into the
63
+ * target-neutral categories the framework grades. Mongo only emits the kinds
64
+ * listed below (missing/extra collections, missing/extra indexes, missing/extra
65
+ * validators, and validator/options mismatches coded as `type_mismatch`); any
66
+ * other kind never reaches this classifier and is graded conservatively as a
67
+ * declared-incompatible divergence. Mongo owns this mapping rather than
68
+ * importing the SQL classifier — the two families share only the framework's
69
+ * category grading.
70
+ */
71
+ function classifyMongoVerifierIssueKind(kind) {
72
+ switch (kind) {
73
+ case "extra_table": return "extraTopLevelObject";
74
+ case "extra_index":
75
+ case "extra_validator": return "extraAuxiliary";
76
+ case "missing_table":
77
+ case "type_missing": return "declaredMissing";
78
+ case "index_mismatch":
79
+ case "type_mismatch": return "declaredIncompatible";
80
+ default: return "declaredIncompatible";
81
+ }
82
+ }
83
+ function verifierDisposition(controlPolicy, issueKind) {
84
+ return dispositionForCategory(controlPolicy, classifyMongoVerifierIssueKind(issueKind));
85
+ }
86
+ //#endregion
87
+ //#region src/core/schema-verify/mongo-control-verify-emit.ts
88
+ /**
89
+ * Reconciles a control-policy disposition with the Mongo family's strict-mode
90
+ * contract for live-only extras — the single point where `strict` and the
91
+ * control policy meet.
92
+ *
93
+ * The control policy decides first; only a `fail` is reconciled against the
94
+ * caller's base node status. Call sites stamp a live-only extra with
95
+ * `strict ? 'fail' : 'warn'` and a declared missing/mismatch with `fail`, so
96
+ * this one step encodes the whole matrix:
97
+ *
98
+ * | live-vs-declared | strict | non-strict |
99
+ * |-------------------------------------|----------|------------|
100
+ * | declared missing / mismatch | fail | fail |
101
+ * | live-only extra (managed/tolerated) | fail | warn |
102
+ * | live-only extra (external) | suppress (extras ignored, both modes) |
103
+ * | anything (observed) | warn (both modes) |
104
+ *
105
+ * `tolerated` no longer diverges from `managed` on a non-strict extra index:
106
+ * both soften to `warn`, because the softening comes from the base status the
107
+ * caller already computed from `strict`, not from per-policy special-casing.
108
+ */
109
+ function reconcileMongoOutcome(controlPolicy, issueKind, baseStatus) {
110
+ const disposition = verifierDisposition(controlPolicy, issueKind);
111
+ return disposition === "fail" ? baseStatus : disposition;
112
+ }
113
+ function emitMongoIssueAndNodeUnderControlPolicy(controlPolicy, issue, node, issues, nodes) {
114
+ const outcome = reconcileMongoOutcome(controlPolicy, issue.kind, node.status);
115
+ if (outcome === "suppress") return "suppress";
116
+ issues.push(issue);
117
+ nodes.push({
118
+ ...node,
119
+ status: outcome
120
+ });
121
+ return outcome;
122
+ }
123
+ //#endregion
59
124
  //#region src/core/schema-diff.ts
60
- function diffMongoSchemas(live, expected, strict) {
125
+ function diffMongoSchemas(live, expected, strict, collectionControlPolicy) {
61
126
  const issues = [];
62
127
  const collectionChildren = [];
63
128
  let pass = 0;
@@ -68,12 +133,11 @@ function diffMongoSchemas(live, expected, strict) {
68
133
  const liveColl = live.collection(name);
69
134
  const expectedColl = expected.collection(name);
70
135
  if (!liveColl && expectedColl) {
71
- issues.push({
136
+ const disposition = emitMongoIssueAndNodeUnderControlPolicy(collectionControlPolicy(name), {
72
137
  kind: "missing_table",
73
138
  table: name,
74
139
  message: `Collection "${name}" is missing from the database`
75
- });
76
- collectionChildren.push({
140
+ }, {
77
141
  status: "fail",
78
142
  kind: "collection",
79
143
  name,
@@ -83,19 +147,18 @@ function diffMongoSchemas(live, expected, strict) {
83
147
  expected: name,
84
148
  actual: null,
85
149
  children: []
86
- });
87
- fail++;
150
+ }, issues, collectionChildren);
151
+ if (disposition === "fail") fail++;
152
+ else if (disposition === "warn") warn++;
88
153
  continue;
89
154
  }
90
155
  if (liveColl && !expectedColl) {
91
- const status = strict ? "fail" : "warn";
92
- issues.push({
156
+ const disposition = emitMongoIssueAndNodeUnderControlPolicy(collectionControlPolicy(name), {
93
157
  kind: "extra_table",
94
158
  table: name,
95
159
  message: `Extra collection "${name}" exists in the database but not in the contract`
96
- });
97
- collectionChildren.push({
98
- status,
160
+ }, {
161
+ status: strict ? "fail" : "warn",
99
162
  kind: "collection",
100
163
  name,
101
164
  contractPath: `storage.namespaces.${UNBOUND_NAMESPACE_ID}.collections.${name}`,
@@ -104,16 +167,17 @@ function diffMongoSchemas(live, expected, strict) {
104
167
  expected: null,
105
168
  actual: name,
106
169
  children: []
107
- });
108
- if (status === "fail") fail++;
109
- else warn++;
170
+ }, issues, collectionChildren);
171
+ if (disposition === "fail") fail++;
172
+ else if (disposition === "warn") warn++;
110
173
  continue;
111
174
  }
112
175
  const lc = liveColl;
113
176
  const ec = expectedColl;
114
- const indexChildren = diffIndexes(name, lc, ec, strict, issues);
115
- const validatorChildren = diffValidator(name, lc, ec, strict, issues);
116
- const optionsChildren = diffOptions(name, lc, ec, strict, issues);
177
+ const controlPolicy = collectionControlPolicy(name);
178
+ const indexChildren = diffIndexes(name, lc, ec, strict, controlPolicy, issues);
179
+ const validatorChildren = diffValidator(name, lc, ec, strict, controlPolicy, issues);
180
+ const optionsChildren = diffOptions(name, lc, ec, strict, controlPolicy, issues);
117
181
  const children = [
118
182
  ...indexChildren,
119
183
  ...validatorChildren,
@@ -177,7 +241,7 @@ function buildIndexLookupKey(index) {
177
241
  function formatIndexName(index) {
178
242
  return index.keys.map((k) => `${k.field}:${k.direction}`).join(", ");
179
243
  }
180
- function diffIndexes(collName, live, expected, strict, issues) {
244
+ function diffIndexes(collName, live, expected, strict, collectionControlPolicy, issues) {
181
245
  const nodes = [];
182
246
  const liveLookup = /* @__PURE__ */ new Map();
183
247
  for (const idx of live.indexes) liveLookup.set(buildIndexLookupKey(idx), idx);
@@ -194,56 +258,50 @@ function diffIndexes(collName, live, expected, strict, issues) {
194
258
  actual: key,
195
259
  children: []
196
260
  });
197
- else {
198
- issues.push({
199
- kind: "index_mismatch",
200
- table: collName,
201
- indexOrConstraint: formatIndexName(idx),
202
- message: `Index ${formatIndexName(idx)} missing on collection "${collName}"`
203
- });
204
- nodes.push({
205
- status: "fail",
206
- kind: "index",
207
- name: formatIndexName(idx),
208
- contractPath: `storage.namespaces.${UNBOUND_NAMESPACE_ID}.collections.${collName}.indexes`,
209
- code: "MISSING_INDEX",
210
- message: `Index ${formatIndexName(idx)} missing`,
211
- expected: key,
212
- actual: null,
213
- children: []
214
- });
215
- }
216
- for (const [key, idx] of liveLookup) if (!expectedLookup.has(key)) {
217
- const status = strict ? "fail" : "warn";
218
- issues.push({
219
- kind: "extra_index",
220
- table: collName,
221
- indexOrConstraint: formatIndexName(idx),
222
- message: `Extra index ${formatIndexName(idx)} on collection "${collName}"`
223
- });
224
- nodes.push({
225
- status,
226
- kind: "index",
227
- name: formatIndexName(idx),
228
- contractPath: `storage.namespaces.${UNBOUND_NAMESPACE_ID}.collections.${collName}.indexes`,
229
- code: "EXTRA_INDEX",
230
- message: `Extra index ${formatIndexName(idx)}`,
231
- expected: null,
232
- actual: key,
233
- children: []
234
- });
235
- }
261
+ else emitMongoIssueAndNodeUnderControlPolicy(collectionControlPolicy, {
262
+ kind: "index_mismatch",
263
+ table: collName,
264
+ indexOrConstraint: formatIndexName(idx),
265
+ message: `Index ${formatIndexName(idx)} missing on collection "${collName}"`
266
+ }, {
267
+ status: "fail",
268
+ kind: "index",
269
+ name: formatIndexName(idx),
270
+ contractPath: `storage.namespaces.${UNBOUND_NAMESPACE_ID}.collections.${collName}.indexes`,
271
+ code: "MISSING_INDEX",
272
+ message: `Index ${formatIndexName(idx)} missing`,
273
+ expected: key,
274
+ actual: null,
275
+ children: []
276
+ }, issues, nodes);
277
+ for (const [key, idx] of liveLookup) if (!expectedLookup.has(key)) emitMongoIssueAndNodeUnderControlPolicy(collectionControlPolicy, {
278
+ kind: "extra_index",
279
+ table: collName,
280
+ indexOrConstraint: formatIndexName(idx),
281
+ message: `Extra index ${formatIndexName(idx)} on collection "${collName}"`
282
+ }, {
283
+ status: strict ? "fail" : "warn",
284
+ kind: "index",
285
+ name: formatIndexName(idx),
286
+ contractPath: `storage.namespaces.${UNBOUND_NAMESPACE_ID}.collections.${collName}.indexes`,
287
+ code: "EXTRA_INDEX",
288
+ message: `Extra index ${formatIndexName(idx)}`,
289
+ expected: null,
290
+ actual: key,
291
+ children: []
292
+ }, issues, nodes);
236
293
  return nodes;
237
294
  }
238
- function diffValidator(collName, live, expected, strict, issues) {
295
+ function diffValidator(collName, live, expected, strict, collectionControlPolicy, issues) {
239
296
  if (!live.validator && !expected.validator) return [];
240
297
  if (expected.validator && !live.validator) {
241
- issues.push({
298
+ const issue = {
242
299
  kind: "type_missing",
243
300
  table: collName,
244
301
  message: `Validator missing on collection "${collName}"`
245
- });
246
- return [{
302
+ };
303
+ const nodes = [];
304
+ emitMongoIssueAndNodeUnderControlPolicy(collectionControlPolicy, issue, {
247
305
  status: "fail",
248
306
  kind: "validator",
249
307
  name: "validator",
@@ -253,17 +311,18 @@ function diffValidator(collName, live, expected, strict, issues) {
253
311
  expected: canonicalize(expected.validator.jsonSchema),
254
312
  actual: null,
255
313
  children: []
256
- }];
314
+ }, issues, nodes);
315
+ return nodes;
257
316
  }
258
317
  if (!expected.validator && live.validator) {
259
- const status = strict ? "fail" : "warn";
260
- issues.push({
318
+ const issue = {
261
319
  kind: "extra_validator",
262
320
  table: collName,
263
321
  message: `Extra validator on collection "${collName}"`
264
- });
265
- return [{
266
- status,
322
+ };
323
+ const nodes = [];
324
+ emitMongoIssueAndNodeUnderControlPolicy(collectionControlPolicy, issue, {
325
+ status: strict ? "fail" : "warn",
267
326
  kind: "validator",
268
327
  name: "validator",
269
328
  contractPath: `storage.namespaces.${UNBOUND_NAMESPACE_ID}.collections.${collName}.validator`,
@@ -272,21 +331,23 @@ function diffValidator(collName, live, expected, strict, issues) {
272
331
  expected: null,
273
332
  actual: canonicalize(live.validator.jsonSchema),
274
333
  children: []
275
- }];
334
+ }, issues, nodes);
335
+ return nodes;
276
336
  }
277
337
  const liveVal = live.validator;
278
338
  const expectedVal = expected.validator;
279
339
  const liveSchema = canonicalize(liveVal.jsonSchema);
280
340
  const expectedSchema = canonicalize(expectedVal.jsonSchema);
281
341
  if (liveSchema !== expectedSchema || liveVal.validationLevel !== expectedVal.validationLevel || liveVal.validationAction !== expectedVal.validationAction) {
282
- issues.push({
342
+ const issue = {
283
343
  kind: "type_mismatch",
284
344
  table: collName,
285
345
  expected: expectedSchema,
286
346
  actual: liveSchema,
287
347
  message: `Validator mismatch on collection "${collName}"`
288
- });
289
- return [{
348
+ };
349
+ const nodes = [];
350
+ emitMongoIssueAndNodeUnderControlPolicy(collectionControlPolicy, issue, {
290
351
  status: "fail",
291
352
  kind: "validator",
292
353
  name: "validator",
@@ -304,7 +365,8 @@ function diffValidator(collName, live, expected, strict, issues) {
304
365
  validationAction: liveVal.validationAction
305
366
  },
306
367
  children: []
307
- }];
368
+ }, issues, nodes);
369
+ return nodes;
308
370
  }
309
371
  return [{
310
372
  status: "pass",
@@ -318,18 +380,18 @@ function diffValidator(collName, live, expected, strict, issues) {
318
380
  children: []
319
381
  }];
320
382
  }
321
- function diffOptions(collName, live, expected, strict, issues) {
383
+ function diffOptions(collName, live, expected, strict, collectionControlPolicy, issues) {
322
384
  if (!live.options && !expected.options) return [];
323
385
  if (!expected.options && live.options) {
324
- const status = strict ? "fail" : "warn";
325
- issues.push({
386
+ const issue = {
326
387
  kind: "type_mismatch",
327
388
  table: collName,
328
389
  actual: canonicalize(live.options),
329
390
  message: `Extra collection options on "${collName}"`
330
- });
331
- return [{
332
- status,
391
+ };
392
+ const nodes = [];
393
+ emitMongoIssueAndNodeUnderControlPolicy(collectionControlPolicy, issue, {
394
+ status: strict ? "fail" : "warn",
333
395
  kind: "options",
334
396
  name: "options",
335
397
  contractPath: `storage.namespaces.${UNBOUND_NAMESPACE_ID}.collections.${collName}.options`,
@@ -338,7 +400,8 @@ function diffOptions(collName, live, expected, strict, issues) {
338
400
  expected: null,
339
401
  actual: live.options,
340
402
  children: []
341
- }];
403
+ }, issues, nodes);
404
+ return nodes;
342
405
  }
343
406
  if (deepEqual(live.options, expected.options)) return [{
344
407
  status: "pass",
@@ -351,14 +414,15 @@ function diffOptions(collName, live, expected, strict, issues) {
351
414
  actual: canonicalize(live.options),
352
415
  children: []
353
416
  }];
354
- issues.push({
417
+ const issue = {
355
418
  kind: "type_mismatch",
356
419
  table: collName,
357
420
  expected: canonicalize(expected.options),
358
421
  actual: canonicalize(live.options),
359
422
  message: `Collection options mismatch on "${collName}"`
360
- });
361
- return [{
423
+ };
424
+ const nodes = [];
425
+ emitMongoIssueAndNodeUnderControlPolicy(collectionControlPolicy, issue, {
362
426
  status: "fail",
363
427
  kind: "options",
364
428
  name: "options",
@@ -368,7 +432,8 @@ function diffOptions(collName, live, expected, strict, issues) {
368
432
  expected: expected.options,
369
433
  actual: live.options,
370
434
  children: []
371
- }];
435
+ }, issues, nodes);
436
+ return nodes;
372
437
  }
373
438
  //#endregion
374
439
  //#region src/core/schema-verify/canonicalize-introspection.ts
@@ -564,7 +629,7 @@ function verifyMongoSchema(options) {
564
629
  const { contract, schema, strict, context } = options;
565
630
  const startTime = Date.now();
566
631
  const { live: canonicalLive, expected: canonicalExpected } = canonicalizeSchemasForVerification(schema, contractToMongoSchemaIR(contract));
567
- const { root, issues, counts } = diffMongoSchemas(canonicalLive, canonicalExpected, strict);
632
+ const { root, issues, counts } = diffMongoSchemas(canonicalLive, canonicalExpected, strict, resolveMongoCollectionControlPolicy(contract));
568
633
  const ok = counts.fail === 0;
569
634
  const profileHash = typeof contract.profileHash === "string" ? contract.profileHash : "";
570
635
  return {
@@ -589,7 +654,12 @@ function verifyMongoSchema(options) {
589
654
  timings: { total: Date.now() - startTime }
590
655
  };
591
656
  }
657
+ function resolveMongoCollectionControlPolicy(contract) {
658
+ const collections = contract.storage.namespaces[UNBOUND_NAMESPACE_ID]?.collections ?? {};
659
+ const defaultControl = contract.defaultControl;
660
+ return (collectionName) => effectiveControlPolicy(collections[collectionName]?.control, defaultControl);
661
+ }
592
662
  //#endregion
593
663
  export { contractToMongoSchemaIR as i, canonicalizeSchemasForVerification as n, diffMongoSchemas as r, verifyMongoSchema as t };
594
664
 
595
- //# sourceMappingURL=verify-mongo-schema-Bhxvdah3.mjs.map
665
+ //# sourceMappingURL=verify-mongo-schema-BXJqoE59.mjs.map