@prisma-next/family-sql 0.14.0-dev.44 → 0.14.0-dev.45

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 +1 @@
1
- {"version":3,"file":"control.mjs","names":[],"sources":["../src/core/operation-preview.ts","../src/core/control-instance.ts","../src/core/control-descriptor.ts","../src/core/migrations/control-policy.ts","../src/core/migrations/field-event-planner.ts","../src/core/migrations/plan-helpers.ts","../src/core/migrations/policies.ts","../src/exports/control.ts"],"sourcesContent":["import type {\n MigrationPlanOperation,\n OperationPreview,\n} from '@prisma-next/framework-components/control';\n\n/**\n * Shape of an SQL execute step on `SqlMigrationPlanOperation`. Used for runtime\n * type narrowing without importing the concrete SQL type.\n */\ninterface SqlExecuteStep {\n readonly sql: string;\n}\n\nfunction isDdlStatement(sqlStatement: string): boolean {\n const trimmed = sqlStatement.trim().toLowerCase();\n return (\n trimmed.startsWith('create ') || trimmed.startsWith('alter ') || trimmed.startsWith('drop ')\n );\n}\n\nfunction hasExecuteSteps(\n operation: MigrationPlanOperation,\n): operation is MigrationPlanOperation & { readonly execute: readonly SqlExecuteStep[] } {\n const candidate = operation as unknown as Record<string, unknown>;\n if (!('execute' in candidate) || !Array.isArray(candidate['execute'])) {\n return false;\n }\n return candidate['execute'].every(\n (step: unknown) => typeof step === 'object' && step !== null && 'sql' in step,\n );\n}\n\n/**\n * Extracts a best-effort SQL DDL preview for CLI plan output.\n * Presentation-only: never used to decide migration correctness.\n */\nexport function extractSqlDdl(operations: readonly MigrationPlanOperation[]): string[] {\n const statements: string[] = [];\n for (const operation of operations) {\n if (!hasExecuteSteps(operation)) {\n continue;\n }\n for (const step of operation.execute) {\n if (typeof step.sql === 'string' && isDdlStatement(step.sql)) {\n statements.push(step.sql.trim());\n }\n }\n }\n return statements;\n}\n\n/**\n * Wraps `extractSqlDdl` into the family-agnostic `OperationPreview` shape.\n * Each statement carries `language: 'sql'`.\n */\nexport function sqlOperationsToPreview(\n operations: readonly MigrationPlanOperation[],\n): OperationPreview {\n return {\n statements: extractSqlDdl(operations).map((text) => ({ text, language: 'sql' })),\n };\n}\n","import type {\n Contract,\n ContractMarkerRecord,\n ControlPolicy,\n LedgerEntryRecord,\n} from '@prisma-next/contract/types';\nimport { effectiveControlPolicy } from '@prisma-next/contract/types';\nimport type {\n TargetBoundComponentDescriptor,\n TargetDescriptor,\n} from '@prisma-next/framework-components/components';\nimport type {\n ControlFamilyInstance,\n ControlStack,\n CoreSchemaView,\n MigrationPlanOperation,\n OperationPreview,\n OperationPreviewCapable,\n PslContractInferCapable,\n SchemaDiffIssue,\n SchemaViewCapable,\n SignDatabaseResult,\n VerifyDatabaseResult,\n VerifyDatabaseSchemaResult,\n} from '@prisma-next/framework-components/control';\nimport {\n APP_SPACE_ID,\n dispositionForCategory,\n SchemaTreeNode,\n VERIFY_CODE_HASH_MISMATCH,\n VERIFY_CODE_MARKER_MISSING,\n VERIFY_CODE_TARGET_MISMATCH,\n} from '@prisma-next/framework-components/control';\nimport type { TypesImportSpec } from '@prisma-next/framework-components/emission';\nimport { isPlainRecord } from '@prisma-next/framework-components/ir';\nimport type { PslDocumentAst } from '@prisma-next/framework-components/psl-ast';\nimport { assertDescriptorSelfConsistency } from '@prisma-next/migration-tools/spaces';\nimport { sqlContractCanonicalizationHooks } from '@prisma-next/sql-contract/canonicalization-hooks';\nimport type { SqlControlDriverInstance, SqlStorage } from '@prisma-next/sql-contract/types';\nimport type {\n AnyQueryAst,\n DdlNode,\n LowererContext,\n SqlExecuteRequest,\n} from '@prisma-next/sql-relational-core/ast';\nimport { defaultIndexName } from '@prisma-next/sql-schema-ir/naming';\nimport type { SqlSchemaIRNode, SqlTableIR } from '@prisma-next/sql-schema-ir/types';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { SqlControlAdapter } from './control-adapter';\nimport { SqlContractSerializer } from './ir/sql-contract-serializer';\nimport type { DiffDatabaseSchemaInput } from './migrations/schema-differ';\nimport type {\n SqlControlAdapterDescriptor,\n SqlControlExtensionDescriptor,\n} from './migrations/types';\nimport { sqlOperationsToPreview } from './operation-preview';\nimport { collectSupportedCodecTypeIds } from './verify';\n\nfunction extractCodecTypeIdsFromContract(contract: unknown): readonly string[] {\n const typeIds = new Set<string>();\n\n // Type guard for SQL contract structure\n if (\n typeof contract === 'object' &&\n contract !== null &&\n 'storage' in contract &&\n typeof contract.storage === 'object' &&\n contract.storage !== null &&\n 'namespaces' in contract.storage &&\n typeof contract.storage.namespaces === 'object' &&\n contract.storage.namespaces !== null\n ) {\n const namespaces = contract.storage.namespaces as Record<\n string,\n { readonly entries: Readonly<Record<string, Readonly<Record<string, unknown>>>> }\n >;\n for (const ns of Object.values(namespaces)) {\n const tbls = ns.entries['table'];\n if (typeof tbls !== 'object' || tbls === null) continue;\n for (const table of Object.values(tbls)) {\n if (\n typeof table === 'object' &&\n table !== null &&\n 'columns' in table &&\n typeof table.columns === 'object' &&\n table.columns !== null\n ) {\n const columns = table.columns as Record<string, { codecId: string } | undefined>;\n for (const column of Object.values(columns)) {\n if (\n column &&\n typeof column === 'object' &&\n 'codecId' in column &&\n typeof column.codecId === 'string'\n ) {\n typeIds.add(column.codecId);\n }\n }\n }\n }\n }\n }\n\n return Array.from(typeIds).sort();\n}\n\nfunction createVerifyResult(options: {\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 missingCodecs?: readonly string[];\n codecCoverageSkipped?: boolean;\n configPath?: string;\n contractPath: string;\n totalTime: number;\n}): VerifyDatabaseResult {\n const contract: { storageHash: string; profileHash?: string } = {\n storageHash: options.contractStorageHash,\n };\n if (options.contractProfileHash) {\n contract.profileHash = options.contractProfileHash;\n }\n\n const target: { expected: string; actual?: string } = {\n expected: options.expectedTargetId,\n };\n if (options.actualTargetId) {\n target.actual = options.actualTargetId;\n }\n\n const meta: { contractPath: string; configPath?: string } = {\n contractPath: options.contractPath,\n };\n if (options.configPath) {\n meta.configPath = options.configPath;\n }\n\n const result: VerifyDatabaseResult = {\n ok: options.ok,\n summary: options.summary,\n contract,\n target,\n meta,\n timings: {\n total: options.totalTime,\n },\n };\n\n if (options.code) {\n (result as { code?: string }).code = options.code;\n }\n\n if (options.marker) {\n (result as { marker?: { storageHash: string; profileHash: string } }).marker = {\n storageHash: options.marker.storageHash,\n profileHash: options.marker.profileHash,\n };\n }\n\n if (options.missingCodecs) {\n (result as { missingCodecs?: readonly string[] }).missingCodecs = options.missingCodecs;\n }\n\n if (options.codecCoverageSkipped) {\n (result as { codecCoverageSkipped?: boolean }).codecCoverageSkipped =\n options.codecCoverageSkipped;\n }\n\n return result;\n}\n\ninterface SqlTypeMetadata {\n readonly typeId: string;\n readonly familyId: 'sql';\n readonly targetId: string;\n readonly nativeType?: string;\n}\n\ntype SqlTypeMetadataRegistry = Map<string, SqlTypeMetadata>;\n\ninterface SqlFamilyInstanceState {\n readonly codecTypeImports: ReadonlyArray<TypesImportSpec>;\n readonly extensionIds: ReadonlyArray<string>;\n readonly typeMetadataRegistry: SqlTypeMetadataRegistry;\n}\n\nexport interface SqlControlFamilyInstance\n extends ControlFamilyInstance<'sql', SqlSchemaIRNode>,\n SchemaViewCapable<SqlSchemaIRNode>,\n PslContractInferCapable<SqlSchemaIRNode>,\n OperationPreviewCapable,\n SqlFamilyInstanceState {\n /**\n * The family seam-of-record for on-disk contract reads. Structurally\n * validates the JSON envelope, then hydrates IR-class instances via\n * the per-target ContractSerializer. The single named entry point\n * every CLI on-disk read crosses (TML-2536) — `as Contract` casts\n * in production package sources are a serializer-bypass smell guarded\n * by `pnpm lint:no-contract-cast`.\n */\n deserializeContract(contractJson: unknown): Contract;\n\n verify(options: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly contract: unknown;\n readonly expectedTargetId: string;\n readonly contractPath: string;\n readonly configPath?: string;\n }): Promise<VerifyDatabaseResult>;\n\n /**\n * Verify a contract against an already-introspected schema.\n *\n * Callers that need to verify against the live database compose\n * `introspect({ driver })` + `verifySchema({ contract, schema, ... })`.\n * The aggregate verifier hands in the full introspected schema and scopes\n * the returned result to each member's contract space afterwards — so\n * sibling-space tables never survive as `extras`.\n */\n verifySchema(options: {\n readonly contract: unknown;\n readonly schema: SqlSchemaIRNode;\n readonly strict: boolean;\n readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;\n }): VerifyDatabaseSchemaResult;\n\n sign(options: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly contract: unknown;\n readonly contractPath: string;\n readonly configPath?: string;\n }): Promise<SignDatabaseResult>;\n\n introspect(options: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly contract?: unknown;\n }): Promise<SqlSchemaIRNode>;\n\n inferPslContract(schemaIR: SqlSchemaIRNode): PslDocumentAst;\n\n lowerAst(\n ast: AnyQueryAst | DdlNode,\n context: LowererContext<unknown>,\n ): Promise<SqlExecuteRequest>;\n\n /**\n * Inserts the initial marker row for `space` (upsert on `space`).\n * Delegates to the target control adapter's write SPI; see\n * `SqlControlAdapter.initMarker`.\n */\n initMarker(options: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly space: string;\n readonly destination: {\n readonly storageHash: string;\n readonly profileHash: string;\n readonly invariants?: readonly string[];\n };\n }): Promise<void>;\n\n /**\n * Compare-and-swap advance of the marker row for `space`. Returns `true`\n * when the swap matched a row; see `SqlControlAdapter.updateMarker`.\n */\n updateMarker(options: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly space: string;\n readonly expectedFrom: string;\n readonly destination: {\n readonly storageHash: string;\n readonly profileHash: string;\n readonly invariants?: readonly string[];\n };\n }): Promise<boolean>;\n\n /**\n * Appends a ledger entry for `space`; see\n * `SqlControlAdapter.writeLedgerEntry`.\n */\n writeLedgerEntry(options: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly space: string;\n readonly entry: {\n readonly edgeId: string;\n readonly from: string;\n readonly to: string;\n readonly migrationName: string;\n readonly migrationHash: string;\n readonly operations: readonly unknown[];\n };\n }): Promise<void>;\n\n bootstrapControlTableQueries(): readonly DdlNode[];\n\n toOperationPreview(operations: readonly MigrationPlanOperation[]): OperationPreview;\n}\n\nexport type SqlFamilyInstance = SqlControlFamilyInstance;\n\ninterface DescriptorWithStorageTypes {\n readonly targetId?: string | undefined;\n readonly types?:\n | {\n readonly storage?:\n | ReadonlyArray<{\n readonly typeId: string;\n readonly familyId: string;\n readonly targetId: string;\n readonly nativeType?: string | undefined;\n }>\n | undefined;\n }\n | undefined;\n}\n\nfunction buildSqlTypeMetadataRegistry(options: {\n readonly target: DescriptorWithStorageTypes;\n readonly adapter: DescriptorWithStorageTypes & { readonly targetId: string };\n readonly extensionPacks: readonly DescriptorWithStorageTypes[];\n}): SqlTypeMetadataRegistry {\n const { target, adapter, extensionPacks: extensions } = options;\n const registry = new Map<string, SqlTypeMetadata>();\n const targetId = adapter.targetId;\n const descriptors = [target, adapter, ...extensions];\n\n for (const descriptor of descriptors) {\n const types = descriptor.types;\n const storageTypes = types?.storage;\n\n if (!storageTypes) {\n continue;\n }\n\n for (const storageType of storageTypes) {\n if (storageType.familyId === 'sql' && storageType.targetId === targetId) {\n registry.set(storageType.typeId, {\n typeId: storageType.typeId,\n familyId: 'sql',\n targetId: storageType.targetId,\n ...(storageType.nativeType !== undefined ? { nativeType: storageType.nativeType } : {}),\n });\n }\n }\n }\n\n return registry;\n}\n\ninterface CrossSpaceFkView {\n readonly id: string;\n readonly contractSpace?: {\n readonly contractJson?: {\n readonly extensionPacks?: Readonly<Record<string, unknown>>;\n readonly storage?: {\n readonly namespaces?: Readonly<Record<string, unknown>>;\n };\n };\n };\n}\n\n/**\n * Builds a map from each extension id to the set of extension ids it\n * transitively depends on. Uses the same declared-dependency data that\n * `buildExtensionLoadOrder` in control-stack uses.\n */\nfunction buildTransitiveDependsOnMap(\n extensions: readonly CrossSpaceFkView[],\n): Map<string, Set<string>> {\n const directDeps = new Map<string, readonly string[]>();\n for (const ext of extensions) {\n const packs = ext.contractSpace?.contractJson?.extensionPacks;\n const deps = packs !== null && typeof packs === 'object' ? Object.keys(packs) : [];\n directDeps.set(ext.id, deps);\n }\n\n const result = new Map<string, Set<string>>();\n const resolve = (id: string, visiting: Set<string>): Set<string> => {\n const cached = result.get(id);\n if (cached !== undefined) return cached;\n const set = new Set<string>();\n result.set(id, set);\n for (const depId of directDeps.get(id) ?? []) {\n set.add(depId);\n if (!visiting.has(depId)) {\n visiting.add(depId);\n for (const transitive of resolve(depId, visiting)) {\n set.add(transitive);\n }\n visiting.delete(depId);\n }\n }\n return set;\n };\n\n for (const ext of extensions) {\n resolve(ext.id, new Set([ext.id]));\n }\n return result;\n}\n\n/**\n * Asserts that no cross-space FK in any extension points against the\n * dependency direction.\n *\n * A cross-space FK (target.spaceId present) from extension A pointing at\n * space B is a violation when B depends on A (directly or transitively),\n * because that means A is pointing \"upward\" against the dependency arrows\n * established by the extension load order.\n *\n * Throws with a diagnostic naming the violating extension (source), the\n * target space, and the direction violation.\n */\nfunction isObjectRecord(v: unknown): v is Record<string, unknown> {\n return typeof v === 'object' && v !== null;\n}\n\nexport function assertNoCrossSpaceFkReverseReferences(\n extensions: readonly CrossSpaceFkView[],\n): void {\n const dependsOnMap = buildTransitiveDependsOnMap(extensions);\n\n for (const ext of extensions) {\n const namespaces = ext.contractSpace?.contractJson?.storage?.namespaces;\n if (!isObjectRecord(namespaces)) continue;\n for (const ns of Object.values(namespaces)) {\n if (!isObjectRecord(ns)) continue;\n const entries = ns['entries'];\n if (!isObjectRecord(entries)) continue;\n for (const slot of Object.values(entries)) {\n if (!isObjectRecord(slot)) continue;\n for (const table of Object.values(slot)) {\n if (!isObjectRecord(table)) continue;\n const foreignKeys = table['foreignKeys'];\n if (!Array.isArray(foreignKeys)) continue;\n for (const fk of foreignKeys) {\n if (!isObjectRecord(fk)) continue;\n const target = fk['target'];\n if (!isObjectRecord(target)) continue;\n if (target['spaceId'] === undefined) continue;\n const targetSpaceId = target['spaceId'];\n if (typeof targetSpaceId !== 'string') continue;\n // Check if targetSpaceId depends on ext.id (directly or transitively)\n const targetDeps = dependsOnMap.get(targetSpaceId);\n if (targetDeps?.has(ext.id)) {\n throw new Error(\n `Cross-space FK reverse-reference detected: extension \"${ext.id}\" has a cross-space FK targeting space \"${targetSpaceId}\", but \"${targetSpaceId}\" depends on \"${ext.id}\". Cross-space FKs must follow the dependency direction (a space can only reference spaces it depends on, not spaces that depend on it).`,\n );\n }\n }\n }\n }\n }\n }\n}\n\nexport function createSqlFamilyInstance<TTargetId extends string>(\n stack: ControlStack<'sql', TTargetId>,\n): SqlFamilyInstance {\n if (!stack.adapter) {\n throw new Error('SQL family requires an adapter descriptor in ControlStack');\n }\n\n const target = stack.target as unknown as TargetDescriptor<'sql', TTargetId> &\n DescriptorWithStorageTypes;\n const adapter = stack.adapter as unknown as SqlControlAdapterDescriptor<TTargetId> &\n DescriptorWithStorageTypes;\n const extensions =\n stack.extensionPacks as unknown as readonly (SqlControlExtensionDescriptor<TTargetId> &\n DescriptorWithStorageTypes)[];\n\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.\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 ...sqlContractCanonicalizationHooks,\n });\n }\n }\n\n assertNoCrossSpaceFkReverseReferences(extensions);\n\n const { codecTypeImports, extensionIds } = stack;\n\n const typeMetadataRegistry = buildSqlTypeMetadataRegistry({\n target,\n adapter,\n extensionPacks: extensions,\n });\n\n // Lazily construct the control adapter on first use, then memoize it.\n // Merely building a family instance must not instantiate the adapter —\n // that would change the load/instantiate semantics of the whole stack\n // wherever a family is created (every CLI command, emit, verify, …), not\n // just the migration paths that actually need it. Memoizing also avoids\n // the previous per-operation re-instantiation (a fresh adapter on every\n // call). Family-instance methods accept `SqlControlDriverInstance<string>`\n // (the family API isn't generic on the target id); the adapter\n // descriptor's `create` returns the concrete `SqlControlAdapter<TTargetId>`,\n // widened to `string` to match the family-level driver type without a\n // per-method probe.\n let controlAdapter: SqlControlAdapter<string> | undefined;\n const getControlAdapter = (): SqlControlAdapter<string> =>\n (controlAdapter ??= adapter.create(stack));\n\n const targetSerializer = (\n target as unknown as {\n contractSerializer?: {\n deserializeContract(json: unknown): Contract<SqlStorage>;\n serializeContract(contract: Contract<SqlStorage>): unknown;\n };\n }\n ).contractSerializer;\n // Database→PSL inference is target logic (it owns the dialect type/default\n // maps and walks its own schema tree), so it is read off the descriptor like\n // `contractSerializer`. Absent for targets without `contract infer` (Mongo).\n const targetInferPslContract = blindCast<\n { readonly inferPslContract?: (schema: SqlSchemaIRNode) => PslDocumentAst },\n 'reading the optional target-descriptor inferPslContract hook'\n >(target).inferPslContract;\n // The combined database-schema verify is a required target-descriptor\n // operation: every SQL target provides it, wrapping the same comparison\n // `diffDatabaseSchema` runs in the verify envelope plus the pass/warn/fail\n // tree the CLI renders. Read it off the descriptor like the other\n // target-owned hooks.\n const verifyDatabaseSchema = blindCast<\n {\n readonly verifyDatabaseSchema?: (\n input: DiffDatabaseSchemaInput,\n ) => VerifyDatabaseSchemaResult;\n },\n 'reading the required target-descriptor verifyDatabaseSchema hook'\n >(target).verifyDatabaseSchema;\n if (!verifyDatabaseSchema) {\n throw new Error(\n `SQL target \"${target.targetId}\" is missing the required verifyDatabaseSchema descriptor operation`,\n );\n }\n const deserializeWithTargetSerializer = (contractOrJson: unknown): Contract<SqlStorage> => {\n const serializer = targetSerializer ?? new SqlContractSerializer();\n const json =\n targetSerializer !== undefined && !isPlainRecord(contractOrJson)\n ? targetSerializer.serializeContract(\n blindCast<\n Contract<SqlStorage>,\n 'isPlainRecord returned false, so contractOrJson is a class instance, not raw JSON'\n >(contractOrJson),\n )\n : contractOrJson;\n return serializer.deserializeContract(json) as Contract<SqlStorage>;\n };\n\n return {\n familyId: 'sql',\n codecTypeImports,\n extensionIds,\n typeMetadataRegistry,\n\n deserializeContract(contractJson: unknown): Contract {\n return deserializeWithTargetSerializer(contractJson);\n },\n\n async verify(verifyOptions: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly contract: unknown;\n readonly expectedTargetId: string;\n readonly contractPath: string;\n readonly configPath?: string;\n }): Promise<VerifyDatabaseResult> {\n const {\n driver,\n contract: rawContract,\n expectedTargetId,\n contractPath,\n configPath,\n } = verifyOptions;\n const startTime = Date.now();\n\n const contract = deserializeWithTargetSerializer(rawContract) as Contract<SqlStorage>;\n\n const contractStorageHash = contract.storage.storageHash;\n const contractProfileHash = contract.profileHash;\n const contractTarget = contract.target;\n\n const marker = await getControlAdapter().readMarker(driver, APP_SPACE_ID);\n\n let missingCodecs: readonly string[] | undefined;\n let codecCoverageSkipped = false;\n const supportedTypeIds = collectSupportedCodecTypeIds([adapter, target, ...extensions]);\n if (supportedTypeIds.length === 0) {\n codecCoverageSkipped = true;\n } else {\n const supportedSet = new Set(supportedTypeIds);\n const usedTypeIds = extractCodecTypeIdsFromContract(contract);\n const missing = usedTypeIds.filter((id) => !supportedSet.has(id));\n if (missing.length > 0) {\n missingCodecs = missing;\n }\n }\n\n if (!marker) {\n const totalTime = Date.now() - startTime;\n return createVerifyResult({\n ok: false,\n code: VERIFY_CODE_MARKER_MISSING,\n summary: 'Marker missing',\n contractStorageHash,\n expectedTargetId,\n contractPath,\n totalTime,\n ...(contractProfileHash ? { contractProfileHash } : {}),\n ...(missingCodecs ? { missingCodecs } : {}),\n ...(codecCoverageSkipped ? { codecCoverageSkipped } : {}),\n ...(configPath ? { configPath } : {}),\n });\n }\n\n if (contractTarget !== expectedTargetId) {\n const totalTime = Date.now() - startTime;\n return createVerifyResult({\n ok: false,\n code: VERIFY_CODE_TARGET_MISMATCH,\n summary: 'Target mismatch',\n contractStorageHash,\n marker,\n expectedTargetId,\n actualTargetId: contractTarget,\n contractPath,\n totalTime,\n ...(contractProfileHash ? { contractProfileHash } : {}),\n ...(missingCodecs ? { missingCodecs } : {}),\n ...(codecCoverageSkipped ? { codecCoverageSkipped } : {}),\n ...(configPath ? { configPath } : {}),\n });\n }\n\n if (marker.storageHash !== contractStorageHash) {\n const totalTime = Date.now() - startTime;\n return createVerifyResult({\n ok: false,\n code: VERIFY_CODE_HASH_MISMATCH,\n summary: 'Hash mismatch',\n contractStorageHash,\n marker,\n expectedTargetId,\n contractPath,\n totalTime,\n ...(contractProfileHash ? { contractProfileHash } : {}),\n ...(missingCodecs ? { missingCodecs } : {}),\n ...(codecCoverageSkipped ? { codecCoverageSkipped } : {}),\n ...(configPath ? { configPath } : {}),\n });\n }\n\n if (contractProfileHash && marker.profileHash !== contractProfileHash) {\n const totalTime = Date.now() - startTime;\n return createVerifyResult({\n ok: false,\n code: VERIFY_CODE_HASH_MISMATCH,\n summary: 'Hash mismatch',\n contractStorageHash,\n contractProfileHash,\n marker,\n expectedTargetId,\n contractPath,\n totalTime,\n ...(missingCodecs ? { missingCodecs } : {}),\n ...(codecCoverageSkipped ? { codecCoverageSkipped } : {}),\n ...(configPath ? { configPath } : {}),\n });\n }\n\n const totalTime = Date.now() - startTime;\n return createVerifyResult({\n ok: true,\n summary: 'Database matches contract',\n contractStorageHash,\n marker,\n expectedTargetId,\n contractPath,\n totalTime,\n ...(contractProfileHash ? { contractProfileHash } : {}),\n ...(missingCodecs ? { missingCodecs } : {}),\n ...(codecCoverageSkipped ? { codecCoverageSkipped } : {}),\n ...(configPath ? { configPath } : {}),\n });\n },\n\n verifySchema(options: {\n readonly contract: unknown;\n readonly schema: SqlSchemaIRNode;\n readonly strict: boolean;\n readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;\n }): VerifyDatabaseSchemaResult {\n const contract = deserializeWithTargetSerializer(options.contract) as Contract<SqlStorage>;\n // Verify is a thin consumer of the target's black-box comparison: it\n // introspects the actual schema (already in `options.schema`), calls the\n // target's required `verifyDatabaseSchema`, and rejects when a surviving\n // issue is a failure. It composes no diffing itself and is blind to how\n // the comparison works.\n const sqlResult = verifyDatabaseSchema({\n contract,\n schema: options.schema,\n strict: options.strict,\n typeMetadataRegistry,\n frameworkComponents: options.frameworkComponents,\n });\n // Control-policy suppression of the structural (e.g. RLS policy) diff\n // issues is a verify-side post-step — the combined diff returns them\n // ownership-filtered, and a suppressed control policy drops them here.\n const schemaDiffIssues = filterSchemaDiffIssues(\n sqlResult.schema.schemaDiffIssues,\n contract.defaultControlPolicy,\n );\n const relationalFails = sqlResult.schema.counts.fail;\n if (schemaDiffIssues.length === 0) {\n if (schemaDiffIssues === sqlResult.schema.schemaDiffIssues) return sqlResult;\n return { ...sqlResult, schema: { ...sqlResult.schema, schemaDiffIssues } };\n }\n const totalFails = relationalFails + schemaDiffIssues.length;\n return {\n ...sqlResult,\n ok: false,\n code: sqlResult.code ?? 'PN-RUN-3010',\n summary: `Database schema does not satisfy contract (${totalFails} failure${totalFails === 1 ? '' : 's'})`,\n schema: {\n ...sqlResult.schema,\n schemaDiffIssues,\n counts: { ...sqlResult.schema.counts, fail: totalFails },\n },\n };\n },\n async sign(options: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly contract: unknown;\n readonly contractPath: string;\n readonly configPath?: string;\n }): Promise<SignDatabaseResult> {\n const { driver, contract: contractInput, contractPath, configPath } = options;\n const startTime = Date.now();\n\n const contract = deserializeWithTargetSerializer(contractInput) as Contract<SqlStorage>;\n\n const contractStorageHash = contract.storage.storageHash;\n const contractProfileHash =\n 'profileHash' in contract && typeof contract.profileHash === 'string'\n ? contract.profileHash\n : contractStorageHash;\n const contractTarget = contract.target;\n\n const controlAdapter = getControlAdapter();\n const lowererContext = { contract };\n for (const query of controlAdapter.bootstrapSignMarkerQueries()) {\n const lowered = await controlAdapter.lowerToExecuteRequest(query, lowererContext);\n await driver.query(lowered.sql, lowered.params);\n }\n\n const existingMarker = await controlAdapter.readMarker(driver, 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.insertMarker(driver, APP_SPACE_ID, {\n storageHash: contractStorageHash,\n profileHash: contractProfileHash,\n });\n markerCreated = true;\n } else {\n const existingStorageHash = existingMarker.storageHash;\n const existingProfileHash = existingMarker.profileHash;\n\n const storageHashMatches = existingStorageHash === contractStorageHash;\n const profileHashMatches = existingProfileHash === contractProfileHash;\n\n if (!storageHashMatches || !profileHashMatches) {\n previousHashes = {\n storageHash: existingStorageHash,\n profileHash: existingProfileHash,\n };\n const updated = await controlAdapter.updateMarker(\n driver,\n APP_SPACE_ID,\n existingStorageHash,\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 const totalTime = Date.now() - startTime;\n\n return {\n ok: true,\n summary,\n contract: {\n storageHash: contractStorageHash,\n profileHash: contractProfileHash,\n },\n target: {\n expected: contractTarget,\n actual: contractTarget,\n },\n marker: {\n created: markerCreated,\n updated: markerUpdated,\n ...(previousHashes ? { previous: previousHashes } : {}),\n },\n meta: {\n contractPath,\n ...(configPath ? { configPath } : {}),\n },\n timings: {\n total: totalTime,\n },\n };\n },\n async readMarker(options: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly space: string;\n }): Promise<ContractMarkerRecord | null> {\n return getControlAdapter().readMarker(options.driver, options.space);\n },\n async readAllMarkers(options: {\n readonly driver: SqlControlDriverInstance<string>;\n }): Promise<ReadonlyMap<string, ContractMarkerRecord>> {\n return getControlAdapter().readAllMarkers(options.driver);\n },\n async readLedger(options: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly space?: string;\n }): Promise<readonly LedgerEntryRecord[]> {\n return getControlAdapter().readLedger(options.driver, options.space);\n },\n async initMarker(options: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly space: string;\n readonly destination: {\n readonly storageHash: string;\n readonly profileHash: string;\n readonly invariants?: readonly string[];\n };\n }): Promise<void> {\n return getControlAdapter().initMarker(options.driver, options.space, options.destination);\n },\n async updateMarker(options: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly space: string;\n readonly expectedFrom: string;\n readonly destination: {\n readonly storageHash: string;\n readonly profileHash: string;\n readonly invariants?: readonly string[];\n };\n }): Promise<boolean> {\n return getControlAdapter().updateMarker(\n options.driver,\n options.space,\n options.expectedFrom,\n options.destination,\n );\n },\n async writeLedgerEntry(options: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly space: string;\n readonly entry: {\n readonly edgeId: string;\n readonly from: string;\n readonly to: string;\n readonly migrationName: string;\n readonly migrationHash: string;\n readonly operations: readonly unknown[];\n };\n }): Promise<void> {\n return getControlAdapter().writeLedgerEntry(options.driver, options.space, options.entry);\n },\n async introspect(options: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly contract?: unknown;\n }): Promise<SqlSchemaIRNode> {\n return getControlAdapter().introspect(options.driver, options.contract);\n },\n\n inferPslContract(schemaIR: SqlSchemaIRNode): PslDocumentAst {\n if (!targetInferPslContract) {\n throw new Error(\n `Target \"${target.targetId}\" does not support contract infer (no inferPslContract on its descriptor).`,\n );\n }\n return targetInferPslContract(schemaIR);\n },\n\n lowerAst(\n ast: AnyQueryAst | DdlNode,\n context: LowererContext<unknown>,\n ): Promise<SqlExecuteRequest> {\n return getControlAdapter().lowerToExecuteRequest(ast, context);\n },\n\n bootstrapControlTableQueries(): readonly DdlNode[] {\n return getControlAdapter().bootstrapControlTableQueries();\n },\n\n toOperationPreview(operations: readonly MigrationPlanOperation[]): OperationPreview {\n return sqlOperationsToPreview(operations);\n },\n\n toSchemaView(schema: SqlSchemaIRNode): CoreSchemaView {\n // Walk the schema-IR tree's own structure (root → namespaces → tables)\n // into one flat list of table nodes. A root that exposes a `namespaces`\n // record (Postgres) contributes each namespace's tables; a flat root\n // (SQLite) is its own single namespace. The single-schema common case\n // renders the same table-level view as today — no synthetic namespace\n // level.\n const root = blindCast<\n {\n readonly namespaces?: Readonly<\n Record<string, { readonly tables: Record<string, SqlTableIR> }>\n >;\n readonly tables?: Record<string, SqlTableIR>;\n },\n 'structural read of the schema-IR tree own namespaces/tables records'\n >(schema);\n // A multi-namespace root qualifies every table's display name with its\n // namespace key, so same-named tables in different namespaces (e.g.\n // public.thing and auth.thing) render distinct ids and labels. The\n // single-namespace case (and a flat SQLite root) keeps today's bare\n // names. Synthesized constraint/index fallback names keep the bare table\n // name — that is the name the database derives them from.\n const namespaceEntries: ReadonlyArray<[string | undefined, Record<string, SqlTableIR>]> =\n root.namespaces !== undefined\n ? Object.entries(root.namespaces).map(\n ([namespaceKey, namespace]): [string, Record<string, SqlTableIR>] => [\n namespaceKey,\n namespace.tables,\n ],\n )\n : [[undefined, root.tables ?? {}]];\n const qualify = namespaceEntries.length > 1;\n const tableEntries: ReadonlyArray<[string, string, SqlTableIR]> = namespaceEntries.flatMap(\n ([namespaceKey, tables]) =>\n Object.entries(tables).map(([tableName, table]): [string, string, SqlTableIR] => [\n qualify && namespaceKey !== undefined ? `${namespaceKey}.${tableName}` : tableName,\n tableName,\n table,\n ]),\n );\n const tableNodes: readonly SchemaTreeNode[] = tableEntries.map(\n ([displayName, tableName, table]: [string, string, SqlTableIR]) => {\n const children: SchemaTreeNode[] = [];\n\n const columnNodes: SchemaTreeNode[] = [];\n for (const [columnName, column] of Object.entries(table.columns)) {\n const typeDisplay = column.nativeType;\n const nullability = column.nullable ? 'nullable' : 'not nullable';\n const label = `${columnName}: ${typeDisplay} (${nullability})`;\n columnNodes.push(\n new SchemaTreeNode({\n kind: 'field',\n id: `column-${displayName}-${columnName}`,\n label,\n meta: {\n nativeType: column.nativeType,\n nullable: column.nullable,\n ...ifDefined('default', column.default),\n },\n }),\n );\n }\n\n if (columnNodes.length > 0) {\n children.push(\n new SchemaTreeNode({\n kind: 'collection',\n id: `columns-${displayName}`,\n label: 'columns',\n children: columnNodes,\n }),\n );\n }\n\n if (table.primaryKey) {\n const pkColumns = table.primaryKey.columns.join(', ');\n children.push(\n new SchemaTreeNode({\n kind: 'index',\n id: `primary-key-${displayName}`,\n label: `primary key: ${pkColumns}`,\n meta: {\n columns: table.primaryKey.columns,\n ...(table.primaryKey.name ? { name: table.primaryKey.name } : {}),\n },\n }),\n );\n }\n\n for (const unique of table.uniques) {\n const name = unique.name ?? `${tableName}_${unique.columns.join('_')}_unique`;\n const label = `unique ${name}`;\n children.push(\n new SchemaTreeNode({\n kind: 'index',\n id: `unique-${displayName}-${name}`,\n label,\n meta: {\n columns: unique.columns,\n unique: true,\n },\n }),\n );\n }\n\n for (const index of table.indexes) {\n const name = index.name ?? defaultIndexName(tableName, index.columns);\n const label = index.unique ? `unique index ${name}` : `index ${name}`;\n children.push(\n new SchemaTreeNode({\n kind: 'index',\n id: `index-${displayName}-${name}`,\n label,\n meta: {\n columns: index.columns,\n unique: index.unique,\n },\n }),\n );\n }\n\n const tableMeta: Record<string, unknown> = {};\n if (table.primaryKey) {\n tableMeta['primaryKey'] = table.primaryKey.columns;\n if (table.primaryKey.name) {\n tableMeta['primaryKeyName'] = table.primaryKey.name;\n }\n }\n if (table.foreignKeys.length > 0) {\n tableMeta['foreignKeys'] = table.foreignKeys.map((fk) => ({\n columns: fk.columns,\n referencedTable: fk.referencedTable,\n referencedColumns: fk.referencedColumns,\n ...(fk.name ? { name: fk.name } : {}),\n }));\n }\n\n return new SchemaTreeNode({\n kind: 'entity',\n id: `table-${displayName}`,\n label: `table ${displayName}`,\n ...(Object.keys(tableMeta).length > 0 ? { meta: tableMeta } : {}),\n ...(children.length > 0 ? { children } : {}),\n });\n },\n );\n\n return {\n root: new SchemaTreeNode({\n kind: 'root',\n id: 'sql-schema',\n label: 'database',\n ...(tableNodes.length > 0 ? { children: tableNodes } : {}),\n }),\n };\n },\n };\n}\n\n/**\n * Filters the structural schema-diff issues (from `diffDatabaseSchema`) through\n * the contract's `defaultControlPolicy`. Issues whose outcome maps to a suppressed\n * category under the effective policy are removed. This mirrors the control-policy\n * filtering applied by `verifySqlSchema` for table/column-level findings.\n *\n * Outcome → category mapping:\n * - `'extra'` → `'extraAuxiliary'` (an extra auxiliary entity, e.g. an RLS policy)\n * - `'missing'` → `'declaredMissing'`\n * - `'mismatch'` → `'declaredIncompatible'`\n */\nexport function filterSchemaDiffIssues(\n issues: readonly SchemaDiffIssue[],\n defaultControlPolicy: ControlPolicy | undefined,\n): readonly SchemaDiffIssue[] {\n if (issues.length === 0) return issues;\n const policy = effectiveControlPolicy(undefined, defaultControlPolicy);\n return issues.filter((issue) => {\n const category =\n issue.outcome === 'extra'\n ? ('extraAuxiliary' as const)\n : issue.outcome === 'missing'\n ? ('declaredMissing' as const)\n : ('declaredIncompatible' as const);\n return dispositionForCategory(policy, category) !== 'suppress';\n });\n}\n","import type {\n ControlFamilyDescriptor,\n ControlStack,\n} from '@prisma-next/framework-components/control';\nimport type { EmissionSpi } from '@prisma-next/framework-components/emission';\nimport { sqlEmission } from '@prisma-next/sql-contract-emitter';\nimport { sqlFamilyEntityTypes, sqlFamilyPslBlockDescriptors } from './authoring-entity-types';\nimport { sqlFamilyAuthoringFieldPresets } from './authoring-field-presets';\nimport { sqlFamilyAuthoringTypes } from './authoring-type-constructors';\nimport { createSqlFamilyInstance, type SqlControlFamilyInstance } from './control-instance';\n\nexport class SqlFamilyDescriptor\n implements ControlFamilyDescriptor<'sql', SqlControlFamilyInstance>\n{\n readonly kind = 'family' as const;\n readonly id = 'sql';\n readonly familyId = 'sql' as const;\n readonly version = '0.0.1';\n readonly emission: EmissionSpi = sqlEmission;\n readonly authoring = {\n field: sqlFamilyAuthoringFieldPresets,\n type: sqlFamilyAuthoringTypes,\n entityTypes: sqlFamilyEntityTypes,\n pslBlockDescriptors: sqlFamilyPslBlockDescriptors,\n } as const;\n\n create<TTargetId extends string>(\n stack: ControlStack<'sql', TTargetId>,\n ): SqlControlFamilyInstance {\n return createSqlFamilyInstance(stack);\n }\n}\n","import {\n type Contract,\n type ControlPolicy,\n effectiveControlPolicy,\n} from '@prisma-next/contract/types';\nimport type { SqlStorage } from '@prisma-next/sql-contract/types';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { SqlPlannerConflict } from './types';\n\n/**\n * The target object a control policy governs for a single planner call,\n * resolved from the target's own IR. `undefined` means the call's target\n * object could not be positively established — a fail-closed signal: any\n * policy stricter than `managed` drops such a call rather than emitting it.\n */\nexport interface ControlPolicySubject {\n readonly namespaceId: string;\n readonly explicitNodeControlPolicy?: ControlPolicy;\n readonly table?: string;\n readonly column?: string;\n readonly typeName?: string;\n /**\n * Whether the call creates a whole, previously-absent top-level storage\n * object (e.g. a table or an enum/type), as opposed to modifying an\n * existing object. This is the only thing `tolerated` permits: it is a\n * create-if-absent policy, so an op that touches an existing object — add\n * column, add index/constraint, alter, drop — is never allowed under it.\n */\n readonly createsNewObject: boolean;\n}\n\n/**\n * The control policy that governs a single call. The `external` default is an\n * un-overridable namespace floor: when the contract default is `external`, no\n * per-object `managed` override can escalate DDL above the floor, so the\n * policy is forced to `external` regardless of the node's own declaration.\n * Every other default defers to the node's effective control policy.\n */\nexport function controlPolicyForCall(\n subject: ControlPolicySubject | undefined,\n defaultControlPolicy: ControlPolicy | undefined,\n): ControlPolicy {\n if (defaultControlPolicy === 'external') {\n return 'external';\n }\n return effectiveControlPolicy(subject?.explicitNodeControlPolicy, defaultControlPolicy);\n}\n\n/**\n * Whether a call is allowed to emit under a given control policy.\n *\n * - `managed` — full lifecycle, every op allowed.\n * - `tolerated` — create-if-absent only: allowed iff the call creates a whole\n * new top-level object (and its subject was positively resolved). Anything\n * that modifies an existing object, and anything whose subject could not be\n * resolved, is suppressed.\n * - `external` / `observed` — no DDL at all.\n */\nfunction callAllowedUnderControlPolicy(\n policy: ControlPolicy,\n subject: ControlPolicySubject | undefined,\n): boolean {\n switch (policy) {\n case 'managed':\n return true;\n case 'tolerated':\n return subject?.createsNewObject === true;\n case 'external':\n case 'observed':\n return false;\n }\n}\n\nfunction defaultSubjectLabel(\n factoryName: string,\n subject: ControlPolicySubject | undefined,\n): string {\n if (subject?.table) {\n return `${factoryName}(${subject.table})`;\n }\n if (subject?.typeName) {\n return `${factoryName}(${subject.typeName})`;\n }\n return factoryName;\n}\n\nfunction suppressionSummary(\n subjectLabel: string,\n subject: ControlPolicySubject | undefined,\n effectivePolicy: ControlPolicy,\n): string {\n const namespace = subject?.namespaceId ?? 'unknown';\n const declared = subject?.explicitNodeControlPolicy;\n if (effectivePolicy === 'external' && declared === 'managed') {\n return `control policy suppressed: ${subjectLabel} — namespace '${namespace}' has effective control 'external' but table declared 'managed'`;\n }\n const declaredSuffix = declared ? ` but table declared '${declared}'` : '';\n return `control policy suppressed: ${subjectLabel} — namespace '${namespace}' has effective control '${effectivePolicy}'${declaredSuffix}`;\n}\n\nfunction buildSubjectSuppressionWarning(\n subject: ControlPolicySubject | undefined,\n effectivePolicy: ControlPolicy,\n factoryName: string,\n formatSubjectLabel: (factoryName: string, subject: ControlPolicySubject | undefined) => string,\n): SqlPlannerConflict {\n const subjectLabel = formatSubjectLabel(factoryName, subject);\n return {\n kind: 'controlPolicySuppressedCall',\n summary: suppressionSummary(subjectLabel, subject, effectivePolicy),\n location: {\n ...ifDefined('namespace', subject?.namespaceId),\n ...ifDefined('table', subject?.table),\n ...ifDefined('column', subject?.column),\n ...ifDefined('type', subject?.typeName),\n },\n meta: {\n controlPolicy: effectivePolicy,\n factoryName,\n ...ifDefined('declaredControlPolicy', subject?.explicitNodeControlPolicy),\n },\n };\n}\n\nfunction defaultModificationFactoryNameForSubject(subject: ControlPolicySubject): string {\n if (subject.table) return 'alterTable';\n if (subject.typeName) return 'alterType';\n return 'alterSchema';\n}\n\n/**\n * Partition the calls produced for a single set of subjects into those the\n * effective control policy permits (`kept`) and a list of\n * {@link SqlPlannerConflict} warnings describing the suppressed calls.\n *\n * **Prefer {@link partitionIssuesByControlPolicy}** for the schema-issue\n * pipeline: it filters subjects out of the planner's *input* so the planner\n * never has to reason about un-modeled state on `external`/`observed`\n * subjects. This call-level helper remains for paths that bypass the issue\n * pipeline — currently the codec-emitted field-event ops, which originate\n * from declared contract fields rather than from introspected schema state\n * and therefore cannot trip the diff engine.\n */\nexport function partitionCallsByControlPolicy<TCall>(options: {\n readonly calls: readonly TCall[];\n readonly contract: Contract<SqlStorage>;\n readonly resolveControlPolicySubject: (call: TCall) => ControlPolicySubject | undefined;\n readonly resolveFactoryName: (call: TCall) => string;\n readonly formatSubjectLabel?: (\n factoryName: string,\n subject: ControlPolicySubject | undefined,\n ) => string;\n}): {\n readonly kept: readonly TCall[];\n readonly warnings: readonly SqlPlannerConflict[];\n} {\n const defaultControlPolicy = options.contract.defaultControlPolicy;\n const formatSubjectLabel = options.formatSubjectLabel ?? defaultSubjectLabel;\n const kept: TCall[] = [];\n const warnings: SqlPlannerConflict[] = [];\n\n for (const call of options.calls) {\n const subject = options.resolveControlPolicySubject(call);\n const policy = controlPolicyForCall(subject, defaultControlPolicy);\n if (callAllowedUnderControlPolicy(policy, subject)) {\n kept.push(call);\n } else {\n const factoryName = options.resolveFactoryName(call);\n warnings.push(\n buildSubjectSuppressionWarning(subject, policy, factoryName, formatSubjectLabel),\n );\n }\n }\n\n return Object.freeze({\n kept: Object.freeze(kept),\n warnings: Object.freeze(warnings),\n });\n}\n\n/**\n * Partition a list of schema-issue-shaped inputs by the effective control\n * policy of each issue's subject *before* the planner is invoked.\n *\n * `plannable` is the list of issues whose subject's effective policy permits\n * the planner to act on them (`managed`, or `tolerated` for whole-object\n * creation issues only). Issues for `external`/`observed` subjects, and\n * non-creation issues for `tolerated` subjects, are dropped from the planner's\n * input entirely — they never enter introspection-driven planning, never feed\n * the diff engine, and never produce DDL calls that would have to be\n * post-filtered. This sidesteps a class of failure where the diff engine\n * cannot reason about the live shape of a subject the user marked as\n * out-of-scope (`external`).\n *\n * `warnings` is one {@link SqlPlannerConflict} per suppressed subject (not per\n * suppressed issue). `factoryName` is inferred from the subject's issue mix:\n * if any of the subject's issues is whole-object creation, the warning takes\n * the corresponding creation factoryName (e.g. `createTable`,\n * `createEnumType`, `createSchema`); otherwise it falls back to\n * `defaultModificationFactoryName(subject)` — a synthetic label that names\n * the *kind* of mutation that would have run, since no concrete DDL call was\n * generated.\n *\n * Unresolved-subject issues (`resolveControlPolicySubject` returns\n * `undefined`) emit one warning each; they cannot be deduplicated because\n * they carry no subject coordinate.\n */\nexport function partitionIssuesByControlPolicy<TIssue>(options: {\n readonly issues: readonly TIssue[];\n readonly contract: Contract<SqlStorage>;\n /**\n * Resolve the subject targeted by this issue (or `undefined` to fail-closed:\n * any policy stricter than `managed` drops the issue).\n */\n readonly resolveControlPolicySubject: (issue: TIssue) => ControlPolicySubject | undefined;\n /**\n * Resolve a creation factoryName for this issue if it represents the\n * absence of the whole top-level object (e.g. `'createTable'` for a\n * missing-table issue). When the issue describes a modification to an\n * existing object, return `undefined`. Both decisions feed off this signal:\n *\n * 1. Under `tolerated`, only issues whose `resolveCreationFactoryName`\n * returns a value flow into the planner (create-if-absent).\n * 2. Subjects that have at least one creation-flavoured issue use the\n * resolved creation factoryName for their suppression warning;\n * otherwise they fall back to `defaultModificationFactoryName`.\n */\n readonly resolveCreationFactoryName: (issue: TIssue) => string | undefined;\n /**\n * Default modification factoryName for a suppressed subject whose issues\n * are all non-creation (the subject exists but has a different shape).\n * Defaults to `'alterTable'` / `'alterType'` / `'alterSchema'` based on the\n * subject's populated coordinates.\n */\n readonly defaultModificationFactoryName?: (subject: ControlPolicySubject) => string;\n readonly formatSubjectLabel?: (\n factoryName: string,\n subject: ControlPolicySubject | undefined,\n ) => string;\n}): {\n readonly plannable: readonly TIssue[];\n readonly warnings: readonly SqlPlannerConflict[];\n} {\n const defaultControlPolicy = options.contract.defaultControlPolicy;\n const formatSubjectLabel = options.formatSubjectLabel ?? defaultSubjectLabel;\n const inferModificationFactoryName =\n options.defaultModificationFactoryName ?? defaultModificationFactoryNameForSubject;\n\n const plannable: TIssue[] = [];\n // Resolved-subject suppressions are deduplicated by subject key so we emit\n // one warning per suppressed subject, not one per suppressed issue.\n // `creationFactoryName` upgrades from `undefined` to a concrete creation\n // name the first time we see a creation-flavoured issue for the subject.\n const suppressedSubjects = new Map<\n string,\n {\n readonly subject: ControlPolicySubject;\n readonly policy: ControlPolicy;\n creationFactoryName?: string;\n }\n >();\n const unresolvedSuppressions: SqlPlannerConflict[] = [];\n\n for (const issue of options.issues) {\n const subject = options.resolveControlPolicySubject(issue);\n const policy = controlPolicyForCall(subject, defaultControlPolicy);\n const creationFactoryName = options.resolveCreationFactoryName(issue);\n\n if (policy === 'managed') {\n plannable.push(issue);\n continue;\n }\n if (\n policy === 'tolerated' &&\n subject !== undefined &&\n creationFactoryName !== undefined &&\n subject.createsNewObject\n ) {\n plannable.push(issue);\n continue;\n }\n\n if (subject === undefined) {\n const factoryName = creationFactoryName ?? 'unknown';\n unresolvedSuppressions.push(\n buildSubjectSuppressionWarning(undefined, policy, factoryName, formatSubjectLabel),\n );\n continue;\n }\n\n const key = subjectKey(subject);\n const existing = suppressedSubjects.get(key);\n if (existing) {\n if (existing.creationFactoryName === undefined && creationFactoryName !== undefined) {\n existing.creationFactoryName = creationFactoryName;\n }\n } else {\n suppressedSubjects.set(key, {\n subject,\n policy,\n ...ifDefined('creationFactoryName', creationFactoryName),\n });\n }\n }\n\n const warnings: SqlPlannerConflict[] = [...unresolvedSuppressions];\n for (const entry of suppressedSubjects.values()) {\n const factoryName = entry.creationFactoryName ?? inferModificationFactoryName(entry.subject);\n warnings.push(\n buildSubjectSuppressionWarning(entry.subject, entry.policy, factoryName, formatSubjectLabel),\n );\n }\n\n return Object.freeze({\n plannable: Object.freeze(plannable),\n warnings: Object.freeze(warnings),\n });\n}\n\nfunction subjectKey(subject: ControlPolicySubject): string {\n return `${subject.namespaceId}\\u0000${subject.table ?? ''}\\u0000${subject.typeName ?? ''}`;\n}\n","/**\n * Codec lifecycle hook planner — runs `onFieldEvent` for every per-field\n * delta between two contracts and concatenates the returned ops in a\n * deterministic order.\n *\n * Wired by each target's planner (`PostgresMigrationPlanner`,\n * `SqliteMigrationPlanner`) so codec-emitted ops are inlined alongside\n * structural DDL in the app-space migration's `ops.json`. Pure, target-\n * agnostic, and only ever invoked at the app-space emitter; extension-space\n * planning never reaches this helper.\n *\n * Ordering rules (see ADR 213):\n *\n * - Events are grouped by phase: `'added'` → `'dropped'` → `'altered'`.\n * - Within each phase, entries are sorted alphabetically by\n * `(namespaceId, tableName, fieldName)`.\n * - The hook's returned ops are appended in the order the hook returned them.\n *\n * `'altered'` is suppressed when only `codecId` differs (codec rotation is a\n * v1 non-goal).\n *\n * See: `docs/architecture docs/adrs/ADR 213 - Codec lifecycle hooks.md`.\n */\n\nimport type { Contract } from '@prisma-next/contract/types';\nimport type { OpFactoryCall } from '@prisma-next/framework-components/control';\nimport { type SqlStorage, type StorageColumn, StorageTable } from '@prisma-next/sql-contract/types';\nimport type { CodecControlHooks, FieldEvent, FieldEventContext } from './types';\n\nexport interface PlanFieldEventOperationsOptions {\n /**\n * Prior contract the planner is diffing against. `null` for first emits\n * (every field is treated as added).\n */\n readonly priorContract: Contract<SqlStorage> | null;\n /**\n * New contract the user just authored.\n */\n readonly newContract: Contract<SqlStorage>;\n /**\n * Codec-id keyed map of control hooks, as produced by\n * {@link import('./assembly').extractCodecControlHooks}. Hooks carry\n * `unknown` target details after extraction; the caller casts the\n * helper's returned ops to its target's `SqlMigrationPlanOperation`\n * specialisation at the integration boundary, mirroring how\n * `storageTypePlanCallStrategy` lifts `planTypeOperations` results into\n * `RawSqlCall`.\n */\n readonly codecHooks: ReadonlyMap<string, CodecControlHooks>;\n}\n\ninterface FieldEntry {\n readonly namespaceId: string;\n readonly tableName: string;\n readonly fieldName: string;\n readonly priorTable: StorageTable | undefined;\n readonly newTable: StorageTable | undefined;\n readonly priorField: StorageColumn | undefined;\n readonly newField: StorageColumn | undefined;\n}\n\nexport function planFieldEventOperations(\n options: PlanFieldEventOperationsOptions,\n): readonly OpFactoryCall[] {\n const priorContract = options.priorContract;\n const newContract = options.newContract;\n\n const added: FieldEntry[] = [];\n const dropped: FieldEntry[] = [];\n const altered: FieldEntry[] = [];\n\n const namespaceIds = unionSorted(\n priorContract ? Object.keys(priorContract.storage.namespaces) : [],\n Object.keys(newContract.storage.namespaces),\n );\n\n for (const namespaceId of namespaceIds) {\n const priorNs = priorContract?.storage.namespaces[namespaceId];\n const newNs = newContract.storage.namespaces[namespaceId];\n const priorTables = priorNs?.entries.table;\n const newTables = newNs?.entries.table;\n\n const tableNames = unionSorted(\n priorTables ? Object.keys(priorTables) : [],\n newTables ? Object.keys(newTables) : [],\n );\n\n for (const tableName of tableNames) {\n const priorTableRaw = priorTables?.[tableName];\n const newTableRaw = newTables?.[tableName];\n const priorTable = StorageTable.is(priorTableRaw) ? priorTableRaw : undefined;\n const newTable = StorageTable.is(newTableRaw) ? newTableRaw : undefined;\n const fieldNames = unionSorted(\n priorTable ? Object.keys(priorTable.columns) : [],\n newTable ? Object.keys(newTable.columns) : [],\n );\n for (const fieldName of fieldNames) {\n const priorField = priorTable?.columns[fieldName];\n const newField = newTable?.columns[fieldName];\n const entry: FieldEntry = {\n namespaceId,\n tableName,\n fieldName,\n priorTable,\n newTable,\n priorField,\n newField,\n };\n if (priorField === undefined && newField !== undefined) {\n added.push(entry);\n } else if (priorField !== undefined && newField === undefined) {\n dropped.push(entry);\n } else if (priorField !== undefined && newField !== undefined) {\n if (isAlteration(priorField, newField)) altered.push(entry);\n }\n }\n }\n }\n\n const calls: OpFactoryCall[] = [];\n appendCalls('added', added, options.codecHooks, calls, (e) => e.newField?.codecId);\n appendCalls('dropped', dropped, options.codecHooks, calls, (e) => e.priorField?.codecId);\n appendCalls('altered', altered, options.codecHooks, calls, (e) => e.newField?.codecId);\n return calls;\n}\n\nfunction appendCalls(\n event: FieldEvent,\n entries: readonly FieldEntry[],\n codecHooks: ReadonlyMap<string, CodecControlHooks>,\n calls: OpFactoryCall[],\n pickCodecId: (entry: FieldEntry) => string | undefined,\n): void {\n for (const entry of entries) {\n const codecId = pickCodecId(entry);\n if (codecId === undefined) continue;\n const hook = codecHooks.get(codecId);\n if (!hook?.onFieldEvent) continue;\n const ctx = buildContext(event, entry);\n const emitted = hook.onFieldEvent(event, ctx);\n for (const call of emitted) calls.push(call);\n }\n}\n\n/**\n * The context's prior/new sides are scoped to the event:\n *\n * - `'added'` — only `newTable` / `newField` populated.\n * - `'dropped'` — only `priorTable` / `priorField` populated.\n * - `'altered'` — both sides populated.\n */\nfunction buildContext(event: FieldEvent, entry: FieldEntry): FieldEventContext {\n const base = {\n namespaceId: entry.namespaceId,\n tableName: entry.tableName,\n fieldName: entry.fieldName,\n };\n if (event === 'added') {\n return {\n ...base,\n ...(entry.newTable !== undefined ? { newTable: entry.newTable } : {}),\n ...(entry.newField !== undefined ? { newField: entry.newField } : {}),\n };\n }\n if (event === 'dropped') {\n return {\n ...base,\n ...(entry.priorTable !== undefined ? { priorTable: entry.priorTable } : {}),\n ...(entry.priorField !== undefined ? { priorField: entry.priorField } : {}),\n };\n }\n return {\n ...base,\n ...(entry.priorTable !== undefined ? { priorTable: entry.priorTable } : {}),\n ...(entry.newTable !== undefined ? { newTable: entry.newTable } : {}),\n ...(entry.priorField !== undefined ? { priorField: entry.priorField } : {}),\n ...(entry.newField !== undefined ? { newField: entry.newField } : {}),\n };\n}\n\n/**\n * `'altered'` predicate. Returns `false` whenever `codecId` differs —\n * any codec change suppresses the `altered` event entirely, including\n * cases where another property also differs in the same diff. Codec\n * rotation is a v1 non-goal; avoiding the mixed event keeps the\n * migration semantics for codec changes explicit rather than smuggling\n * them through as `altered`.\n *\n * For non-`codecId` diffs, returns `true` iff any other column property\n * differs.\n */\nfunction isAlteration(prior: StorageColumn, current: StorageColumn): boolean {\n if (prior.codecId !== current.codecId) return false;\n return !sameStorageColumn(prior, current);\n}\n\nfunction sameStorageColumn(a: StorageColumn, b: StorageColumn): boolean {\n if (a === b) return true;\n if (a.nativeType !== b.nativeType) return false;\n if (a.nullable !== b.nullable) return false;\n if (a.typeRef !== b.typeRef) return false;\n if (!sameJson(a.typeParams, b.typeParams)) return false;\n if (!sameJson(a.default, b.default)) return false;\n return true;\n}\n\nfunction sameJson(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a === undefined || b === undefined) return false;\n return JSON.stringify(a) === JSON.stringify(b);\n}\n\nfunction unionSorted(a: readonly string[], b: readonly string[]): readonly string[] {\n const set = new Set<string>();\n for (const name of a) set.add(name);\n for (const name of b) set.add(name);\n return [...set].sort((x, y) => (x < y ? -1 : x > y ? 1 : 0));\n}\n","import type { NotOk, Ok } from '@prisma-next/utils/result';\nimport { notOk, ok } from '@prisma-next/utils/result';\nimport type {\n AnyRecord,\n CreateSqlMigrationPlanOptions,\n SqlMigrationPlan,\n SqlMigrationPlanOperation,\n SqlMigrationPlanOperationStep,\n SqlMigrationPlanOperationTarget,\n SqlMigrationRunnerErrorCode,\n SqlMigrationRunnerFailure,\n SqlMigrationRunnerSuccessValue,\n SqlPlannerConflict,\n SqlPlannerFailureResult,\n SqlPlannerSuccessResult,\n} from './types';\n\nconst readOnlyEmptyObject: Record<string, never> = Object.freeze({});\n\nfunction cloneRecord<T extends AnyRecord>(value: T): T {\n if (value === readOnlyEmptyObject) {\n return value;\n }\n return Object.freeze({ ...value }) as T;\n}\n\nfunction freezeSteps(\n steps: readonly SqlMigrationPlanOperationStep[],\n): readonly SqlMigrationPlanOperationStep[] {\n if (steps.length === 0) {\n return Object.freeze([]);\n }\n return Object.freeze(\n steps.map((step) =>\n Object.freeze({\n description: step.description,\n sql: step.sql,\n ...(step.params ? { params: Object.freeze([...step.params]) } : {}),\n ...(step.meta ? { meta: cloneRecord(step.meta) } : {}),\n }),\n ),\n );\n}\n\nfunction freezeDetailsValue<T>(value: T): T {\n // Primitives and null/undefined are already immutable, return as-is\n if (value === null || value === undefined) {\n return value;\n }\n if (typeof value !== 'object') {\n return value;\n }\n // Arrays: shallow clone and freeze\n if (Array.isArray(value)) {\n return Object.freeze([...value]) as T;\n }\n // Objects: shallow clone and freeze (matching cloneRecord pattern)\n return Object.freeze({ ...value }) as T;\n}\n\nfunction freezeTargetDetails<TTargetDetails>(\n target: SqlMigrationPlanOperationTarget<TTargetDetails>,\n): SqlMigrationPlanOperationTarget<TTargetDetails> {\n return Object.freeze({\n id: target.id,\n ...(target.details !== undefined ? { details: freezeDetailsValue(target.details) } : {}),\n });\n}\n\nfunction freezeOperation<TTargetDetails>(\n operation: SqlMigrationPlanOperation<TTargetDetails>,\n): SqlMigrationPlanOperation<TTargetDetails> {\n return Object.freeze({\n id: operation.id,\n label: operation.label,\n ...(operation.summary ? { summary: operation.summary } : {}),\n operationClass: operation.operationClass,\n ...(operation.invariantId ? { invariantId: operation.invariantId } : {}),\n target: freezeTargetDetails(operation.target),\n precheck: freezeSteps(operation.precheck),\n execute: freezeSteps(operation.execute),\n postcheck: freezeSteps(operation.postcheck),\n ...(operation.meta ? { meta: cloneRecord(operation.meta) } : {}),\n });\n}\n\nfunction freezeOperations<TTargetDetails>(\n operations: readonly SqlMigrationPlanOperation<TTargetDetails>[],\n): readonly SqlMigrationPlanOperation<TTargetDetails>[] {\n if (operations.length === 0) {\n return Object.freeze([]);\n }\n return Object.freeze(operations.map((operation) => freezeOperation(operation)));\n}\n\nexport function createMigrationPlan<TTargetDetails>(\n options: CreateSqlMigrationPlanOptions<TTargetDetails>,\n): SqlMigrationPlan<TTargetDetails> {\n return Object.freeze({\n targetId: options.targetId,\n spaceId: options.spaceId,\n ...(options.origin !== undefined\n ? { origin: options.origin ? Object.freeze({ ...options.origin }) : null }\n : {}),\n destination: Object.freeze({ ...options.destination }),\n operations: freezeOperations(options.operations),\n providedInvariants: Object.freeze([...options.providedInvariants]),\n ...(options.meta ? { meta: cloneRecord(options.meta) } : {}),\n });\n}\n\nexport function plannerSuccess<TTargetDetails>(\n plan: SqlMigrationPlan<TTargetDetails>,\n warnings?: readonly SqlPlannerConflict[],\n): SqlPlannerSuccessResult<TTargetDetails> {\n return Object.freeze({\n kind: 'success',\n plan,\n ...(warnings && warnings.length > 0\n ? {\n warnings: Object.freeze(\n warnings.map((conflict) =>\n Object.freeze({\n kind: conflict.kind,\n summary: conflict.summary,\n ...(conflict.why ? { why: conflict.why } : {}),\n ...(conflict.location ? { location: Object.freeze({ ...conflict.location }) } : {}),\n ...(conflict.meta ? { meta: cloneRecord(conflict.meta) } : {}),\n }),\n ),\n ),\n }\n : {}),\n });\n}\n\nexport function plannerFailure(conflicts: readonly SqlPlannerConflict[]): SqlPlannerFailureResult {\n return Object.freeze({\n kind: 'failure' as const,\n conflicts: Object.freeze(\n conflicts.map((conflict) =>\n Object.freeze({\n kind: conflict.kind,\n summary: conflict.summary,\n ...(conflict.why ? { why: conflict.why } : {}),\n ...(conflict.location ? { location: Object.freeze({ ...conflict.location }) } : {}),\n ...(conflict.meta ? { meta: cloneRecord(conflict.meta) } : {}),\n }),\n ),\n ),\n });\n}\n\n/**\n * Creates a successful migration runner result.\n */\nexport function runnerSuccess(value: {\n operationsPlanned: number;\n operationsExecuted: number;\n}): Ok<SqlMigrationRunnerSuccessValue> {\n return ok(\n Object.freeze({\n operationsPlanned: value.operationsPlanned,\n operationsExecuted: value.operationsExecuted,\n }),\n );\n}\n\n/**\n * Creates a failed migration runner result.\n */\nexport function runnerFailure(\n code: SqlMigrationRunnerErrorCode,\n summary: string,\n options?: { why?: string; meta?: AnyRecord },\n): NotOk<SqlMigrationRunnerFailure> {\n const failure: SqlMigrationRunnerFailure = Object.freeze({\n code,\n summary,\n ...(options?.why ? { why: options.why } : {}),\n ...(options?.meta ? { meta: cloneRecord(options.meta) } : {}),\n });\n return notOk(failure);\n}\n","import type { MigrationOperationPolicy } from '@prisma-next/framework-components/control';\n\n/**\n * Policy used by `db init`: additive-only operations, no widening/destructive steps.\n */\nexport const INIT_ADDITIVE_POLICY: MigrationOperationPolicy = Object.freeze({\n allowedOperationClasses: Object.freeze(['additive'] as const),\n});\n","import { SqlFamilyDescriptor } from '../core/control-descriptor';\n\n// Re-export core types from canonical source\nexport type {\n MigrationOperationClass,\n MigrationOperationPolicy,\n MigrationPlan,\n MigrationPlanner,\n MigrationPlannerConflict,\n MigrationPlannerResult,\n MigrationPlanOperation,\n TargetMigrationsCapability,\n} from '@prisma-next/framework-components/control';\nexport { assembleAuthoringContributions } from '@prisma-next/framework-components/control';\nexport { extractCodecControlHooks } from '../core/assembly';\nexport type { SqlControlFamilyInstance } from '../core/control-instance';\nexport type {\n ContractToSchemaIROptions,\n DefaultRenderer,\n EnumNamespaceSchemaResolver,\n NativeTypeExpander,\n} from '../core/migrations/contract-to-schema-ir';\n// Contract → SchemaIR conversion for offline migration planning\nexport {\n contractNamespaceToSchemaIR,\n contractToSchemaIR,\n detectDestructiveChanges,\n resolveValueSetValues,\n} from '../core/migrations/contract-to-schema-ir';\nexport type { ControlPolicySubject } from '../core/migrations/control-policy';\nexport {\n controlPolicyForCall,\n partitionCallsByControlPolicy,\n partitionIssuesByControlPolicy,\n} from '../core/migrations/control-policy';\nexport type { PlanFieldEventOperationsOptions } from '../core/migrations/field-event-planner';\nexport { planFieldEventOperations } from '../core/migrations/field-event-planner';\nexport {\n createMigrationPlan,\n plannerFailure,\n plannerSuccess,\n runnerFailure,\n runnerSuccess,\n} from '../core/migrations/plan-helpers';\nexport { INIT_ADDITIVE_POLICY } from '../core/migrations/policies';\nexport type {\n CodecControlHooks,\n CreateSqlMigrationPlanOptions,\n ExpandNativeTypeInput,\n FieldEvent,\n FieldEventContext,\n ResolveIdentityValueInput,\n SqlControlAdapterDescriptor,\n SqlControlExtensionDescriptor,\n SqlControlTargetDescriptor,\n SqlMigrationPlan,\n SqlMigrationPlanContractInfo,\n SqlMigrationPlanner,\n SqlMigrationPlannerPlanOptions,\n SqlMigrationPlanOperation,\n SqlMigrationPlanOperationStep,\n SqlMigrationPlanOperationTarget,\n SqlMigrationRunner,\n SqlMigrationRunnerErrorCode,\n SqlMigrationRunnerExecuteCallbacks,\n SqlMigrationRunnerExecuteOptions,\n SqlMigrationRunnerFailure,\n SqlMigrationRunnerResult,\n SqlMigrationRunnerSuccessValue,\n SqlPlannerConflict,\n SqlPlannerConflictKind,\n SqlPlannerConflictLocation,\n SqlPlannerFailureResult,\n SqlPlannerResult,\n SqlPlannerSuccessResult,\n SqlPlanTargetDetails,\n StorageTypePlanResult,\n} from '../core/migrations/types';\nexport {\n temporalAuthoringPresets,\n timestampNowControlDescriptor,\n} from '../core/timestamp-now-generator';\n\nexport default new SqlFamilyDescriptor();\n"],"mappings":"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"}
1
+ {"version":3,"file":"control.mjs","names":[],"sources":["../src/core/operation-preview.ts","../src/core/control-instance.ts","../src/core/control-descriptor.ts","../src/core/migrations/control-policy.ts","../src/core/migrations/field-event-planner.ts","../src/core/migrations/plan-helpers.ts","../src/core/migrations/policies.ts","../src/exports/control.ts"],"sourcesContent":["import type {\n MigrationPlanOperation,\n OperationPreview,\n} from '@prisma-next/framework-components/control';\n\n/**\n * Shape of an SQL execute step on `SqlMigrationPlanOperation`. Used for runtime\n * type narrowing without importing the concrete SQL type.\n */\ninterface SqlExecuteStep {\n readonly sql: string;\n}\n\nfunction isDdlStatement(sqlStatement: string): boolean {\n const trimmed = sqlStatement.trim().toLowerCase();\n return (\n trimmed.startsWith('create ') || trimmed.startsWith('alter ') || trimmed.startsWith('drop ')\n );\n}\n\nfunction hasExecuteSteps(\n operation: MigrationPlanOperation,\n): operation is MigrationPlanOperation & { readonly execute: readonly SqlExecuteStep[] } {\n const candidate = operation as unknown as Record<string, unknown>;\n if (!('execute' in candidate) || !Array.isArray(candidate['execute'])) {\n return false;\n }\n return candidate['execute'].every(\n (step: unknown) => typeof step === 'object' && step !== null && 'sql' in step,\n );\n}\n\n/**\n * Extracts a best-effort SQL DDL preview for CLI plan output.\n * Presentation-only: never used to decide migration correctness.\n */\nexport function extractSqlDdl(operations: readonly MigrationPlanOperation[]): string[] {\n const statements: string[] = [];\n for (const operation of operations) {\n if (!hasExecuteSteps(operation)) {\n continue;\n }\n for (const step of operation.execute) {\n if (typeof step.sql === 'string' && isDdlStatement(step.sql)) {\n statements.push(step.sql.trim());\n }\n }\n }\n return statements;\n}\n\n/**\n * Wraps `extractSqlDdl` into the family-agnostic `OperationPreview` shape.\n * Each statement carries `language: 'sql'`.\n */\nexport function sqlOperationsToPreview(\n operations: readonly MigrationPlanOperation[],\n): OperationPreview {\n return {\n statements: extractSqlDdl(operations).map((text) => ({ text, language: 'sql' })),\n };\n}\n","import type {\n Contract,\n ContractMarkerRecord,\n ControlPolicy,\n LedgerEntryRecord,\n} from '@prisma-next/contract/types';\nimport { effectiveControlPolicy } from '@prisma-next/contract/types';\nimport type {\n TargetBoundComponentDescriptor,\n TargetDescriptor,\n} from '@prisma-next/framework-components/components';\nimport type {\n ControlFamilyInstance,\n ControlStack,\n CoreSchemaView,\n MigrationPlanOperation,\n OperationPreview,\n OperationPreviewCapable,\n PslContractInferCapable,\n SchemaDiffIssue,\n SchemaViewCapable,\n SignDatabaseResult,\n VerifyDatabaseResult,\n VerifyDatabaseSchemaResult,\n} from '@prisma-next/framework-components/control';\nimport {\n APP_SPACE_ID,\n dispositionForCategory,\n SchemaTreeNode,\n VERIFY_CODE_HASH_MISMATCH,\n VERIFY_CODE_MARKER_MISSING,\n VERIFY_CODE_TARGET_MISMATCH,\n} from '@prisma-next/framework-components/control';\nimport type { TypesImportSpec } from '@prisma-next/framework-components/emission';\nimport { isPlainRecord } from '@prisma-next/framework-components/ir';\nimport type { PslDocumentAst } from '@prisma-next/framework-components/psl-ast';\nimport { assertDescriptorSelfConsistency } from '@prisma-next/migration-tools/spaces';\nimport { sqlContractCanonicalizationHooks } from '@prisma-next/sql-contract/canonicalization-hooks';\nimport type { SqlControlDriverInstance, SqlStorage } from '@prisma-next/sql-contract/types';\nimport type {\n AnyQueryAst,\n DdlNode,\n LowererContext,\n SqlExecuteRequest,\n} from '@prisma-next/sql-relational-core/ast';\nimport { defaultIndexName } from '@prisma-next/sql-schema-ir/naming';\nimport type { SqlSchemaIRNode, SqlTableIR } from '@prisma-next/sql-schema-ir/types';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { SqlControlAdapter } from './control-adapter';\nimport type {\n SqlControlTargetDescriptor,\n SqlDescribedContractSpace,\n} from './control-target-descriptor';\nimport { SqlContractSerializer } from './ir/sql-contract-serializer';\nimport type { DiffDatabaseSchemaInput } from './migrations/schema-differ';\nimport type {\n SqlControlAdapterDescriptor,\n SqlControlExtensionDescriptor,\n} from './migrations/types';\nimport { sqlOperationsToPreview } from './operation-preview';\nimport { collectSupportedCodecTypeIds } from './verify';\n\nfunction extractCodecTypeIdsFromContract(contract: unknown): readonly string[] {\n const typeIds = new Set<string>();\n\n // Type guard for SQL contract structure\n if (\n typeof contract === 'object' &&\n contract !== null &&\n 'storage' in contract &&\n typeof contract.storage === 'object' &&\n contract.storage !== null &&\n 'namespaces' in contract.storage &&\n typeof contract.storage.namespaces === 'object' &&\n contract.storage.namespaces !== null\n ) {\n const namespaces = contract.storage.namespaces as Record<\n string,\n { readonly entries: Readonly<Record<string, Readonly<Record<string, unknown>>>> }\n >;\n for (const ns of Object.values(namespaces)) {\n const tbls = ns.entries['table'];\n if (typeof tbls !== 'object' || tbls === null) continue;\n for (const table of Object.values(tbls)) {\n if (\n typeof table === 'object' &&\n table !== null &&\n 'columns' in table &&\n typeof table.columns === 'object' &&\n table.columns !== null\n ) {\n const columns = table.columns as Record<string, { codecId: string } | undefined>;\n for (const column of Object.values(columns)) {\n if (\n column &&\n typeof column === 'object' &&\n 'codecId' in column &&\n typeof column.codecId === 'string'\n ) {\n typeIds.add(column.codecId);\n }\n }\n }\n }\n }\n }\n\n return Array.from(typeIds).sort();\n}\n\nfunction createVerifyResult(options: {\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 missingCodecs?: readonly string[];\n codecCoverageSkipped?: boolean;\n configPath?: string;\n contractPath: string;\n totalTime: number;\n}): VerifyDatabaseResult {\n const contract: { storageHash: string; profileHash?: string } = {\n storageHash: options.contractStorageHash,\n };\n if (options.contractProfileHash) {\n contract.profileHash = options.contractProfileHash;\n }\n\n const target: { expected: string; actual?: string } = {\n expected: options.expectedTargetId,\n };\n if (options.actualTargetId) {\n target.actual = options.actualTargetId;\n }\n\n const meta: { contractPath: string; configPath?: string } = {\n contractPath: options.contractPath,\n };\n if (options.configPath) {\n meta.configPath = options.configPath;\n }\n\n const result: VerifyDatabaseResult = {\n ok: options.ok,\n summary: options.summary,\n contract,\n target,\n meta,\n timings: {\n total: options.totalTime,\n },\n };\n\n if (options.code) {\n (result as { code?: string }).code = options.code;\n }\n\n if (options.marker) {\n (result as { marker?: { storageHash: string; profileHash: string } }).marker = {\n storageHash: options.marker.storageHash,\n profileHash: options.marker.profileHash,\n };\n }\n\n if (options.missingCodecs) {\n (result as { missingCodecs?: readonly string[] }).missingCodecs = options.missingCodecs;\n }\n\n if (options.codecCoverageSkipped) {\n (result as { codecCoverageSkipped?: boolean }).codecCoverageSkipped =\n options.codecCoverageSkipped;\n }\n\n return result;\n}\n\ninterface SqlTypeMetadata {\n readonly typeId: string;\n readonly familyId: 'sql';\n readonly targetId: string;\n readonly nativeType?: string;\n}\n\ntype SqlTypeMetadataRegistry = Map<string, SqlTypeMetadata>;\n\ninterface SqlFamilyInstanceState {\n readonly codecTypeImports: ReadonlyArray<TypesImportSpec>;\n readonly extensionIds: ReadonlyArray<string>;\n readonly typeMetadataRegistry: SqlTypeMetadataRegistry;\n}\n\nexport interface SqlControlFamilyInstance\n extends ControlFamilyInstance<'sql', SqlSchemaIRNode>,\n SchemaViewCapable<SqlSchemaIRNode>,\n PslContractInferCapable<SqlSchemaIRNode>,\n OperationPreviewCapable,\n SqlFamilyInstanceState {\n /**\n * The family seam-of-record for on-disk contract reads. Structurally\n * validates the JSON envelope, then hydrates IR-class instances via\n * the per-target ContractSerializer. The single named entry point\n * every CLI on-disk read crosses (TML-2536) — `as Contract` casts\n * in production package sources are a serializer-bypass smell guarded\n * by `pnpm lint:no-contract-cast`.\n */\n deserializeContract(contractJson: unknown): Contract;\n\n verify(options: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly contract: unknown;\n readonly expectedTargetId: string;\n readonly contractPath: string;\n readonly configPath?: string;\n }): Promise<VerifyDatabaseResult>;\n\n /**\n * Verify a contract against an already-introspected schema.\n *\n * Callers that need to verify against the live database compose\n * `introspect({ driver })` + `verifySchema({ contract, schema, ... })`.\n * The aggregate verifier hands in the full introspected schema and scopes\n * the returned result to each member's contract space afterwards — so\n * sibling-space tables never survive as `extras`.\n */\n verifySchema(options: {\n readonly contract: unknown;\n readonly schema: SqlSchemaIRNode;\n readonly strict: boolean;\n readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;\n }): VerifyDatabaseSchemaResult;\n\n sign(options: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly contract: unknown;\n readonly contractPath: string;\n readonly configPath?: string;\n }): Promise<SignDatabaseResult>;\n\n introspect(options: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly contract?: unknown;\n }): Promise<SqlSchemaIRNode>;\n\n inferPslContract(schemaIR: SqlSchemaIRNode): PslDocumentAst;\n\n lowerAst(\n ast: AnyQueryAst | DdlNode,\n context: LowererContext<unknown>,\n ): Promise<SqlExecuteRequest>;\n\n /**\n * Inserts the initial marker row for `space` (upsert on `space`).\n * Delegates to the target control adapter's write SPI; see\n * `SqlControlAdapter.initMarker`.\n */\n initMarker(options: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly space: string;\n readonly destination: {\n readonly storageHash: string;\n readonly profileHash: string;\n readonly invariants?: readonly string[];\n };\n }): Promise<void>;\n\n /**\n * Compare-and-swap advance of the marker row for `space`. Returns `true`\n * when the swap matched a row; see `SqlControlAdapter.updateMarker`.\n */\n updateMarker(options: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly space: string;\n readonly expectedFrom: string;\n readonly destination: {\n readonly storageHash: string;\n readonly profileHash: string;\n readonly invariants?: readonly string[];\n };\n }): Promise<boolean>;\n\n /**\n * Appends a ledger entry for `space`; see\n * `SqlControlAdapter.writeLedgerEntry`.\n */\n writeLedgerEntry(options: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly space: string;\n readonly entry: {\n readonly edgeId: string;\n readonly from: string;\n readonly to: string;\n readonly migrationName: string;\n readonly migrationHash: string;\n readonly operations: readonly unknown[];\n };\n }): Promise<void>;\n\n bootstrapControlTableQueries(): readonly DdlNode[];\n\n toOperationPreview(operations: readonly MigrationPlanOperation[]): OperationPreview;\n}\n\nexport type SqlFamilyInstance = SqlControlFamilyInstance;\n\ninterface DescriptorWithStorageTypes {\n readonly targetId?: string | undefined;\n readonly types?:\n | {\n readonly storage?:\n | ReadonlyArray<{\n readonly typeId: string;\n readonly familyId: string;\n readonly targetId: string;\n readonly nativeType?: string | undefined;\n }>\n | undefined;\n }\n | undefined;\n}\n\nfunction buildSqlTypeMetadataRegistry(options: {\n readonly target: DescriptorWithStorageTypes;\n readonly adapter: DescriptorWithStorageTypes & { readonly targetId: string };\n readonly extensionPacks: readonly DescriptorWithStorageTypes[];\n}): SqlTypeMetadataRegistry {\n const { target, adapter, extensionPacks: extensions } = options;\n const registry = new Map<string, SqlTypeMetadata>();\n const targetId = adapter.targetId;\n const descriptors = [target, adapter, ...extensions];\n\n for (const descriptor of descriptors) {\n const types = descriptor.types;\n const storageTypes = types?.storage;\n\n if (!storageTypes) {\n continue;\n }\n\n for (const storageType of storageTypes) {\n if (storageType.familyId === 'sql' && storageType.targetId === targetId) {\n registry.set(storageType.typeId, {\n typeId: storageType.typeId,\n familyId: 'sql',\n targetId: storageType.targetId,\n ...(storageType.nativeType !== undefined ? { nativeType: storageType.nativeType } : {}),\n });\n }\n }\n }\n\n return registry;\n}\n\ninterface CrossSpaceFkView {\n readonly id: string;\n readonly contractSpace?: {\n readonly contractJson?: {\n readonly extensionPacks?: Readonly<Record<string, unknown>>;\n readonly storage?: {\n readonly namespaces?: Readonly<Record<string, unknown>>;\n };\n };\n };\n}\n\n/**\n * Builds a map from each extension id to the set of extension ids it\n * transitively depends on. Uses the same declared-dependency data that\n * `buildExtensionLoadOrder` in control-stack uses.\n */\nfunction buildTransitiveDependsOnMap(\n extensions: readonly CrossSpaceFkView[],\n): Map<string, Set<string>> {\n const directDeps = new Map<string, readonly string[]>();\n for (const ext of extensions) {\n const packs = ext.contractSpace?.contractJson?.extensionPacks;\n const deps = packs !== null && typeof packs === 'object' ? Object.keys(packs) : [];\n directDeps.set(ext.id, deps);\n }\n\n const result = new Map<string, Set<string>>();\n const resolve = (id: string, visiting: Set<string>): Set<string> => {\n const cached = result.get(id);\n if (cached !== undefined) return cached;\n const set = new Set<string>();\n result.set(id, set);\n for (const depId of directDeps.get(id) ?? []) {\n set.add(depId);\n if (!visiting.has(depId)) {\n visiting.add(depId);\n for (const transitive of resolve(depId, visiting)) {\n set.add(transitive);\n }\n visiting.delete(depId);\n }\n }\n return set;\n };\n\n for (const ext of extensions) {\n resolve(ext.id, new Set([ext.id]));\n }\n return result;\n}\n\n/**\n * Asserts that no cross-space FK in any extension points against the\n * dependency direction.\n *\n * A cross-space FK (target.spaceId present) from extension A pointing at\n * space B is a violation when B depends on A (directly or transitively),\n * because that means A is pointing \"upward\" against the dependency arrows\n * established by the extension load order.\n *\n * Throws with a diagnostic naming the violating extension (source), the\n * target space, and the direction violation.\n */\nfunction isObjectRecord(v: unknown): v is Record<string, unknown> {\n return typeof v === 'object' && v !== null;\n}\n\nexport function assertNoCrossSpaceFkReverseReferences(\n extensions: readonly CrossSpaceFkView[],\n): void {\n const dependsOnMap = buildTransitiveDependsOnMap(extensions);\n\n for (const ext of extensions) {\n const namespaces = ext.contractSpace?.contractJson?.storage?.namespaces;\n if (!isObjectRecord(namespaces)) continue;\n for (const ns of Object.values(namespaces)) {\n if (!isObjectRecord(ns)) continue;\n const entries = ns['entries'];\n if (!isObjectRecord(entries)) continue;\n for (const slot of Object.values(entries)) {\n if (!isObjectRecord(slot)) continue;\n for (const table of Object.values(slot)) {\n if (!isObjectRecord(table)) continue;\n const foreignKeys = table['foreignKeys'];\n if (!Array.isArray(foreignKeys)) continue;\n for (const fk of foreignKeys) {\n if (!isObjectRecord(fk)) continue;\n const target = fk['target'];\n if (!isObjectRecord(target)) continue;\n if (target['spaceId'] === undefined) continue;\n const targetSpaceId = target['spaceId'];\n if (typeof targetSpaceId !== 'string') continue;\n // Check if targetSpaceId depends on ext.id (directly or transitively)\n const targetDeps = dependsOnMap.get(targetSpaceId);\n if (targetDeps?.has(ext.id)) {\n throw new Error(\n `Cross-space FK reverse-reference detected: extension \"${ext.id}\" has a cross-space FK targeting space \"${targetSpaceId}\", but \"${targetSpaceId}\" depends on \"${ext.id}\". Cross-space FKs must follow the dependency direction (a space can only reference spaces it depends on, not spaces that depend on it).`,\n );\n }\n }\n }\n }\n }\n }\n}\n\nexport function createSqlFamilyInstance<TTargetId extends string>(\n stack: ControlStack<'sql', TTargetId>,\n): SqlFamilyInstance {\n if (!stack.adapter) {\n throw new Error('SQL family requires an adapter descriptor in ControlStack');\n }\n\n const target = stack.target as unknown as TargetDescriptor<'sql', TTargetId> &\n DescriptorWithStorageTypes;\n const adapter = stack.adapter as unknown as SqlControlAdapterDescriptor<TTargetId> &\n DescriptorWithStorageTypes;\n const extensions =\n stack.extensionPacks as unknown as readonly (SqlControlExtensionDescriptor<TTargetId> &\n DescriptorWithStorageTypes)[];\n\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.\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 ...sqlContractCanonicalizationHooks,\n });\n }\n }\n\n assertNoCrossSpaceFkReverseReferences(extensions);\n\n const { codecTypeImports, extensionIds } = stack;\n\n const typeMetadataRegistry = buildSqlTypeMetadataRegistry({\n target,\n adapter,\n extensionPacks: extensions,\n });\n\n // Lazily construct the control adapter on first use, then memoize it.\n // Merely building a family instance must not instantiate the adapter —\n // that would change the load/instantiate semantics of the whole stack\n // wherever a family is created (every CLI command, emit, verify, …), not\n // just the migration paths that actually need it. Memoizing also avoids\n // the previous per-operation re-instantiation (a fresh adapter on every\n // call). Family-instance methods accept `SqlControlDriverInstance<string>`\n // (the family API isn't generic on the target id); the adapter\n // descriptor's `create` returns the concrete `SqlControlAdapter<TTargetId>`,\n // widened to `string` to match the family-level driver type without a\n // per-method probe.\n let controlAdapter: SqlControlAdapter<string> | undefined;\n const getControlAdapter = (): SqlControlAdapter<string> =>\n (controlAdapter ??= adapter.create(stack));\n\n const targetSerializer = (\n target as unknown as {\n contractSerializer?: {\n deserializeContract(json: unknown): Contract<SqlStorage>;\n serializeContract(contract: Contract<SqlStorage>): unknown;\n };\n }\n ).contractSerializer;\n // Database→PSL inference is target logic (it owns the dialect type/default\n // maps and walks its own schema tree), so it is read off the descriptor like\n // `contractSerializer`. Absent for targets without `contract infer` (Mongo).\n const targetInferPslContract = blindCast<\n SqlControlTargetDescriptor<TTargetId, unknown>,\n 'reading the optional target-descriptor inferPslContract hook'\n >(target).inferPslContract;\n // `contract infer` needs each extension pack's already-assembled contract,\n // carried as-is (no merging — that is the contract-spaces machinery's\n // concern), paired with the `spaceId` its descriptor was registered under\n // (neither the contract JSON nor `ContractSpace` self-declares it), so the\n // target hook can omit elements those contracts describe and qualify a\n // cross-space relation with the owning pack's space id.\n const describedContracts: readonly SqlDescribedContractSpace[] = extensions.flatMap(\n (extension) =>\n extension.contractSpace\n ? [{ spaceId: extension.id, contract: extension.contractSpace.contractJson }]\n : [],\n );\n // The combined database-schema verify is a required target-descriptor\n // operation: every SQL target provides it, wrapping the same comparison\n // `diffDatabaseSchema` runs in the verify envelope plus the pass/warn/fail\n // tree the CLI renders. Read it off the descriptor like the other\n // target-owned hooks.\n const verifyDatabaseSchema = blindCast<\n {\n readonly verifyDatabaseSchema?: (\n input: DiffDatabaseSchemaInput,\n ) => VerifyDatabaseSchemaResult;\n },\n 'reading the required target-descriptor verifyDatabaseSchema hook'\n >(target).verifyDatabaseSchema;\n if (!verifyDatabaseSchema) {\n throw new Error(\n `SQL target \"${target.targetId}\" is missing the required verifyDatabaseSchema descriptor operation`,\n );\n }\n const deserializeWithTargetSerializer = (contractOrJson: unknown): Contract<SqlStorage> => {\n const serializer = targetSerializer ?? new SqlContractSerializer();\n const json =\n targetSerializer !== undefined && !isPlainRecord(contractOrJson)\n ? targetSerializer.serializeContract(\n blindCast<\n Contract<SqlStorage>,\n 'isPlainRecord returned false, so contractOrJson is a class instance, not raw JSON'\n >(contractOrJson),\n )\n : contractOrJson;\n return serializer.deserializeContract(json) as Contract<SqlStorage>;\n };\n\n return {\n familyId: 'sql',\n codecTypeImports,\n extensionIds,\n typeMetadataRegistry,\n\n deserializeContract(contractJson: unknown): Contract {\n return deserializeWithTargetSerializer(contractJson);\n },\n\n async verify(verifyOptions: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly contract: unknown;\n readonly expectedTargetId: string;\n readonly contractPath: string;\n readonly configPath?: string;\n }): Promise<VerifyDatabaseResult> {\n const {\n driver,\n contract: rawContract,\n expectedTargetId,\n contractPath,\n configPath,\n } = verifyOptions;\n const startTime = Date.now();\n\n const contract = deserializeWithTargetSerializer(rawContract) as Contract<SqlStorage>;\n\n const contractStorageHash = contract.storage.storageHash;\n const contractProfileHash = contract.profileHash;\n const contractTarget = contract.target;\n\n const marker = await getControlAdapter().readMarker(driver, APP_SPACE_ID);\n\n let missingCodecs: readonly string[] | undefined;\n let codecCoverageSkipped = false;\n const supportedTypeIds = collectSupportedCodecTypeIds([adapter, target, ...extensions]);\n if (supportedTypeIds.length === 0) {\n codecCoverageSkipped = true;\n } else {\n const supportedSet = new Set(supportedTypeIds);\n const usedTypeIds = extractCodecTypeIdsFromContract(contract);\n const missing = usedTypeIds.filter((id) => !supportedSet.has(id));\n if (missing.length > 0) {\n missingCodecs = missing;\n }\n }\n\n if (!marker) {\n const totalTime = Date.now() - startTime;\n return createVerifyResult({\n ok: false,\n code: VERIFY_CODE_MARKER_MISSING,\n summary: 'Marker missing',\n contractStorageHash,\n expectedTargetId,\n contractPath,\n totalTime,\n ...(contractProfileHash ? { contractProfileHash } : {}),\n ...(missingCodecs ? { missingCodecs } : {}),\n ...(codecCoverageSkipped ? { codecCoverageSkipped } : {}),\n ...(configPath ? { configPath } : {}),\n });\n }\n\n if (contractTarget !== expectedTargetId) {\n const totalTime = Date.now() - startTime;\n return createVerifyResult({\n ok: false,\n code: VERIFY_CODE_TARGET_MISMATCH,\n summary: 'Target mismatch',\n contractStorageHash,\n marker,\n expectedTargetId,\n actualTargetId: contractTarget,\n contractPath,\n totalTime,\n ...(contractProfileHash ? { contractProfileHash } : {}),\n ...(missingCodecs ? { missingCodecs } : {}),\n ...(codecCoverageSkipped ? { codecCoverageSkipped } : {}),\n ...(configPath ? { configPath } : {}),\n });\n }\n\n if (marker.storageHash !== contractStorageHash) {\n const totalTime = Date.now() - startTime;\n return createVerifyResult({\n ok: false,\n code: VERIFY_CODE_HASH_MISMATCH,\n summary: 'Hash mismatch',\n contractStorageHash,\n marker,\n expectedTargetId,\n contractPath,\n totalTime,\n ...(contractProfileHash ? { contractProfileHash } : {}),\n ...(missingCodecs ? { missingCodecs } : {}),\n ...(codecCoverageSkipped ? { codecCoverageSkipped } : {}),\n ...(configPath ? { configPath } : {}),\n });\n }\n\n if (contractProfileHash && marker.profileHash !== contractProfileHash) {\n const totalTime = Date.now() - startTime;\n return createVerifyResult({\n ok: false,\n code: VERIFY_CODE_HASH_MISMATCH,\n summary: 'Hash mismatch',\n contractStorageHash,\n contractProfileHash,\n marker,\n expectedTargetId,\n contractPath,\n totalTime,\n ...(missingCodecs ? { missingCodecs } : {}),\n ...(codecCoverageSkipped ? { codecCoverageSkipped } : {}),\n ...(configPath ? { configPath } : {}),\n });\n }\n\n const totalTime = Date.now() - startTime;\n return createVerifyResult({\n ok: true,\n summary: 'Database matches contract',\n contractStorageHash,\n marker,\n expectedTargetId,\n contractPath,\n totalTime,\n ...(contractProfileHash ? { contractProfileHash } : {}),\n ...(missingCodecs ? { missingCodecs } : {}),\n ...(codecCoverageSkipped ? { codecCoverageSkipped } : {}),\n ...(configPath ? { configPath } : {}),\n });\n },\n\n verifySchema(options: {\n readonly contract: unknown;\n readonly schema: SqlSchemaIRNode;\n readonly strict: boolean;\n readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;\n }): VerifyDatabaseSchemaResult {\n const contract = deserializeWithTargetSerializer(options.contract) as Contract<SqlStorage>;\n // Verify is a thin consumer of the target's black-box comparison: it\n // introspects the actual schema (already in `options.schema`), calls the\n // target's required `verifyDatabaseSchema`, and rejects when a surviving\n // issue is a failure. It composes no diffing itself and is blind to how\n // the comparison works.\n const sqlResult = verifyDatabaseSchema({\n contract,\n schema: options.schema,\n strict: options.strict,\n typeMetadataRegistry,\n frameworkComponents: options.frameworkComponents,\n });\n // Control-policy suppression of the structural (e.g. RLS policy) diff\n // issues is a verify-side post-step — the combined diff returns them\n // ownership-filtered, and a suppressed control policy drops them here.\n const schemaDiffIssues = filterSchemaDiffIssues(\n sqlResult.schema.schemaDiffIssues,\n contract.defaultControlPolicy,\n );\n const relationalFails = sqlResult.schema.counts.fail;\n if (schemaDiffIssues.length === 0) {\n if (schemaDiffIssues === sqlResult.schema.schemaDiffIssues) return sqlResult;\n return { ...sqlResult, schema: { ...sqlResult.schema, schemaDiffIssues } };\n }\n const totalFails = relationalFails + schemaDiffIssues.length;\n return {\n ...sqlResult,\n ok: false,\n code: sqlResult.code ?? 'PN-RUN-3010',\n summary: `Database schema does not satisfy contract (${totalFails} failure${totalFails === 1 ? '' : 's'})`,\n schema: {\n ...sqlResult.schema,\n schemaDiffIssues,\n counts: { ...sqlResult.schema.counts, fail: totalFails },\n },\n };\n },\n async sign(options: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly contract: unknown;\n readonly contractPath: string;\n readonly configPath?: string;\n }): Promise<SignDatabaseResult> {\n const { driver, contract: contractInput, contractPath, configPath } = options;\n const startTime = Date.now();\n\n const contract = deserializeWithTargetSerializer(contractInput) as Contract<SqlStorage>;\n\n const contractStorageHash = contract.storage.storageHash;\n const contractProfileHash =\n 'profileHash' in contract && typeof contract.profileHash === 'string'\n ? contract.profileHash\n : contractStorageHash;\n const contractTarget = contract.target;\n\n const controlAdapter = getControlAdapter();\n const lowererContext = { contract };\n for (const query of controlAdapter.bootstrapSignMarkerQueries()) {\n const lowered = await controlAdapter.lowerToExecuteRequest(query, lowererContext);\n await driver.query(lowered.sql, lowered.params);\n }\n\n const existingMarker = await controlAdapter.readMarker(driver, 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.insertMarker(driver, APP_SPACE_ID, {\n storageHash: contractStorageHash,\n profileHash: contractProfileHash,\n });\n markerCreated = true;\n } else {\n const existingStorageHash = existingMarker.storageHash;\n const existingProfileHash = existingMarker.profileHash;\n\n const storageHashMatches = existingStorageHash === contractStorageHash;\n const profileHashMatches = existingProfileHash === contractProfileHash;\n\n if (!storageHashMatches || !profileHashMatches) {\n previousHashes = {\n storageHash: existingStorageHash,\n profileHash: existingProfileHash,\n };\n const updated = await controlAdapter.updateMarker(\n driver,\n APP_SPACE_ID,\n existingStorageHash,\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 const totalTime = Date.now() - startTime;\n\n return {\n ok: true,\n summary,\n contract: {\n storageHash: contractStorageHash,\n profileHash: contractProfileHash,\n },\n target: {\n expected: contractTarget,\n actual: contractTarget,\n },\n marker: {\n created: markerCreated,\n updated: markerUpdated,\n ...(previousHashes ? { previous: previousHashes } : {}),\n },\n meta: {\n contractPath,\n ...(configPath ? { configPath } : {}),\n },\n timings: {\n total: totalTime,\n },\n };\n },\n async readMarker(options: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly space: string;\n }): Promise<ContractMarkerRecord | null> {\n return getControlAdapter().readMarker(options.driver, options.space);\n },\n async readAllMarkers(options: {\n readonly driver: SqlControlDriverInstance<string>;\n }): Promise<ReadonlyMap<string, ContractMarkerRecord>> {\n return getControlAdapter().readAllMarkers(options.driver);\n },\n async readLedger(options: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly space?: string;\n }): Promise<readonly LedgerEntryRecord[]> {\n return getControlAdapter().readLedger(options.driver, options.space);\n },\n async initMarker(options: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly space: string;\n readonly destination: {\n readonly storageHash: string;\n readonly profileHash: string;\n readonly invariants?: readonly string[];\n };\n }): Promise<void> {\n return getControlAdapter().initMarker(options.driver, options.space, options.destination);\n },\n async updateMarker(options: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly space: string;\n readonly expectedFrom: string;\n readonly destination: {\n readonly storageHash: string;\n readonly profileHash: string;\n readonly invariants?: readonly string[];\n };\n }): Promise<boolean> {\n return getControlAdapter().updateMarker(\n options.driver,\n options.space,\n options.expectedFrom,\n options.destination,\n );\n },\n async writeLedgerEntry(options: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly space: string;\n readonly entry: {\n readonly edgeId: string;\n readonly from: string;\n readonly to: string;\n readonly migrationName: string;\n readonly migrationHash: string;\n readonly operations: readonly unknown[];\n };\n }): Promise<void> {\n return getControlAdapter().writeLedgerEntry(options.driver, options.space, options.entry);\n },\n async introspect(options: {\n readonly driver: SqlControlDriverInstance<string>;\n readonly contract?: unknown;\n }): Promise<SqlSchemaIRNode> {\n return getControlAdapter().introspect(options.driver, options.contract);\n },\n\n inferPslContract(schemaIR: SqlSchemaIRNode): PslDocumentAst {\n if (!targetInferPslContract) {\n throw new Error(\n `Target \"${target.targetId}\" does not support contract infer (no inferPslContract on its descriptor).`,\n );\n }\n return targetInferPslContract(schemaIR, describedContracts);\n },\n\n lowerAst(\n ast: AnyQueryAst | DdlNode,\n context: LowererContext<unknown>,\n ): Promise<SqlExecuteRequest> {\n return getControlAdapter().lowerToExecuteRequest(ast, context);\n },\n\n bootstrapControlTableQueries(): readonly DdlNode[] {\n return getControlAdapter().bootstrapControlTableQueries();\n },\n\n toOperationPreview(operations: readonly MigrationPlanOperation[]): OperationPreview {\n return sqlOperationsToPreview(operations);\n },\n\n toSchemaView(schema: SqlSchemaIRNode): CoreSchemaView {\n // Walk the schema-IR tree's own structure (root → namespaces → tables)\n // into one flat list of table nodes. A root that exposes a `namespaces`\n // record (Postgres) contributes each namespace's tables; a flat root\n // (SQLite) is its own single namespace. The single-schema common case\n // renders the same table-level view as today — no synthetic namespace\n // level.\n const root = blindCast<\n {\n readonly namespaces?: Readonly<\n Record<string, { readonly tables: Record<string, SqlTableIR> }>\n >;\n readonly tables?: Record<string, SqlTableIR>;\n },\n 'structural read of the schema-IR tree own namespaces/tables records'\n >(schema);\n // A multi-namespace root qualifies every table's display name with its\n // namespace key, so same-named tables in different namespaces (e.g.\n // public.thing and auth.thing) render distinct ids and labels. The\n // single-namespace case (and a flat SQLite root) keeps today's bare\n // names. Synthesized constraint/index fallback names keep the bare table\n // name — that is the name the database derives them from.\n const namespaceEntries: ReadonlyArray<[string | undefined, Record<string, SqlTableIR>]> =\n root.namespaces !== undefined\n ? Object.entries(root.namespaces).map(\n ([namespaceKey, namespace]): [string, Record<string, SqlTableIR>] => [\n namespaceKey,\n namespace.tables,\n ],\n )\n : [[undefined, root.tables ?? {}]];\n const qualify = namespaceEntries.length > 1;\n const tableEntries: ReadonlyArray<[string, string, SqlTableIR]> = namespaceEntries.flatMap(\n ([namespaceKey, tables]) =>\n Object.entries(tables).map(([tableName, table]): [string, string, SqlTableIR] => [\n qualify && namespaceKey !== undefined ? `${namespaceKey}.${tableName}` : tableName,\n tableName,\n table,\n ]),\n );\n const tableNodes: readonly SchemaTreeNode[] = tableEntries.map(\n ([displayName, tableName, table]: [string, string, SqlTableIR]) => {\n const children: SchemaTreeNode[] = [];\n\n const columnNodes: SchemaTreeNode[] = [];\n for (const [columnName, column] of Object.entries(table.columns)) {\n const typeDisplay = column.nativeType;\n const nullability = column.nullable ? 'nullable' : 'not nullable';\n const label = `${columnName}: ${typeDisplay} (${nullability})`;\n columnNodes.push(\n new SchemaTreeNode({\n kind: 'field',\n id: `column-${displayName}-${columnName}`,\n label,\n meta: {\n nativeType: column.nativeType,\n nullable: column.nullable,\n ...ifDefined('default', column.default),\n },\n }),\n );\n }\n\n if (columnNodes.length > 0) {\n children.push(\n new SchemaTreeNode({\n kind: 'collection',\n id: `columns-${displayName}`,\n label: 'columns',\n children: columnNodes,\n }),\n );\n }\n\n if (table.primaryKey) {\n const pkColumns = table.primaryKey.columns.join(', ');\n children.push(\n new SchemaTreeNode({\n kind: 'index',\n id: `primary-key-${displayName}`,\n label: `primary key: ${pkColumns}`,\n meta: {\n columns: table.primaryKey.columns,\n ...(table.primaryKey.name ? { name: table.primaryKey.name } : {}),\n },\n }),\n );\n }\n\n for (const unique of table.uniques) {\n const name = unique.name ?? `${tableName}_${unique.columns.join('_')}_unique`;\n const label = `unique ${name}`;\n children.push(\n new SchemaTreeNode({\n kind: 'index',\n id: `unique-${displayName}-${name}`,\n label,\n meta: {\n columns: unique.columns,\n unique: true,\n },\n }),\n );\n }\n\n for (const index of table.indexes) {\n const name = index.name ?? defaultIndexName(tableName, index.columns);\n const label = index.unique ? `unique index ${name}` : `index ${name}`;\n children.push(\n new SchemaTreeNode({\n kind: 'index',\n id: `index-${displayName}-${name}`,\n label,\n meta: {\n columns: index.columns,\n unique: index.unique,\n },\n }),\n );\n }\n\n const tableMeta: Record<string, unknown> = {};\n if (table.primaryKey) {\n tableMeta['primaryKey'] = table.primaryKey.columns;\n if (table.primaryKey.name) {\n tableMeta['primaryKeyName'] = table.primaryKey.name;\n }\n }\n if (table.foreignKeys.length > 0) {\n tableMeta['foreignKeys'] = table.foreignKeys.map((fk) => ({\n columns: fk.columns,\n referencedTable: fk.referencedTable,\n referencedColumns: fk.referencedColumns,\n ...(fk.name ? { name: fk.name } : {}),\n }));\n }\n\n return new SchemaTreeNode({\n kind: 'entity',\n id: `table-${displayName}`,\n label: `table ${displayName}`,\n ...(Object.keys(tableMeta).length > 0 ? { meta: tableMeta } : {}),\n ...(children.length > 0 ? { children } : {}),\n });\n },\n );\n\n return {\n root: new SchemaTreeNode({\n kind: 'root',\n id: 'sql-schema',\n label: 'database',\n ...(tableNodes.length > 0 ? { children: tableNodes } : {}),\n }),\n };\n },\n };\n}\n\n/**\n * Filters the structural schema-diff issues (from `diffDatabaseSchema`) through\n * the contract's `defaultControlPolicy`. Issues whose outcome maps to a suppressed\n * category under the effective policy are removed. This mirrors the control-policy\n * filtering applied by `verifySqlSchema` for table/column-level findings.\n *\n * Outcome → category mapping:\n * - `'extra'` → `'extraAuxiliary'` (an extra auxiliary entity, e.g. an RLS policy)\n * - `'missing'` → `'declaredMissing'`\n * - `'mismatch'` → `'declaredIncompatible'`\n */\nexport function filterSchemaDiffIssues(\n issues: readonly SchemaDiffIssue[],\n defaultControlPolicy: ControlPolicy | undefined,\n): readonly SchemaDiffIssue[] {\n if (issues.length === 0) return issues;\n const policy = effectiveControlPolicy(undefined, defaultControlPolicy);\n return issues.filter((issue) => {\n const category =\n issue.outcome === 'extra'\n ? ('extraAuxiliary' as const)\n : issue.outcome === 'missing'\n ? ('declaredMissing' as const)\n : ('declaredIncompatible' as const);\n return dispositionForCategory(policy, category) !== 'suppress';\n });\n}\n","import type {\n ControlFamilyDescriptor,\n ControlStack,\n} from '@prisma-next/framework-components/control';\nimport type { EmissionSpi } from '@prisma-next/framework-components/emission';\nimport { sqlEmission } from '@prisma-next/sql-contract-emitter';\nimport { sqlFamilyEntityTypes, sqlFamilyPslBlockDescriptors } from './authoring-entity-types';\nimport { sqlFamilyAuthoringFieldPresets } from './authoring-field-presets';\nimport { sqlFamilyAuthoringTypes } from './authoring-type-constructors';\nimport { createSqlFamilyInstance, type SqlControlFamilyInstance } from './control-instance';\n\nexport class SqlFamilyDescriptor\n implements ControlFamilyDescriptor<'sql', SqlControlFamilyInstance>\n{\n readonly kind = 'family' as const;\n readonly id = 'sql';\n readonly familyId = 'sql' as const;\n readonly version = '0.0.1';\n readonly emission: EmissionSpi = sqlEmission;\n readonly authoring = {\n field: sqlFamilyAuthoringFieldPresets,\n type: sqlFamilyAuthoringTypes,\n entityTypes: sqlFamilyEntityTypes,\n pslBlockDescriptors: sqlFamilyPslBlockDescriptors,\n } as const;\n\n create<TTargetId extends string>(\n stack: ControlStack<'sql', TTargetId>,\n ): SqlControlFamilyInstance {\n return createSqlFamilyInstance(stack);\n }\n}\n","import {\n type Contract,\n type ControlPolicy,\n effectiveControlPolicy,\n} from '@prisma-next/contract/types';\nimport type { SqlStorage } from '@prisma-next/sql-contract/types';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { SqlPlannerConflict } from './types';\n\n/**\n * The target object a control policy governs for a single planner call,\n * resolved from the target's own IR. `undefined` means the call's target\n * object could not be positively established — a fail-closed signal: any\n * policy stricter than `managed` drops such a call rather than emitting it.\n */\nexport interface ControlPolicySubject {\n readonly namespaceId: string;\n readonly explicitNodeControlPolicy?: ControlPolicy;\n readonly table?: string;\n readonly column?: string;\n readonly typeName?: string;\n /**\n * Whether the call creates a whole, previously-absent top-level storage\n * object (e.g. a table or an enum/type), as opposed to modifying an\n * existing object. This is the only thing `tolerated` permits: it is a\n * create-if-absent policy, so an op that touches an existing object — add\n * column, add index/constraint, alter, drop — is never allowed under it.\n */\n readonly createsNewObject: boolean;\n}\n\n/**\n * The control policy that governs a single call. The `external` default is an\n * un-overridable namespace floor: when the contract default is `external`, no\n * per-object `managed` override can escalate DDL above the floor, so the\n * policy is forced to `external` regardless of the node's own declaration.\n * Every other default defers to the node's effective control policy.\n */\nexport function controlPolicyForCall(\n subject: ControlPolicySubject | undefined,\n defaultControlPolicy: ControlPolicy | undefined,\n): ControlPolicy {\n if (defaultControlPolicy === 'external') {\n return 'external';\n }\n return effectiveControlPolicy(subject?.explicitNodeControlPolicy, defaultControlPolicy);\n}\n\n/**\n * Whether a call is allowed to emit under a given control policy.\n *\n * - `managed` — full lifecycle, every op allowed.\n * - `tolerated` — create-if-absent only: allowed iff the call creates a whole\n * new top-level object (and its subject was positively resolved). Anything\n * that modifies an existing object, and anything whose subject could not be\n * resolved, is suppressed.\n * - `external` / `observed` — no DDL at all.\n */\nfunction callAllowedUnderControlPolicy(\n policy: ControlPolicy,\n subject: ControlPolicySubject | undefined,\n): boolean {\n switch (policy) {\n case 'managed':\n return true;\n case 'tolerated':\n return subject?.createsNewObject === true;\n case 'external':\n case 'observed':\n return false;\n }\n}\n\nfunction defaultSubjectLabel(\n factoryName: string,\n subject: ControlPolicySubject | undefined,\n): string {\n if (subject?.table) {\n return `${factoryName}(${subject.table})`;\n }\n if (subject?.typeName) {\n return `${factoryName}(${subject.typeName})`;\n }\n return factoryName;\n}\n\nfunction suppressionSummary(\n subjectLabel: string,\n subject: ControlPolicySubject | undefined,\n effectivePolicy: ControlPolicy,\n): string {\n const namespace = subject?.namespaceId ?? 'unknown';\n const declared = subject?.explicitNodeControlPolicy;\n if (effectivePolicy === 'external' && declared === 'managed') {\n return `control policy suppressed: ${subjectLabel} — namespace '${namespace}' has effective control 'external' but table declared 'managed'`;\n }\n const declaredSuffix = declared ? ` but table declared '${declared}'` : '';\n return `control policy suppressed: ${subjectLabel} — namespace '${namespace}' has effective control '${effectivePolicy}'${declaredSuffix}`;\n}\n\nfunction buildSubjectSuppressionWarning(\n subject: ControlPolicySubject | undefined,\n effectivePolicy: ControlPolicy,\n factoryName: string,\n formatSubjectLabel: (factoryName: string, subject: ControlPolicySubject | undefined) => string,\n): SqlPlannerConflict {\n const subjectLabel = formatSubjectLabel(factoryName, subject);\n return {\n kind: 'controlPolicySuppressedCall',\n summary: suppressionSummary(subjectLabel, subject, effectivePolicy),\n location: {\n ...ifDefined('namespace', subject?.namespaceId),\n ...ifDefined('table', subject?.table),\n ...ifDefined('column', subject?.column),\n ...ifDefined('type', subject?.typeName),\n },\n meta: {\n controlPolicy: effectivePolicy,\n factoryName,\n ...ifDefined('declaredControlPolicy', subject?.explicitNodeControlPolicy),\n },\n };\n}\n\nfunction defaultModificationFactoryNameForSubject(subject: ControlPolicySubject): string {\n if (subject.table) return 'alterTable';\n if (subject.typeName) return 'alterType';\n return 'alterSchema';\n}\n\n/**\n * Partition the calls produced for a single set of subjects into those the\n * effective control policy permits (`kept`) and a list of\n * {@link SqlPlannerConflict} warnings describing the suppressed calls.\n *\n * **Prefer {@link partitionIssuesByControlPolicy}** for the schema-issue\n * pipeline: it filters subjects out of the planner's *input* so the planner\n * never has to reason about un-modeled state on `external`/`observed`\n * subjects. This call-level helper remains for paths that bypass the issue\n * pipeline — currently the codec-emitted field-event ops, which originate\n * from declared contract fields rather than from introspected schema state\n * and therefore cannot trip the diff engine.\n */\nexport function partitionCallsByControlPolicy<TCall>(options: {\n readonly calls: readonly TCall[];\n readonly contract: Contract<SqlStorage>;\n readonly resolveControlPolicySubject: (call: TCall) => ControlPolicySubject | undefined;\n readonly resolveFactoryName: (call: TCall) => string;\n readonly formatSubjectLabel?: (\n factoryName: string,\n subject: ControlPolicySubject | undefined,\n ) => string;\n}): {\n readonly kept: readonly TCall[];\n readonly warnings: readonly SqlPlannerConflict[];\n} {\n const defaultControlPolicy = options.contract.defaultControlPolicy;\n const formatSubjectLabel = options.formatSubjectLabel ?? defaultSubjectLabel;\n const kept: TCall[] = [];\n const warnings: SqlPlannerConflict[] = [];\n\n for (const call of options.calls) {\n const subject = options.resolveControlPolicySubject(call);\n const policy = controlPolicyForCall(subject, defaultControlPolicy);\n if (callAllowedUnderControlPolicy(policy, subject)) {\n kept.push(call);\n } else {\n const factoryName = options.resolveFactoryName(call);\n warnings.push(\n buildSubjectSuppressionWarning(subject, policy, factoryName, formatSubjectLabel),\n );\n }\n }\n\n return Object.freeze({\n kept: Object.freeze(kept),\n warnings: Object.freeze(warnings),\n });\n}\n\n/**\n * Partition a list of schema-issue-shaped inputs by the effective control\n * policy of each issue's subject *before* the planner is invoked.\n *\n * `plannable` is the list of issues whose subject's effective policy permits\n * the planner to act on them (`managed`, or `tolerated` for whole-object\n * creation issues only). Issues for `external`/`observed` subjects, and\n * non-creation issues for `tolerated` subjects, are dropped from the planner's\n * input entirely — they never enter introspection-driven planning, never feed\n * the diff engine, and never produce DDL calls that would have to be\n * post-filtered. This sidesteps a class of failure where the diff engine\n * cannot reason about the live shape of a subject the user marked as\n * out-of-scope (`external`).\n *\n * `warnings` is one {@link SqlPlannerConflict} per suppressed subject (not per\n * suppressed issue). `factoryName` is inferred from the subject's issue mix:\n * if any of the subject's issues is whole-object creation, the warning takes\n * the corresponding creation factoryName (e.g. `createTable`,\n * `createEnumType`, `createSchema`); otherwise it falls back to\n * `defaultModificationFactoryName(subject)` — a synthetic label that names\n * the *kind* of mutation that would have run, since no concrete DDL call was\n * generated.\n *\n * Unresolved-subject issues (`resolveControlPolicySubject` returns\n * `undefined`) emit one warning each; they cannot be deduplicated because\n * they carry no subject coordinate.\n */\nexport function partitionIssuesByControlPolicy<TIssue>(options: {\n readonly issues: readonly TIssue[];\n readonly contract: Contract<SqlStorage>;\n /**\n * Resolve the subject targeted by this issue (or `undefined` to fail-closed:\n * any policy stricter than `managed` drops the issue).\n */\n readonly resolveControlPolicySubject: (issue: TIssue) => ControlPolicySubject | undefined;\n /**\n * Resolve a creation factoryName for this issue if it represents the\n * absence of the whole top-level object (e.g. `'createTable'` for a\n * missing-table issue). When the issue describes a modification to an\n * existing object, return `undefined`. Both decisions feed off this signal:\n *\n * 1. Under `tolerated`, only issues whose `resolveCreationFactoryName`\n * returns a value flow into the planner (create-if-absent).\n * 2. Subjects that have at least one creation-flavoured issue use the\n * resolved creation factoryName for their suppression warning;\n * otherwise they fall back to `defaultModificationFactoryName`.\n */\n readonly resolveCreationFactoryName: (issue: TIssue) => string | undefined;\n /**\n * Default modification factoryName for a suppressed subject whose issues\n * are all non-creation (the subject exists but has a different shape).\n * Defaults to `'alterTable'` / `'alterType'` / `'alterSchema'` based on the\n * subject's populated coordinates.\n */\n readonly defaultModificationFactoryName?: (subject: ControlPolicySubject) => string;\n readonly formatSubjectLabel?: (\n factoryName: string,\n subject: ControlPolicySubject | undefined,\n ) => string;\n}): {\n readonly plannable: readonly TIssue[];\n readonly warnings: readonly SqlPlannerConflict[];\n} {\n const defaultControlPolicy = options.contract.defaultControlPolicy;\n const formatSubjectLabel = options.formatSubjectLabel ?? defaultSubjectLabel;\n const inferModificationFactoryName =\n options.defaultModificationFactoryName ?? defaultModificationFactoryNameForSubject;\n\n const plannable: TIssue[] = [];\n // Resolved-subject suppressions are deduplicated by subject key so we emit\n // one warning per suppressed subject, not one per suppressed issue.\n // `creationFactoryName` upgrades from `undefined` to a concrete creation\n // name the first time we see a creation-flavoured issue for the subject.\n const suppressedSubjects = new Map<\n string,\n {\n readonly subject: ControlPolicySubject;\n readonly policy: ControlPolicy;\n creationFactoryName?: string;\n }\n >();\n const unresolvedSuppressions: SqlPlannerConflict[] = [];\n\n for (const issue of options.issues) {\n const subject = options.resolveControlPolicySubject(issue);\n const policy = controlPolicyForCall(subject, defaultControlPolicy);\n const creationFactoryName = options.resolveCreationFactoryName(issue);\n\n if (policy === 'managed') {\n plannable.push(issue);\n continue;\n }\n if (\n policy === 'tolerated' &&\n subject !== undefined &&\n creationFactoryName !== undefined &&\n subject.createsNewObject\n ) {\n plannable.push(issue);\n continue;\n }\n\n if (subject === undefined) {\n const factoryName = creationFactoryName ?? 'unknown';\n unresolvedSuppressions.push(\n buildSubjectSuppressionWarning(undefined, policy, factoryName, formatSubjectLabel),\n );\n continue;\n }\n\n const key = subjectKey(subject);\n const existing = suppressedSubjects.get(key);\n if (existing) {\n if (existing.creationFactoryName === undefined && creationFactoryName !== undefined) {\n existing.creationFactoryName = creationFactoryName;\n }\n } else {\n suppressedSubjects.set(key, {\n subject,\n policy,\n ...ifDefined('creationFactoryName', creationFactoryName),\n });\n }\n }\n\n const warnings: SqlPlannerConflict[] = [...unresolvedSuppressions];\n for (const entry of suppressedSubjects.values()) {\n const factoryName = entry.creationFactoryName ?? inferModificationFactoryName(entry.subject);\n warnings.push(\n buildSubjectSuppressionWarning(entry.subject, entry.policy, factoryName, formatSubjectLabel),\n );\n }\n\n return Object.freeze({\n plannable: Object.freeze(plannable),\n warnings: Object.freeze(warnings),\n });\n}\n\nfunction subjectKey(subject: ControlPolicySubject): string {\n return `${subject.namespaceId}\\u0000${subject.table ?? ''}\\u0000${subject.typeName ?? ''}`;\n}\n","/**\n * Codec lifecycle hook planner — runs `onFieldEvent` for every per-field\n * delta between two contracts and concatenates the returned ops in a\n * deterministic order.\n *\n * Wired by each target's planner (`PostgresMigrationPlanner`,\n * `SqliteMigrationPlanner`) so codec-emitted ops are inlined alongside\n * structural DDL in the app-space migration's `ops.json`. Pure, target-\n * agnostic, and only ever invoked at the app-space emitter; extension-space\n * planning never reaches this helper.\n *\n * Ordering rules (see ADR 213):\n *\n * - Events are grouped by phase: `'added'` → `'dropped'` → `'altered'`.\n * - Within each phase, entries are sorted alphabetically by\n * `(namespaceId, tableName, fieldName)`.\n * - The hook's returned ops are appended in the order the hook returned them.\n *\n * `'altered'` is suppressed when only `codecId` differs (codec rotation is a\n * v1 non-goal).\n *\n * See: `docs/architecture docs/adrs/ADR 213 - Codec lifecycle hooks.md`.\n */\n\nimport type { Contract } from '@prisma-next/contract/types';\nimport type { OpFactoryCall } from '@prisma-next/framework-components/control';\nimport { type SqlStorage, type StorageColumn, StorageTable } from '@prisma-next/sql-contract/types';\nimport type { CodecControlHooks, FieldEvent, FieldEventContext } from './types';\n\nexport interface PlanFieldEventOperationsOptions {\n /**\n * Prior contract the planner is diffing against. `null` for first emits\n * (every field is treated as added).\n */\n readonly priorContract: Contract<SqlStorage> | null;\n /**\n * New contract the user just authored.\n */\n readonly newContract: Contract<SqlStorage>;\n /**\n * Codec-id keyed map of control hooks, as produced by\n * {@link import('./assembly').extractCodecControlHooks}. Hooks carry\n * `unknown` target details after extraction; the caller casts the\n * helper's returned ops to its target's `SqlMigrationPlanOperation`\n * specialisation at the integration boundary, mirroring how\n * `storageTypePlanCallStrategy` lifts `planTypeOperations` results into\n * `RawSqlCall`.\n */\n readonly codecHooks: ReadonlyMap<string, CodecControlHooks>;\n}\n\ninterface FieldEntry {\n readonly namespaceId: string;\n readonly tableName: string;\n readonly fieldName: string;\n readonly priorTable: StorageTable | undefined;\n readonly newTable: StorageTable | undefined;\n readonly priorField: StorageColumn | undefined;\n readonly newField: StorageColumn | undefined;\n}\n\nexport function planFieldEventOperations(\n options: PlanFieldEventOperationsOptions,\n): readonly OpFactoryCall[] {\n const priorContract = options.priorContract;\n const newContract = options.newContract;\n\n const added: FieldEntry[] = [];\n const dropped: FieldEntry[] = [];\n const altered: FieldEntry[] = [];\n\n const namespaceIds = unionSorted(\n priorContract ? Object.keys(priorContract.storage.namespaces) : [],\n Object.keys(newContract.storage.namespaces),\n );\n\n for (const namespaceId of namespaceIds) {\n const priorNs = priorContract?.storage.namespaces[namespaceId];\n const newNs = newContract.storage.namespaces[namespaceId];\n const priorTables = priorNs?.entries.table;\n const newTables = newNs?.entries.table;\n\n const tableNames = unionSorted(\n priorTables ? Object.keys(priorTables) : [],\n newTables ? Object.keys(newTables) : [],\n );\n\n for (const tableName of tableNames) {\n const priorTableRaw = priorTables?.[tableName];\n const newTableRaw = newTables?.[tableName];\n const priorTable = StorageTable.is(priorTableRaw) ? priorTableRaw : undefined;\n const newTable = StorageTable.is(newTableRaw) ? newTableRaw : undefined;\n const fieldNames = unionSorted(\n priorTable ? Object.keys(priorTable.columns) : [],\n newTable ? Object.keys(newTable.columns) : [],\n );\n for (const fieldName of fieldNames) {\n const priorField = priorTable?.columns[fieldName];\n const newField = newTable?.columns[fieldName];\n const entry: FieldEntry = {\n namespaceId,\n tableName,\n fieldName,\n priorTable,\n newTable,\n priorField,\n newField,\n };\n if (priorField === undefined && newField !== undefined) {\n added.push(entry);\n } else if (priorField !== undefined && newField === undefined) {\n dropped.push(entry);\n } else if (priorField !== undefined && newField !== undefined) {\n if (isAlteration(priorField, newField)) altered.push(entry);\n }\n }\n }\n }\n\n const calls: OpFactoryCall[] = [];\n appendCalls('added', added, options.codecHooks, calls, (e) => e.newField?.codecId);\n appendCalls('dropped', dropped, options.codecHooks, calls, (e) => e.priorField?.codecId);\n appendCalls('altered', altered, options.codecHooks, calls, (e) => e.newField?.codecId);\n return calls;\n}\n\nfunction appendCalls(\n event: FieldEvent,\n entries: readonly FieldEntry[],\n codecHooks: ReadonlyMap<string, CodecControlHooks>,\n calls: OpFactoryCall[],\n pickCodecId: (entry: FieldEntry) => string | undefined,\n): void {\n for (const entry of entries) {\n const codecId = pickCodecId(entry);\n if (codecId === undefined) continue;\n const hook = codecHooks.get(codecId);\n if (!hook?.onFieldEvent) continue;\n const ctx = buildContext(event, entry);\n const emitted = hook.onFieldEvent(event, ctx);\n for (const call of emitted) calls.push(call);\n }\n}\n\n/**\n * The context's prior/new sides are scoped to the event:\n *\n * - `'added'` — only `newTable` / `newField` populated.\n * - `'dropped'` — only `priorTable` / `priorField` populated.\n * - `'altered'` — both sides populated.\n */\nfunction buildContext(event: FieldEvent, entry: FieldEntry): FieldEventContext {\n const base = {\n namespaceId: entry.namespaceId,\n tableName: entry.tableName,\n fieldName: entry.fieldName,\n };\n if (event === 'added') {\n return {\n ...base,\n ...(entry.newTable !== undefined ? { newTable: entry.newTable } : {}),\n ...(entry.newField !== undefined ? { newField: entry.newField } : {}),\n };\n }\n if (event === 'dropped') {\n return {\n ...base,\n ...(entry.priorTable !== undefined ? { priorTable: entry.priorTable } : {}),\n ...(entry.priorField !== undefined ? { priorField: entry.priorField } : {}),\n };\n }\n return {\n ...base,\n ...(entry.priorTable !== undefined ? { priorTable: entry.priorTable } : {}),\n ...(entry.newTable !== undefined ? { newTable: entry.newTable } : {}),\n ...(entry.priorField !== undefined ? { priorField: entry.priorField } : {}),\n ...(entry.newField !== undefined ? { newField: entry.newField } : {}),\n };\n}\n\n/**\n * `'altered'` predicate. Returns `false` whenever `codecId` differs —\n * any codec change suppresses the `altered` event entirely, including\n * cases where another property also differs in the same diff. Codec\n * rotation is a v1 non-goal; avoiding the mixed event keeps the\n * migration semantics for codec changes explicit rather than smuggling\n * them through as `altered`.\n *\n * For non-`codecId` diffs, returns `true` iff any other column property\n * differs.\n */\nfunction isAlteration(prior: StorageColumn, current: StorageColumn): boolean {\n if (prior.codecId !== current.codecId) return false;\n return !sameStorageColumn(prior, current);\n}\n\nfunction sameStorageColumn(a: StorageColumn, b: StorageColumn): boolean {\n if (a === b) return true;\n if (a.nativeType !== b.nativeType) return false;\n if (a.nullable !== b.nullable) return false;\n if (a.typeRef !== b.typeRef) return false;\n if (!sameJson(a.typeParams, b.typeParams)) return false;\n if (!sameJson(a.default, b.default)) return false;\n return true;\n}\n\nfunction sameJson(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a === undefined || b === undefined) return false;\n return JSON.stringify(a) === JSON.stringify(b);\n}\n\nfunction unionSorted(a: readonly string[], b: readonly string[]): readonly string[] {\n const set = new Set<string>();\n for (const name of a) set.add(name);\n for (const name of b) set.add(name);\n return [...set].sort((x, y) => (x < y ? -1 : x > y ? 1 : 0));\n}\n","import type { NotOk, Ok } from '@prisma-next/utils/result';\nimport { notOk, ok } from '@prisma-next/utils/result';\nimport type {\n AnyRecord,\n CreateSqlMigrationPlanOptions,\n SqlMigrationPlan,\n SqlMigrationPlanOperation,\n SqlMigrationPlanOperationStep,\n SqlMigrationPlanOperationTarget,\n SqlMigrationRunnerErrorCode,\n SqlMigrationRunnerFailure,\n SqlMigrationRunnerSuccessValue,\n SqlPlannerConflict,\n SqlPlannerFailureResult,\n SqlPlannerSuccessResult,\n} from './types';\n\nconst readOnlyEmptyObject: Record<string, never> = Object.freeze({});\n\nfunction cloneRecord<T extends AnyRecord>(value: T): T {\n if (value === readOnlyEmptyObject) {\n return value;\n }\n return Object.freeze({ ...value }) as T;\n}\n\nfunction freezeSteps(\n steps: readonly SqlMigrationPlanOperationStep[],\n): readonly SqlMigrationPlanOperationStep[] {\n if (steps.length === 0) {\n return Object.freeze([]);\n }\n return Object.freeze(\n steps.map((step) =>\n Object.freeze({\n description: step.description,\n sql: step.sql,\n ...(step.params ? { params: Object.freeze([...step.params]) } : {}),\n ...(step.meta ? { meta: cloneRecord(step.meta) } : {}),\n }),\n ),\n );\n}\n\nfunction freezeDetailsValue<T>(value: T): T {\n // Primitives and null/undefined are already immutable, return as-is\n if (value === null || value === undefined) {\n return value;\n }\n if (typeof value !== 'object') {\n return value;\n }\n // Arrays: shallow clone and freeze\n if (Array.isArray(value)) {\n return Object.freeze([...value]) as T;\n }\n // Objects: shallow clone and freeze (matching cloneRecord pattern)\n return Object.freeze({ ...value }) as T;\n}\n\nfunction freezeTargetDetails<TTargetDetails>(\n target: SqlMigrationPlanOperationTarget<TTargetDetails>,\n): SqlMigrationPlanOperationTarget<TTargetDetails> {\n return Object.freeze({\n id: target.id,\n ...(target.details !== undefined ? { details: freezeDetailsValue(target.details) } : {}),\n });\n}\n\nfunction freezeOperation<TTargetDetails>(\n operation: SqlMigrationPlanOperation<TTargetDetails>,\n): SqlMigrationPlanOperation<TTargetDetails> {\n return Object.freeze({\n id: operation.id,\n label: operation.label,\n ...(operation.summary ? { summary: operation.summary } : {}),\n operationClass: operation.operationClass,\n ...(operation.invariantId ? { invariantId: operation.invariantId } : {}),\n target: freezeTargetDetails(operation.target),\n precheck: freezeSteps(operation.precheck),\n execute: freezeSteps(operation.execute),\n postcheck: freezeSteps(operation.postcheck),\n ...(operation.meta ? { meta: cloneRecord(operation.meta) } : {}),\n });\n}\n\nfunction freezeOperations<TTargetDetails>(\n operations: readonly SqlMigrationPlanOperation<TTargetDetails>[],\n): readonly SqlMigrationPlanOperation<TTargetDetails>[] {\n if (operations.length === 0) {\n return Object.freeze([]);\n }\n return Object.freeze(operations.map((operation) => freezeOperation(operation)));\n}\n\nexport function createMigrationPlan<TTargetDetails>(\n options: CreateSqlMigrationPlanOptions<TTargetDetails>,\n): SqlMigrationPlan<TTargetDetails> {\n return Object.freeze({\n targetId: options.targetId,\n spaceId: options.spaceId,\n ...(options.origin !== undefined\n ? { origin: options.origin ? Object.freeze({ ...options.origin }) : null }\n : {}),\n destination: Object.freeze({ ...options.destination }),\n operations: freezeOperations(options.operations),\n providedInvariants: Object.freeze([...options.providedInvariants]),\n ...(options.meta ? { meta: cloneRecord(options.meta) } : {}),\n });\n}\n\nexport function plannerSuccess<TTargetDetails>(\n plan: SqlMigrationPlan<TTargetDetails>,\n warnings?: readonly SqlPlannerConflict[],\n): SqlPlannerSuccessResult<TTargetDetails> {\n return Object.freeze({\n kind: 'success',\n plan,\n ...(warnings && warnings.length > 0\n ? {\n warnings: Object.freeze(\n warnings.map((conflict) =>\n Object.freeze({\n kind: conflict.kind,\n summary: conflict.summary,\n ...(conflict.why ? { why: conflict.why } : {}),\n ...(conflict.location ? { location: Object.freeze({ ...conflict.location }) } : {}),\n ...(conflict.meta ? { meta: cloneRecord(conflict.meta) } : {}),\n }),\n ),\n ),\n }\n : {}),\n });\n}\n\nexport function plannerFailure(conflicts: readonly SqlPlannerConflict[]): SqlPlannerFailureResult {\n return Object.freeze({\n kind: 'failure' as const,\n conflicts: Object.freeze(\n conflicts.map((conflict) =>\n Object.freeze({\n kind: conflict.kind,\n summary: conflict.summary,\n ...(conflict.why ? { why: conflict.why } : {}),\n ...(conflict.location ? { location: Object.freeze({ ...conflict.location }) } : {}),\n ...(conflict.meta ? { meta: cloneRecord(conflict.meta) } : {}),\n }),\n ),\n ),\n });\n}\n\n/**\n * Creates a successful migration runner result.\n */\nexport function runnerSuccess(value: {\n operationsPlanned: number;\n operationsExecuted: number;\n}): Ok<SqlMigrationRunnerSuccessValue> {\n return ok(\n Object.freeze({\n operationsPlanned: value.operationsPlanned,\n operationsExecuted: value.operationsExecuted,\n }),\n );\n}\n\n/**\n * Creates a failed migration runner result.\n */\nexport function runnerFailure(\n code: SqlMigrationRunnerErrorCode,\n summary: string,\n options?: { why?: string; meta?: AnyRecord },\n): NotOk<SqlMigrationRunnerFailure> {\n const failure: SqlMigrationRunnerFailure = Object.freeze({\n code,\n summary,\n ...(options?.why ? { why: options.why } : {}),\n ...(options?.meta ? { meta: cloneRecord(options.meta) } : {}),\n });\n return notOk(failure);\n}\n","import type { MigrationOperationPolicy } from '@prisma-next/framework-components/control';\n\n/**\n * Policy used by `db init`: additive-only operations, no widening/destructive steps.\n */\nexport const INIT_ADDITIVE_POLICY: MigrationOperationPolicy = Object.freeze({\n allowedOperationClasses: Object.freeze(['additive'] as const),\n});\n","import { SqlFamilyDescriptor } from '../core/control-descriptor';\n\n// Re-export core types from canonical source\nexport type {\n MigrationOperationClass,\n MigrationOperationPolicy,\n MigrationPlan,\n MigrationPlanner,\n MigrationPlannerConflict,\n MigrationPlannerResult,\n MigrationPlanOperation,\n TargetMigrationsCapability,\n} from '@prisma-next/framework-components/control';\nexport { assembleAuthoringContributions } from '@prisma-next/framework-components/control';\nexport { extractCodecControlHooks } from '../core/assembly';\nexport type { SqlControlFamilyInstance } from '../core/control-instance';\nexport type {\n SqlControlTargetDescriptor,\n SqlDescribedContractSpace,\n} from '../core/control-target-descriptor';\nexport type {\n ContractToSchemaIROptions,\n DefaultRenderer,\n EnumNamespaceSchemaResolver,\n NativeTypeExpander,\n} from '../core/migrations/contract-to-schema-ir';\n// Contract → SchemaIR conversion for offline migration planning\nexport {\n contractNamespaceToSchemaIR,\n contractToSchemaIR,\n detectDestructiveChanges,\n resolveValueSetValues,\n} from '../core/migrations/contract-to-schema-ir';\nexport type { ControlPolicySubject } from '../core/migrations/control-policy';\nexport {\n controlPolicyForCall,\n partitionCallsByControlPolicy,\n partitionIssuesByControlPolicy,\n} from '../core/migrations/control-policy';\nexport type { PlanFieldEventOperationsOptions } from '../core/migrations/field-event-planner';\nexport { planFieldEventOperations } from '../core/migrations/field-event-planner';\nexport {\n createMigrationPlan,\n plannerFailure,\n plannerSuccess,\n runnerFailure,\n runnerSuccess,\n} from '../core/migrations/plan-helpers';\nexport { INIT_ADDITIVE_POLICY } from '../core/migrations/policies';\nexport type {\n CodecControlHooks,\n CreateSqlMigrationPlanOptions,\n ExpandNativeTypeInput,\n FieldEvent,\n FieldEventContext,\n ResolveIdentityValueInput,\n SqlControlAdapterDescriptor,\n SqlControlExtensionDescriptor,\n SqlMigrationPlan,\n SqlMigrationPlanContractInfo,\n SqlMigrationPlanner,\n SqlMigrationPlannerPlanOptions,\n SqlMigrationPlanOperation,\n SqlMigrationPlanOperationStep,\n SqlMigrationPlanOperationTarget,\n SqlMigrationRunner,\n SqlMigrationRunnerErrorCode,\n SqlMigrationRunnerExecuteCallbacks,\n SqlMigrationRunnerExecuteOptions,\n SqlMigrationRunnerFailure,\n SqlMigrationRunnerResult,\n SqlMigrationRunnerSuccessValue,\n SqlPlannerConflict,\n SqlPlannerConflictKind,\n SqlPlannerConflictLocation,\n SqlPlannerFailureResult,\n SqlPlannerResult,\n SqlPlannerSuccessResult,\n SqlPlanTargetDetails,\n StorageTypePlanResult,\n} from '../core/migrations/types';\nexport {\n temporalAuthoringPresets,\n timestampNowControlDescriptor,\n} from '../core/timestamp-now-generator';\n\nexport default new SqlFamilyDescriptor();\n"],"mappings":"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"}
package/dist/diff.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { a as verifySqlSchemaTree, i as verifySqlSchema, n as NativeTypeNormalizer, r as VerifySqlSchemaOptions } from "./sql-schema-diff-6z36dZt6.mjs";
2
2
  import { ControlPolicy } from "@prisma-next/contract/types";
3
3
  import { SchemaIssue } from "@prisma-next/framework-components/control";
4
- import { SqlIndexIR, SqlUniqueIR } from "@prisma-next/sql-schema-ir/types";
4
+ import { SqlForeignKeyIR, SqlIndexIR, SqlUniqueIR } from "@prisma-next/sql-schema-ir/types";
5
5
 
6
6
  //#region src/core/diff/verify-helpers.d.ts
7
7
  /**
@@ -1,4 +1,4 @@
1
- import { T as SqlPlanTargetDetails, p as SqlMigrationPlanOperation } from "./types-CkOIJXxU.mjs";
1
+ import { f as SqlMigrationPlanOperation, w as SqlPlanTargetDetails } from "./types-DBxrwN1d.mjs";
2
2
  import { Contract } from "@prisma-next/contract/types";
3
3
  import { SqlStorage } from "@prisma-next/sql-contract/types";
4
4
  import { Migration } from "@prisma-next/migration-tools/migration";
@@ -1,5 +1,5 @@
1
1
  import { ColumnDefault } from "@prisma-next/contract/types";
2
- import { SqlTableIR } from "@prisma-next/sql-schema-ir/types";
2
+ import { SqlForeignKeyIR, SqlTableIR } from "@prisma-next/sql-schema-ir/types";
3
3
 
4
4
  //#region src/core/psl-contract-infer/default-mapping.d.ts
5
5
  interface DefaultMappingOptions {
@@ -56,6 +56,18 @@ interface PslPrinterOptions {
56
56
  type RelationField = {
57
57
  readonly fieldName: string;
58
58
  readonly typeName: string;
59
+ /**
60
+ * Namespace qualifier for a cross-space relation (e.g. `"auth"` for a
61
+ * relation into `supabase:auth.AuthUser`). Absent for a same-namespace
62
+ * relation.
63
+ */
64
+ readonly typeNamespaceId?: string | undefined;
65
+ /**
66
+ * Contract-space qualifier for a relation into another stack extension
67
+ * pack's contract space (e.g. `"supabase"`). Absent for a same-space
68
+ * relation.
69
+ */
70
+ readonly typeContractSpaceId?: string | undefined;
59
71
  readonly referencedTableName?: string | undefined;
60
72
  readonly optional: boolean;
61
73
  readonly list: boolean;
@@ -75,6 +87,15 @@ type InferredRelations = {
75
87
  readonly relationsByTable: ReadonlyMap<string, readonly RelationField[]>;
76
88
  };
77
89
  declare function inferRelations(tables: Record<string, SqlTableIR>, modelNameMap: ReadonlyMap<string, string>): InferredRelations;
90
+ /**
91
+ * Builds the child-side {@link RelationField} for a single foreign key:
92
+ * `typeName` is the parent model name, `fields`/`references` are the FK's raw
93
+ * columns, and `onDelete`/`onUpdate` are normalized to their PSL spelling.
94
+ * Exported so a caller resolving a foreign key against a model outside
95
+ * `tables` (e.g. a cross-space reference into another contract) can reuse the
96
+ * same normalization instead of duplicating it.
97
+ */
98
+ declare function buildChildRelationField(fieldName: string, parentModelName: string, fk: SqlForeignKeyIR, optional: boolean, relationName?: string): RelationField;
78
99
  //#endregion
79
- export { type DefaultMappingOptions, type DefaultMappingResult, type EnumInfo, type InferredRelations, type PslNativeTypeAttribute, type PslPrinterOptions, type PslTypeMap, type PslTypeResolution, type RelationField, deriveBackRelationFieldName, deriveRelationFieldName, inferRelations, mapDefault, parseRawDefault, pluralize, toEnumName, toFieldName, toModelName, toNamedTypeName };
100
+ export { type DefaultMappingOptions, type DefaultMappingResult, type EnumInfo, type InferredRelations, type PslNativeTypeAttribute, type PslPrinterOptions, type PslTypeMap, type PslTypeResolution, type RelationField, buildChildRelationField, deriveBackRelationFieldName, deriveRelationFieldName, inferRelations, mapDefault, parseRawDefault, pluralize, toEnumName, toFieldName, toModelName, toNamedTypeName };
80
101
  //# sourceMappingURL=psl-infer.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"psl-infer.d.mts","names":[],"sources":["../src/core/psl-contract-infer/default-mapping.ts","../src/core/psl-contract-infer/name-transforms.ts","../src/core/psl-contract-infer/printer-config.ts","../src/core/psl-contract-infer/raw-default-parser.ts","../src/core/psl-contract-infer/relation-inference.ts"],"mappings":";;;;UAOiB,qBAAA;EAAA,SACN,kBAAA,GAAqB,QAAQ,CAAC,MAAA;EAAA,SAC9B,yBAAA,KAA8B,UAAA;AAAA;AAAA,KAG7B,oBAAA;EAAA,SAAkC,SAAA;AAAA;EAAA,SAAiC,OAAO;AAAA;AAAA,iBAEtE,UAAA,CACd,aAAA,EAAe,aAAA,EACf,OAAA,GAAU,qBAAA,GACT,oBAAA;;;KCbE,UAAA;EAAA,SACM,IAAA;EAAA,SACA,GAAG;AAAA;AAAA,iBA4DE,WAAA,CAAY,SAAA,WAAoB,UAAU;AAAA,iBAqB1C,WAAA,CAAY,UAAA,WAAqB,UAAU;AAAA,iBAqB3C,UAAA,CAAW,UAAA,WAAqB,UAAU;AAAA,iBAqB1C,SAAA,CAAU,IAAY;AAAA,iBAgBtB,uBAAA,CACd,SAAA,qBACA,mBAA2B;AAAA,iBAeb,2BAAA,CAA4B,cAAA,UAAwB,UAAmB;AAAA,iBAKvE,eAAA,CAAgB,UAAkB;;;KCpKtC,sBAAA;EAAA,SACD,IAAA;EAAA,SACA,IAAI;AAAA;AAAA,KAGH,iBAAA;EAAA,SAEG,OAAA;EAAA,SACA,UAAA;EAAA,SACA,UAAA,GAAa,MAAA;EAAA,SACb,mBAAA,GAAsB,sBAAsB;AAAA;EAAA,SAG5C,WAAA;EAAA,SACA,UAAA;AAAA;AAAA,UAGE,UAAA;EACf,OAAA,CAAQ,UAAA,UAAoB,WAAA,GAAc,MAAA,oBAA0B,iBAAiB;AAAA;AAAA,UAGtE,QAAA;EAAA,SACN,SAAA,EAAW,WAAA;EAAA,SACX,WAAA,EAAa,WAAW;AAAA;AAAA,UAGlB,iBAAA;EAAA,SACN,OAAA,EAAS,UAAA;EAAA,SACT,cAAA,GAAiB,qBAAA;EAAA,SACjB,QAAA,GAAW,QAAA;EAAA,SACX,eAAA,IAAmB,UAAA,UAAoB,UAAA,cAAwB,aAAA;AAAA;AAAA,KAG9D,aAAA;EAAA,SACD,SAAA;EAAA,SACA,QAAA;EAAA,SACA,mBAAA;EAAA,SACA,QAAA;EAAA,SACA,IAAA;EAAA,SACA,YAAA;EAAA,SACA,MAAA;EAAA,SACA,MAAA;EAAA,SACA,UAAA;EAAA,SACA,QAAA;EAAA,SACA,QAAA;AAAA;;;iBCVK,eAAA,CACd,UAAA,UACA,UAAA,YACC,aAAa;;;KCzBJ,iBAAA;EAAA,SACD,gBAAA,EAAkB,WAAW,kBAAkB,aAAA;AAAA;AAAA,iBAG1C,cAAA,CACd,MAAA,EAAQ,MAAA,SAAe,UAAA,GACvB,YAAA,EAAc,WAAA,mBACb,iBAAA"}
1
+ {"version":3,"file":"psl-infer.d.mts","names":[],"sources":["../src/core/psl-contract-infer/default-mapping.ts","../src/core/psl-contract-infer/name-transforms.ts","../src/core/psl-contract-infer/printer-config.ts","../src/core/psl-contract-infer/raw-default-parser.ts","../src/core/psl-contract-infer/relation-inference.ts"],"mappings":";;;;UAOiB,qBAAA;EAAA,SACN,kBAAA,GAAqB,QAAQ,CAAC,MAAA;EAAA,SAC9B,yBAAA,KAA8B,UAAA;AAAA;AAAA,KAG7B,oBAAA;EAAA,SAAkC,SAAA;AAAA;EAAA,SAAiC,OAAO;AAAA;AAAA,iBAEtE,UAAA,CACd,aAAA,EAAe,aAAA,EACf,OAAA,GAAU,qBAAA,GACT,oBAAA;;;KCbE,UAAA;EAAA,SACM,IAAA;EAAA,SACA,GAAG;AAAA;AAAA,iBA4DE,WAAA,CAAY,SAAA,WAAoB,UAAU;AAAA,iBAqB1C,WAAA,CAAY,UAAA,WAAqB,UAAU;AAAA,iBAqB3C,UAAA,CAAW,UAAA,WAAqB,UAAU;AAAA,iBAqB1C,SAAA,CAAU,IAAY;AAAA,iBAgBtB,uBAAA,CACd,SAAA,qBACA,mBAA2B;AAAA,iBAeb,2BAAA,CAA4B,cAAA,UAAwB,UAAmB;AAAA,iBAKvE,eAAA,CAAgB,UAAkB;;;KCpKtC,sBAAA;EAAA,SACD,IAAA;EAAA,SACA,IAAI;AAAA;AAAA,KAGH,iBAAA;EAAA,SAEG,OAAA;EAAA,SACA,UAAA;EAAA,SACA,UAAA,GAAa,MAAA;EAAA,SACb,mBAAA,GAAsB,sBAAsB;AAAA;EAAA,SAG5C,WAAA;EAAA,SACA,UAAA;AAAA;AAAA,UAGE,UAAA;EACf,OAAA,CAAQ,UAAA,UAAoB,WAAA,GAAc,MAAA,oBAA0B,iBAAiB;AAAA;AAAA,UAGtE,QAAA;EAAA,SACN,SAAA,EAAW,WAAA;EAAA,SACX,WAAA,EAAa,WAAW;AAAA;AAAA,UAGlB,iBAAA;EAAA,SACN,OAAA,EAAS,UAAA;EAAA,SACT,cAAA,GAAiB,qBAAA;EAAA,SACjB,QAAA,GAAW,QAAA;EAAA,SACX,eAAA,IAAmB,UAAA,UAAoB,UAAA,cAAwB,aAAA;AAAA;AAAA,KAG9D,aAAA;EAAA,SACD,SAAA;EAAA,SACA,QAAA;EFtBT;;;AACqB;;EADrB,SE4BS,eAAA;;;;;;WAMA,mBAAA;EAAA,SACA,mBAAA;EAAA,SACA,QAAA;EAAA,SACA,IAAA;EAAA,SACA,YAAA;EAAA,SACA,MAAA;EAAA,SACA,MAAA;EAAA,SACA,UAAA;EAAA,SACA,QAAA;EAAA,SACA,QAAA;AAAA;;;iBCtBK,eAAA,CACd,UAAA,UACA,UAAA,YACC,aAAa;;;KCzBJ,iBAAA;EAAA,SACD,gBAAA,EAAkB,WAAW,kBAAkB,aAAA;AAAA;AAAA,iBAG1C,cAAA,CACd,MAAA,EAAQ,MAAA,SAAe,UAAA,GACvB,YAAA,EAAc,WAAA,mBACb,iBAAA;;;;;;;;;iBA4Ha,uBAAA,CACd,SAAA,UACA,eAAA,UACA,EAAA,EAAI,eAAA,EACJ,QAAA,WACA,YAAA,YACC,aAAa"}
@@ -298,6 +298,14 @@ function deriveRelationName(fk, childRelationFieldName, parentModelName, isSelfR
298
298
  if (isSelfRelation) return `${childRelationFieldName.charAt(0).toUpperCase() + childRelationFieldName.slice(1)}${pluralize(parentModelName)}`;
299
299
  return fk.columns.join("_");
300
300
  }
301
+ /**
302
+ * Builds the child-side {@link RelationField} for a single foreign key:
303
+ * `typeName` is the parent model name, `fields`/`references` are the FK's raw
304
+ * columns, and `onDelete`/`onUpdate` are normalized to their PSL spelling.
305
+ * Exported so a caller resolving a foreign key against a model outside
306
+ * `tables` (e.g. a cross-space reference into another contract) can reuse the
307
+ * same normalization instead of duplicating it.
308
+ */
301
309
  function buildChildRelationField(fieldName, parentModelName, fk, optional, relationName) {
302
310
  const onDelete = fk.onDelete && fk.onDelete !== DEFAULT_ON_DELETE ? fk.onDelete : void 0;
303
311
  const onUpdate = fk.onUpdate && fk.onUpdate !== DEFAULT_ON_UPDATE ? fk.onUpdate : void 0;
@@ -329,6 +337,6 @@ function addRelationField(map, tableName, field) {
329
337
  else map.set(tableName, [field]);
330
338
  }
331
339
  //#endregion
332
- export { deriveBackRelationFieldName, deriveRelationFieldName, inferRelations, mapDefault, parseRawDefault, pluralize, toEnumName, toFieldName, toModelName, toNamedTypeName };
340
+ export { buildChildRelationField, deriveBackRelationFieldName, deriveRelationFieldName, inferRelations, mapDefault, parseRawDefault, pluralize, toEnumName, toFieldName, toModelName, toNamedTypeName };
333
341
 
334
342
  //# sourceMappingURL=psl-infer.mjs.map