@prisma-next/core-control-plane 0.1.0-pr.49.3 → 0.1.0-pr.49.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -1
- package/dist/exports/config-types.d.ts +1 -1
- package/dist/exports/config-types.js.map +1 -1
- package/dist/exports/config-validation.d.ts +1 -1
- package/dist/exports/emission.js +0 -13
- package/dist/exports/emission.js.map +1 -1
- package/dist/exports/types.d.ts +143 -142
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -14,9 +14,10 @@ This package provides the core domain logic for control plane operations (contra
|
|
|
14
14
|
- **Domain Actions**:
|
|
15
15
|
- `verifyDatabase()`: Verifies database contract markers (accepts config object and ContractIR)
|
|
16
16
|
|
|
17
|
-
Note: Contract emission is implemented on family
|
|
17
|
+
Note: Contract emission is implemented on the SQL family instance (e.g., `familyInstance.emitContract()`), not as a core domain action.
|
|
18
18
|
- **Error Factories**: Domain error factories (`CliStructuredError`, config errors, runtime errors)
|
|
19
19
|
- **Pack Manifest Types**: Type definitions for extension pack manifests
|
|
20
|
+
- **Migration SPI**: Generic migration planner/runner interfaces (`MigrationPlanner<TFamilyId, TTargetId>`, `MigrationRunner<TFamilyId, TTargetId>`, `TargetMigrationsCapability<TFamilyId, TTargetId, TFamilyInstance>`) that thread family/target IDs for compile-time component compatibility enforcement
|
|
20
21
|
|
|
21
22
|
## Dependencies
|
|
22
23
|
|
|
@@ -102,6 +103,30 @@ throw errorConfigFileNotFound('prisma-next.config.ts', {
|
|
|
102
103
|
});
|
|
103
104
|
```
|
|
104
105
|
|
|
106
|
+
## Migration SPI Design
|
|
107
|
+
|
|
108
|
+
The migration planner/runner interfaces are generic over `TFamilyId` and `TTargetId` to enable compile-time enforcement of component compatibility:
|
|
109
|
+
|
|
110
|
+
- **`MigrationPlanner<TFamilyId, TTargetId>`**: Generic planner interface that accepts `TargetBoundComponentDescriptor<TFamilyId, TTargetId>[]`
|
|
111
|
+
- **`MigrationRunner<TFamilyId, TTargetId>`**: Generic runner interface that accepts `TargetBoundComponentDescriptor<TFamilyId, TTargetId>[]`
|
|
112
|
+
- **`TargetMigrationsCapability<TFamilyId, TTargetId, TFamilyInstance>`**: Generic capability interface for targets that support migrations
|
|
113
|
+
|
|
114
|
+
The CLI performs runtime validation at the composition boundary using `assertFrameworkComponentsCompatible()` before calling typed planner/runner instances. This validates that all components have matching `familyId` and `targetId`, then returns a typed `TargetBoundComponentDescriptor` array that satisfies the planner/runner interface requirements.
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
// CLI composition boundary - runtime assertion + type narrowing
|
|
118
|
+
const rawComponents = [config.target, config.adapter, ...(config.extensions ?? [])];
|
|
119
|
+
const frameworkComponents = assertFrameworkComponentsCompatible(
|
|
120
|
+
config.family.familyId,
|
|
121
|
+
config.target.targetId,
|
|
122
|
+
rawComponents,
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
// Now frameworkComponents is typed as TargetBoundComponentDescriptor<TFamilyId, TTargetId>[]
|
|
126
|
+
const planner = target.migrations.createPlanner(sqlFamilyInstance);
|
|
127
|
+
planner.plan({ contract, schema, policy, frameworkComponents });
|
|
128
|
+
```
|
|
129
|
+
|
|
105
130
|
## Package Location
|
|
106
131
|
|
|
107
132
|
This package is part of the **framework domain**, **core layer**, **migration plane**:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ControlFamilyDescriptor, ControlTargetDescriptor, ControlAdapterDescriptor, ControlExtensionDescriptor, ControlDriverDescriptor } from './types.js';
|
|
2
|
+
import '@prisma-next/contract/framework-components';
|
|
2
3
|
import '@prisma-next/contract/ir';
|
|
3
|
-
import '@prisma-next/contract/pack-manifest-types';
|
|
4
4
|
import '@prisma-next/contract/types';
|
|
5
5
|
import '@prisma-next/utils/result';
|
|
6
6
|
import './schema-view.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/config-types.ts"],"sourcesContent":["import { dirname, join } from 'node:path';\nimport { type } from 'arktype';\nimport type {\n ControlAdapterDescriptor,\n ControlDriverDescriptor,\n ControlDriverInstance,\n ControlExtensionDescriptor,\n ControlFamilyDescriptor,\n ControlTargetDescriptor,\n} from './types';\n\n/**\n * Type alias for CLI driver instances.\n */\nexport type CliDriver = ControlDriverInstance
|
|
1
|
+
{"version":3,"sources":["../../src/config-types.ts"],"sourcesContent":["import { dirname, join } from 'node:path';\nimport { type } from 'arktype';\nimport type {\n ControlAdapterDescriptor,\n ControlDriverDescriptor,\n ControlDriverInstance,\n ControlExtensionDescriptor,\n ControlFamilyDescriptor,\n ControlTargetDescriptor,\n} from './types';\n\n/**\n * Type alias for CLI driver instances.\n * Uses string for both family and target IDs for maximum flexibility.\n */\nexport type CliDriver = ControlDriverInstance<string, string>;\n\n/**\n * Contract configuration specifying source and artifact locations.\n */\nexport interface ContractConfig {\n /**\n * Contract source. Can be a value or a function that returns a value (sync or async).\n * If a function, it will be called to resolve the contract.\n */\n readonly source: unknown | (() => unknown | Promise<unknown>);\n /**\n * Path to contract.json artifact. Defaults to 'src/prisma/contract.json'.\n * This is the canonical location where other CLI commands can find the contract JSON.\n */\n readonly output?: string;\n /**\n * Path to contract.d.ts artifact. Defaults to output with .d.ts extension.\n * If output ends with .json, replaces .json with .d.ts.\n * Otherwise, appends .d.ts to the directory containing output.\n */\n readonly types?: string;\n}\n\n/**\n * Configuration for Prisma Next CLI.\n * Uses Control*Descriptor types for type-safe wiring with compile-time compatibility checks.\n *\n * @template TFamilyId - The family ID (e.g., 'sql', 'document')\n * @template TTargetId - The target ID (e.g., 'postgres', 'mysql')\n */\nexport interface PrismaNextConfig<\n TFamilyId extends string = string,\n TTargetId extends string = string,\n> {\n readonly family: ControlFamilyDescriptor<TFamilyId>;\n readonly target: ControlTargetDescriptor<TFamilyId, TTargetId>;\n readonly adapter: ControlAdapterDescriptor<TFamilyId, TTargetId>;\n readonly extensions?: readonly ControlExtensionDescriptor<TFamilyId, TTargetId>[];\n /**\n * Driver descriptor for DB-connected CLI commands.\n * Required for DB-connected commands (e.g., db verify).\n * Optional for commands that don't need database access (e.g., emit).\n */\n readonly driver?: ControlDriverDescriptor<TFamilyId, TTargetId>;\n readonly db?: {\n readonly url?: string;\n };\n /**\n * Contract configuration. Specifies source and artifact locations.\n * Required for emit command; optional for other commands that only read artifacts.\n */\n readonly contract?: ContractConfig;\n}\n\n/**\n * Arktype schema for ContractConfig validation.\n * Validates that source is present and output/types are strings when provided.\n */\nconst ContractConfigSchema = type({\n source: 'unknown', // Can be value or function - runtime check needed\n 'output?': 'string',\n 'types?': 'string',\n});\n\n/**\n * Arktype schema for PrismaNextConfig validation.\n * Note: This validates structure only. Descriptor objects (family, target, adapter) are validated separately.\n */\nconst PrismaNextConfigSchema = type({\n family: 'unknown', // ControlFamilyDescriptor - validated separately\n target: 'unknown', // ControlTargetDescriptor - validated separately\n adapter: 'unknown', // ControlAdapterDescriptor - validated separately\n 'extensions?': 'unknown[]',\n 'driver?': 'unknown', // ControlDriverDescriptor - validated separately (optional)\n 'db?': 'unknown',\n 'contract?': ContractConfigSchema,\n});\n\n/**\n * Helper function to define a Prisma Next config.\n * Validates and normalizes the config using Arktype, then returns the normalized IR.\n *\n * Normalization:\n * - contract.output defaults to 'src/prisma/contract.json' if missing\n * - contract.types defaults to output with .d.ts extension if missing\n *\n * @param config - Raw config input from user\n * @returns Normalized config IR with defaults applied\n * @throws Error if config structure is invalid\n */\nexport function defineConfig<TFamilyId extends string = string, TTargetId extends string = string>(\n config: PrismaNextConfig<TFamilyId, TTargetId>,\n): PrismaNextConfig<TFamilyId, TTargetId> {\n // Validate structure using Arktype\n const validated = PrismaNextConfigSchema(config);\n if (validated instanceof type.errors) {\n const messages = validated.map((p: { message: string }) => p.message).join('; ');\n throw new Error(`Config validation failed: ${messages}`);\n }\n\n // Normalize contract config if present\n if (config.contract) {\n // Validate contract.source is a value or function (runtime check)\n const source = config.contract.source;\n if (\n source !== null &&\n typeof source !== 'object' &&\n typeof source !== 'function' &&\n typeof source !== 'string' &&\n typeof source !== 'number' &&\n typeof source !== 'boolean'\n ) {\n throw new Error(\n 'Config.contract.source must be a value (object, string, number, boolean, null) or a function',\n );\n }\n\n // Apply defaults\n const output = config.contract.output ?? 'src/prisma/contract.json';\n const types =\n config.contract.types ??\n (output.endsWith('.json')\n ? `${output.slice(0, -5)}.d.ts`\n : join(dirname(output), 'contract.d.ts'));\n\n const normalizedContract: ContractConfig = {\n source: config.contract.source,\n output,\n types,\n };\n\n // Return normalized config\n return {\n ...config,\n contract: normalizedContract,\n };\n }\n\n // Return config as-is if no contract (preserve literal types)\n return config;\n}\n"],"mappings":";AAAA,SAAS,SAAS,YAAY;AAC9B,SAAS,YAAY;AAyErB,IAAM,uBAAuB,KAAK;AAAA,EAChC,QAAQ;AAAA;AAAA,EACR,WAAW;AAAA,EACX,UAAU;AACZ,CAAC;AAMD,IAAM,yBAAyB,KAAK;AAAA,EAClC,QAAQ;AAAA;AAAA,EACR,QAAQ;AAAA;AAAA,EACR,SAAS;AAAA;AAAA,EACT,eAAe;AAAA,EACf,WAAW;AAAA;AAAA,EACX,OAAO;AAAA,EACP,aAAa;AACf,CAAC;AAcM,SAAS,aACd,QACwC;AAExC,QAAM,YAAY,uBAAuB,MAAM;AAC/C,MAAI,qBAAqB,KAAK,QAAQ;AACpC,UAAM,WAAW,UAAU,IAAI,CAAC,MAA2B,EAAE,OAAO,EAAE,KAAK,IAAI;AAC/E,UAAM,IAAI,MAAM,6BAA6B,QAAQ,EAAE;AAAA,EACzD;AAGA,MAAI,OAAO,UAAU;AAEnB,UAAM,SAAS,OAAO,SAAS;AAC/B,QACE,WAAW,QACX,OAAO,WAAW,YAClB,OAAO,WAAW,cAClB,OAAO,WAAW,YAClB,OAAO,WAAW,YAClB,OAAO,WAAW,WAClB;AACA,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAGA,UAAM,SAAS,OAAO,SAAS,UAAU;AACzC,UAAM,QACJ,OAAO,SAAS,UACf,OAAO,SAAS,OAAO,IACpB,GAAG,OAAO,MAAM,GAAG,EAAE,CAAC,UACtB,KAAK,QAAQ,MAAM,GAAG,eAAe;AAE3C,UAAM,qBAAqC;AAAA,MACzC,QAAQ,OAAO,SAAS;AAAA,MACxB;AAAA,MACA;AAAA,IACF;AAGA,WAAO;AAAA,MACL,GAAG;AAAA,MACH,UAAU;AAAA,IACZ;AAAA,EACF;AAGA,SAAO;AACT;","names":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { PrismaNextConfig } from './config-types.js';
|
|
2
2
|
import './types.js';
|
|
3
|
+
import '@prisma-next/contract/framework-components';
|
|
3
4
|
import '@prisma-next/contract/ir';
|
|
4
|
-
import '@prisma-next/contract/pack-manifest-types';
|
|
5
5
|
import '@prisma-next/contract/types';
|
|
6
6
|
import '@prisma-next/utils/result';
|
|
7
7
|
import './schema-view.js';
|
package/dist/exports/emission.js
CHANGED
|
@@ -232,16 +232,6 @@ function validateCoreStructure(ir) {
|
|
|
232
232
|
throw new Error("ContractIR must have sources");
|
|
233
233
|
}
|
|
234
234
|
}
|
|
235
|
-
function validateExtensions(ir, extensionIds) {
|
|
236
|
-
const extensions = ir.extensions;
|
|
237
|
-
for (const extensionId of extensionIds) {
|
|
238
|
-
if (!extensions[extensionId]) {
|
|
239
|
-
throw new Error(
|
|
240
|
-
`Extension "${extensionId}" must appear in contract.extensions.${extensionId}`
|
|
241
|
-
);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
235
|
async function emit(ir, options, targetFamily) {
|
|
246
236
|
const { operationRegistry, codecTypeImports, operationTypeImports, extensionIds } = options;
|
|
247
237
|
validateCoreStructure(ir);
|
|
@@ -253,9 +243,6 @@ async function emit(ir, options, targetFamily) {
|
|
|
253
243
|
};
|
|
254
244
|
targetFamily.validateTypes(ir, ctx);
|
|
255
245
|
targetFamily.validateStructure(ir);
|
|
256
|
-
if (extensionIds) {
|
|
257
|
-
validateExtensions(ir, extensionIds);
|
|
258
|
-
}
|
|
259
246
|
const contractJson = {
|
|
260
247
|
schemaVersion: ir.schemaVersion,
|
|
261
248
|
targetFamily: ir.targetFamily,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/emission/canonicalization.ts","../../src/emission/emit.ts","../../src/emission/hashing.ts"],"sourcesContent":["import type { ContractIR } from '@prisma-next/contract/ir';\n\ntype NormalizedContract = {\n schemaVersion: string;\n targetFamily: string;\n target: string;\n coreHash?: string;\n profileHash?: string;\n models: Record<string, unknown>;\n relations: Record<string, unknown>;\n storage: Record<string, unknown>;\n extensions: Record<string, unknown>;\n capabilities: Record<string, Record<string, boolean>>;\n meta: Record<string, unknown>;\n sources: Record<string, unknown>;\n};\n\nconst TOP_LEVEL_ORDER = [\n 'schemaVersion',\n 'canonicalVersion',\n 'targetFamily',\n 'target',\n 'coreHash',\n 'profileHash',\n 'models',\n 'storage',\n 'capabilities',\n 'extensions',\n 'meta',\n 'sources',\n] as const;\n\nfunction isDefaultValue(value: unknown): boolean {\n if (value === false) return true;\n if (value === null) return false;\n if (Array.isArray(value) && value.length === 0) return true;\n if (typeof value === 'object' && value !== null) {\n const keys = Object.keys(value);\n return keys.length === 0;\n }\n return false;\n}\n\nfunction omitDefaults(obj: unknown, path: readonly string[]): unknown {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => omitDefaults(item, path));\n }\n\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n const currentPath = [...path, key];\n\n // Exclude metadata fields from canonicalization\n if (key === '_generated') {\n continue;\n }\n\n if (key === 'nullable' && value === false) {\n continue;\n }\n\n if (key === 'generated' && value === false) {\n continue;\n }\n\n if (isDefaultValue(value)) {\n const isRequiredModels = currentPath.length === 1 && currentPath[0] === 'models';\n const isRequiredTables =\n currentPath.length === 2 && currentPath[0] === 'storage' && currentPath[1] === 'tables';\n const isRequiredRelations = currentPath.length === 1 && currentPath[0] === 'relations';\n const isRequiredExtensions = currentPath.length === 1 && currentPath[0] === 'extensions';\n const isRequiredCapabilities = currentPath.length === 1 && currentPath[0] === 'capabilities';\n const isRequiredMeta = currentPath.length === 1 && currentPath[0] === 'meta';\n const isRequiredSources = currentPath.length === 1 && currentPath[0] === 'sources';\n const isExtensionNamespace = currentPath.length === 2 && currentPath[0] === 'extensions';\n const isModelRelations =\n currentPath.length === 3 && currentPath[0] === 'models' && currentPath[2] === 'relations';\n const isTableUniques =\n currentPath.length === 4 &&\n currentPath[0] === 'storage' &&\n currentPath[1] === 'tables' &&\n currentPath[3] === 'uniques';\n const isTableIndexes =\n currentPath.length === 4 &&\n currentPath[0] === 'storage' &&\n currentPath[1] === 'tables' &&\n currentPath[3] === 'indexes';\n const isTableForeignKeys =\n currentPath.length === 4 &&\n currentPath[0] === 'storage' &&\n currentPath[1] === 'tables' &&\n currentPath[3] === 'foreignKeys';\n\n if (\n !isRequiredModels &&\n !isRequiredTables &&\n !isRequiredRelations &&\n !isRequiredExtensions &&\n !isRequiredCapabilities &&\n !isRequiredMeta &&\n !isRequiredSources &&\n !isExtensionNamespace &&\n !isModelRelations &&\n !isTableUniques &&\n !isTableIndexes &&\n !isTableForeignKeys\n ) {\n continue;\n }\n }\n\n result[key] = omitDefaults(value, currentPath);\n }\n\n return result;\n}\n\nfunction sortObjectKeys(obj: unknown): unknown {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => sortObjectKeys(item));\n }\n\n const sorted: Record<string, unknown> = {};\n const keys = Object.keys(obj).sort();\n for (const key of keys) {\n sorted[key] = sortObjectKeys((obj as Record<string, unknown>)[key]);\n }\n\n return sorted;\n}\n\ntype StorageObject = {\n tables?: Record<string, unknown>;\n [key: string]: unknown;\n};\n\ntype TableObject = {\n indexes?: unknown[];\n uniques?: unknown[];\n [key: string]: unknown;\n};\n\nfunction sortIndexesAndUniques(storage: unknown): unknown {\n if (!storage || typeof storage !== 'object') {\n return storage;\n }\n\n const storageObj = storage as StorageObject;\n if (!storageObj.tables || typeof storageObj.tables !== 'object') {\n return storage;\n }\n\n const tables = storageObj.tables;\n const result: StorageObject = { ...storageObj };\n\n result.tables = {};\n // Sort table names to ensure deterministic ordering\n const sortedTableNames = Object.keys(tables).sort();\n for (const tableName of sortedTableNames) {\n const table = tables[tableName];\n if (!table || typeof table !== 'object') {\n result.tables[tableName] = table;\n continue;\n }\n\n const tableObj = table as TableObject;\n const sortedTable: TableObject = { ...tableObj };\n\n if (Array.isArray(tableObj.indexes)) {\n sortedTable.indexes = [...tableObj.indexes].sort((a, b) => {\n const nameA = (a as { name?: string })?.name || '';\n const nameB = (b as { name?: string })?.name || '';\n return nameA.localeCompare(nameB);\n });\n }\n\n if (Array.isArray(tableObj.uniques)) {\n sortedTable.uniques = [...tableObj.uniques].sort((a, b) => {\n const nameA = (a as { name?: string })?.name || '';\n const nameB = (b as { name?: string })?.name || '';\n return nameA.localeCompare(nameB);\n });\n }\n\n result.tables[tableName] = sortedTable;\n }\n\n return result;\n}\n\nfunction orderTopLevel(obj: Record<string, unknown>): Record<string, unknown> {\n const ordered: Record<string, unknown> = {};\n const remaining = new Set(Object.keys(obj));\n\n for (const key of TOP_LEVEL_ORDER) {\n if (remaining.has(key)) {\n ordered[key] = obj[key];\n remaining.delete(key);\n }\n }\n\n for (const key of Array.from(remaining).sort()) {\n ordered[key] = obj[key];\n }\n\n return ordered;\n}\n\nexport function canonicalizeContract(\n ir: ContractIR & { coreHash?: string; profileHash?: string },\n): string {\n const normalized: NormalizedContract = {\n schemaVersion: ir.schemaVersion,\n targetFamily: ir.targetFamily,\n target: ir.target,\n models: ir.models,\n relations: ir.relations,\n storage: ir.storage,\n extensions: ir.extensions,\n capabilities: ir.capabilities,\n meta: ir.meta,\n sources: ir.sources,\n };\n\n if (ir.coreHash !== undefined) {\n normalized.coreHash = ir.coreHash;\n }\n\n if (ir.profileHash !== undefined) {\n normalized.profileHash = ir.profileHash;\n }\n\n const withDefaultsOmitted = omitDefaults(normalized, []) as NormalizedContract;\n const withSortedIndexes = sortIndexesAndUniques(withDefaultsOmitted.storage);\n const withSortedStorage = { ...withDefaultsOmitted, storage: withSortedIndexes };\n const withSortedKeys = sortObjectKeys(withSortedStorage) as Record<string, unknown>;\n const withOrderedTopLevel = orderTopLevel(withSortedKeys);\n\n return JSON.stringify(withOrderedTopLevel, null, 2);\n}\n","import type { ContractIR } from '@prisma-next/contract/ir';\nimport type { TargetFamilyHook, ValidationContext } from '@prisma-next/contract/types';\nimport { format } from 'prettier';\nimport { canonicalizeContract } from './canonicalization';\nimport { computeCoreHash, computeProfileHash } from './hashing';\nimport type { EmitOptions, EmitResult } from './types';\n\nfunction validateCoreStructure(ir: ContractIR): void {\n if (!ir.targetFamily) {\n throw new Error('ContractIR must have targetFamily');\n }\n if (!ir.target) {\n throw new Error('ContractIR must have target');\n }\n if (!ir.schemaVersion) {\n throw new Error('ContractIR must have schemaVersion');\n }\n if (!ir.models || typeof ir.models !== 'object') {\n throw new Error('ContractIR must have models');\n }\n if (!ir.storage || typeof ir.storage !== 'object') {\n throw new Error('ContractIR must have storage');\n }\n if (!ir.relations || typeof ir.relations !== 'object') {\n throw new Error('ContractIR must have relations');\n }\n if (!ir.extensions || typeof ir.extensions !== 'object') {\n throw new Error('ContractIR must have extensions');\n }\n if (!ir.capabilities || typeof ir.capabilities !== 'object') {\n throw new Error('ContractIR must have capabilities');\n }\n if (!ir.meta || typeof ir.meta !== 'object') {\n throw new Error('ContractIR must have meta');\n }\n if (!ir.sources || typeof ir.sources !== 'object') {\n throw new Error('ContractIR must have sources');\n }\n}\n\nfunction validateExtensions(ir: ContractIR, extensionIds: ReadonlyArray<string>): void {\n const extensions = ir.extensions as Record<string, unknown>;\n for (const extensionId of extensionIds) {\n if (!extensions[extensionId]) {\n throw new Error(\n `Extension \"${extensionId}\" must appear in contract.extensions.${extensionId}`,\n );\n }\n }\n}\n\nexport async function emit(\n ir: ContractIR,\n options: EmitOptions,\n targetFamily: TargetFamilyHook,\n): Promise<EmitResult> {\n const { operationRegistry, codecTypeImports, operationTypeImports, extensionIds } = options;\n\n validateCoreStructure(ir);\n\n const ctx: ValidationContext = {\n ...(operationRegistry ? { operationRegistry } : {}),\n ...(codecTypeImports ? { codecTypeImports } : {}),\n ...(operationTypeImports ? { operationTypeImports } : {}),\n ...(extensionIds ? { extensionIds } : {}),\n };\n targetFamily.validateTypes(ir, ctx);\n\n targetFamily.validateStructure(ir);\n\n if (extensionIds) {\n validateExtensions(ir, extensionIds);\n }\n\n const contractJson = {\n schemaVersion: ir.schemaVersion,\n targetFamily: ir.targetFamily,\n target: ir.target,\n models: ir.models,\n relations: ir.relations,\n storage: ir.storage,\n extensions: ir.extensions,\n capabilities: ir.capabilities,\n meta: ir.meta,\n sources: ir.sources,\n } as const;\n\n const coreHash = computeCoreHash(contractJson);\n const profileHash = computeProfileHash(contractJson);\n\n const contractWithHashes: ContractIR & { coreHash?: string; profileHash?: string } = {\n ...ir,\n schemaVersion: contractJson.schemaVersion,\n coreHash,\n profileHash,\n };\n\n // Add _generated metadata to indicate this is a generated artifact\n // This ensures consistency between CLI emit and programmatic emit\n // Always add/update _generated with standard content for consistency\n const contractJsonObj = JSON.parse(canonicalizeContract(contractWithHashes)) as Record<\n string,\n unknown\n >;\n const contractJsonWithMeta = {\n ...contractJsonObj,\n _generated: {\n warning: '⚠️ GENERATED FILE - DO NOT EDIT',\n message: 'This file is automatically generated by \"prisma-next emit\".',\n regenerate: 'To regenerate, run: prisma-next emit',\n },\n };\n const contractJsonString = JSON.stringify(contractJsonWithMeta, null, 2);\n\n const contractDtsRaw = targetFamily.generateContractTypes(\n ir,\n codecTypeImports ?? [],\n operationTypeImports ?? [],\n );\n const contractDts = await format(contractDtsRaw, {\n parser: 'typescript',\n singleQuote: true,\n semi: true,\n printWidth: 100,\n });\n\n return {\n contractJson: contractJsonString,\n contractDts,\n coreHash,\n profileHash,\n };\n}\n","import { createHash } from 'node:crypto';\nimport type { ContractIR } from '@prisma-next/contract/ir';\nimport { canonicalizeContract } from './canonicalization';\n\ntype ContractInput = {\n schemaVersion: string;\n targetFamily: string;\n target: string;\n models: Record<string, unknown>;\n relations: Record<string, unknown>;\n storage: Record<string, unknown>;\n extensions: Record<string, unknown>;\n sources: Record<string, unknown>;\n capabilities: Record<string, Record<string, boolean>>;\n meta: Record<string, unknown>;\n [key: string]: unknown;\n};\n\nfunction computeHash(content: string): string {\n const hash = createHash('sha256');\n hash.update(content);\n return `sha256:${hash.digest('hex')}`;\n}\n\nexport function computeCoreHash(contract: ContractInput): string {\n const coreContract: ContractIR = {\n schemaVersion: contract.schemaVersion,\n targetFamily: contract.targetFamily,\n target: contract.target,\n models: contract.models,\n relations: contract.relations,\n storage: contract.storage,\n extensions: contract.extensions,\n sources: contract.sources,\n capabilities: contract.capabilities,\n meta: contract.meta,\n };\n const canonical = canonicalizeContract(coreContract);\n return computeHash(canonical);\n}\n\nexport function computeProfileHash(contract: ContractInput): string {\n const profileContract: ContractIR = {\n schemaVersion: contract.schemaVersion,\n targetFamily: contract.targetFamily,\n target: contract.target,\n models: {},\n relations: {},\n storage: {},\n extensions: {},\n capabilities: contract.capabilities,\n meta: {},\n sources: {},\n };\n const canonical = canonicalizeContract(profileContract);\n return computeHash(canonical);\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/emission/canonicalization.ts","../../src/emission/emit.ts","../../src/emission/hashing.ts"],"sourcesContent":["import type { ContractIR } from '@prisma-next/contract/ir';\n\ntype NormalizedContract = {\n schemaVersion: string;\n targetFamily: string;\n target: string;\n coreHash?: string;\n profileHash?: string;\n models: Record<string, unknown>;\n relations: Record<string, unknown>;\n storage: Record<string, unknown>;\n extensions: Record<string, unknown>;\n capabilities: Record<string, Record<string, boolean>>;\n meta: Record<string, unknown>;\n sources: Record<string, unknown>;\n};\n\nconst TOP_LEVEL_ORDER = [\n 'schemaVersion',\n 'canonicalVersion',\n 'targetFamily',\n 'target',\n 'coreHash',\n 'profileHash',\n 'models',\n 'storage',\n 'capabilities',\n 'extensions',\n 'meta',\n 'sources',\n] as const;\n\nfunction isDefaultValue(value: unknown): boolean {\n if (value === false) return true;\n if (value === null) return false;\n if (Array.isArray(value) && value.length === 0) return true;\n if (typeof value === 'object' && value !== null) {\n const keys = Object.keys(value);\n return keys.length === 0;\n }\n return false;\n}\n\nfunction omitDefaults(obj: unknown, path: readonly string[]): unknown {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => omitDefaults(item, path));\n }\n\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n const currentPath = [...path, key];\n\n // Exclude metadata fields from canonicalization\n if (key === '_generated') {\n continue;\n }\n\n if (key === 'nullable' && value === false) {\n continue;\n }\n\n if (key === 'generated' && value === false) {\n continue;\n }\n\n if (isDefaultValue(value)) {\n const isRequiredModels = currentPath.length === 1 && currentPath[0] === 'models';\n const isRequiredTables =\n currentPath.length === 2 && currentPath[0] === 'storage' && currentPath[1] === 'tables';\n const isRequiredRelations = currentPath.length === 1 && currentPath[0] === 'relations';\n const isRequiredExtensions = currentPath.length === 1 && currentPath[0] === 'extensions';\n const isRequiredCapabilities = currentPath.length === 1 && currentPath[0] === 'capabilities';\n const isRequiredMeta = currentPath.length === 1 && currentPath[0] === 'meta';\n const isRequiredSources = currentPath.length === 1 && currentPath[0] === 'sources';\n const isExtensionNamespace = currentPath.length === 2 && currentPath[0] === 'extensions';\n const isModelRelations =\n currentPath.length === 3 && currentPath[0] === 'models' && currentPath[2] === 'relations';\n const isTableUniques =\n currentPath.length === 4 &&\n currentPath[0] === 'storage' &&\n currentPath[1] === 'tables' &&\n currentPath[3] === 'uniques';\n const isTableIndexes =\n currentPath.length === 4 &&\n currentPath[0] === 'storage' &&\n currentPath[1] === 'tables' &&\n currentPath[3] === 'indexes';\n const isTableForeignKeys =\n currentPath.length === 4 &&\n currentPath[0] === 'storage' &&\n currentPath[1] === 'tables' &&\n currentPath[3] === 'foreignKeys';\n\n if (\n !isRequiredModels &&\n !isRequiredTables &&\n !isRequiredRelations &&\n !isRequiredExtensions &&\n !isRequiredCapabilities &&\n !isRequiredMeta &&\n !isRequiredSources &&\n !isExtensionNamespace &&\n !isModelRelations &&\n !isTableUniques &&\n !isTableIndexes &&\n !isTableForeignKeys\n ) {\n continue;\n }\n }\n\n result[key] = omitDefaults(value, currentPath);\n }\n\n return result;\n}\n\nfunction sortObjectKeys(obj: unknown): unknown {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => sortObjectKeys(item));\n }\n\n const sorted: Record<string, unknown> = {};\n const keys = Object.keys(obj).sort();\n for (const key of keys) {\n sorted[key] = sortObjectKeys((obj as Record<string, unknown>)[key]);\n }\n\n return sorted;\n}\n\ntype StorageObject = {\n tables?: Record<string, unknown>;\n [key: string]: unknown;\n};\n\ntype TableObject = {\n indexes?: unknown[];\n uniques?: unknown[];\n [key: string]: unknown;\n};\n\nfunction sortIndexesAndUniques(storage: unknown): unknown {\n if (!storage || typeof storage !== 'object') {\n return storage;\n }\n\n const storageObj = storage as StorageObject;\n if (!storageObj.tables || typeof storageObj.tables !== 'object') {\n return storage;\n }\n\n const tables = storageObj.tables;\n const result: StorageObject = { ...storageObj };\n\n result.tables = {};\n // Sort table names to ensure deterministic ordering\n const sortedTableNames = Object.keys(tables).sort();\n for (const tableName of sortedTableNames) {\n const table = tables[tableName];\n if (!table || typeof table !== 'object') {\n result.tables[tableName] = table;\n continue;\n }\n\n const tableObj = table as TableObject;\n const sortedTable: TableObject = { ...tableObj };\n\n if (Array.isArray(tableObj.indexes)) {\n sortedTable.indexes = [...tableObj.indexes].sort((a, b) => {\n const nameA = (a as { name?: string })?.name || '';\n const nameB = (b as { name?: string })?.name || '';\n return nameA.localeCompare(nameB);\n });\n }\n\n if (Array.isArray(tableObj.uniques)) {\n sortedTable.uniques = [...tableObj.uniques].sort((a, b) => {\n const nameA = (a as { name?: string })?.name || '';\n const nameB = (b as { name?: string })?.name || '';\n return nameA.localeCompare(nameB);\n });\n }\n\n result.tables[tableName] = sortedTable;\n }\n\n return result;\n}\n\nfunction orderTopLevel(obj: Record<string, unknown>): Record<string, unknown> {\n const ordered: Record<string, unknown> = {};\n const remaining = new Set(Object.keys(obj));\n\n for (const key of TOP_LEVEL_ORDER) {\n if (remaining.has(key)) {\n ordered[key] = obj[key];\n remaining.delete(key);\n }\n }\n\n for (const key of Array.from(remaining).sort()) {\n ordered[key] = obj[key];\n }\n\n return ordered;\n}\n\nexport function canonicalizeContract(\n ir: ContractIR & { coreHash?: string; profileHash?: string },\n): string {\n const normalized: NormalizedContract = {\n schemaVersion: ir.schemaVersion,\n targetFamily: ir.targetFamily,\n target: ir.target,\n models: ir.models,\n relations: ir.relations,\n storage: ir.storage,\n extensions: ir.extensions,\n capabilities: ir.capabilities,\n meta: ir.meta,\n sources: ir.sources,\n };\n\n if (ir.coreHash !== undefined) {\n normalized.coreHash = ir.coreHash;\n }\n\n if (ir.profileHash !== undefined) {\n normalized.profileHash = ir.profileHash;\n }\n\n const withDefaultsOmitted = omitDefaults(normalized, []) as NormalizedContract;\n const withSortedIndexes = sortIndexesAndUniques(withDefaultsOmitted.storage);\n const withSortedStorage = { ...withDefaultsOmitted, storage: withSortedIndexes };\n const withSortedKeys = sortObjectKeys(withSortedStorage) as Record<string, unknown>;\n const withOrderedTopLevel = orderTopLevel(withSortedKeys);\n\n return JSON.stringify(withOrderedTopLevel, null, 2);\n}\n","import type { ContractIR } from '@prisma-next/contract/ir';\nimport type { TargetFamilyHook, ValidationContext } from '@prisma-next/contract/types';\nimport { format } from 'prettier';\nimport { canonicalizeContract } from './canonicalization';\nimport { computeCoreHash, computeProfileHash } from './hashing';\nimport type { EmitOptions, EmitResult } from './types';\n\nfunction validateCoreStructure(ir: ContractIR): void {\n if (!ir.targetFamily) {\n throw new Error('ContractIR must have targetFamily');\n }\n if (!ir.target) {\n throw new Error('ContractIR must have target');\n }\n if (!ir.schemaVersion) {\n throw new Error('ContractIR must have schemaVersion');\n }\n if (!ir.models || typeof ir.models !== 'object') {\n throw new Error('ContractIR must have models');\n }\n if (!ir.storage || typeof ir.storage !== 'object') {\n throw new Error('ContractIR must have storage');\n }\n if (!ir.relations || typeof ir.relations !== 'object') {\n throw new Error('ContractIR must have relations');\n }\n if (!ir.extensions || typeof ir.extensions !== 'object') {\n throw new Error('ContractIR must have extensions');\n }\n if (!ir.capabilities || typeof ir.capabilities !== 'object') {\n throw new Error('ContractIR must have capabilities');\n }\n if (!ir.meta || typeof ir.meta !== 'object') {\n throw new Error('ContractIR must have meta');\n }\n if (!ir.sources || typeof ir.sources !== 'object') {\n throw new Error('ContractIR must have sources');\n }\n}\n\nexport async function emit(\n ir: ContractIR,\n options: EmitOptions,\n targetFamily: TargetFamilyHook,\n): Promise<EmitResult> {\n const { operationRegistry, codecTypeImports, operationTypeImports, extensionIds } = options;\n\n validateCoreStructure(ir);\n\n const ctx: ValidationContext = {\n ...(operationRegistry ? { operationRegistry } : {}),\n ...(codecTypeImports ? { codecTypeImports } : {}),\n ...(operationTypeImports ? { operationTypeImports } : {}),\n ...(extensionIds ? { extensionIds } : {}),\n };\n targetFamily.validateTypes(ir, ctx);\n\n targetFamily.validateStructure(ir);\n\n const contractJson = {\n schemaVersion: ir.schemaVersion,\n targetFamily: ir.targetFamily,\n target: ir.target,\n models: ir.models,\n relations: ir.relations,\n storage: ir.storage,\n extensions: ir.extensions,\n capabilities: ir.capabilities,\n meta: ir.meta,\n sources: ir.sources,\n } as const;\n\n const coreHash = computeCoreHash(contractJson);\n const profileHash = computeProfileHash(contractJson);\n\n const contractWithHashes: ContractIR & { coreHash?: string; profileHash?: string } = {\n ...ir,\n schemaVersion: contractJson.schemaVersion,\n coreHash,\n profileHash,\n };\n\n // Add _generated metadata to indicate this is a generated artifact\n // This ensures consistency between CLI emit and programmatic emit\n // Always add/update _generated with standard content for consistency\n const contractJsonObj = JSON.parse(canonicalizeContract(contractWithHashes)) as Record<\n string,\n unknown\n >;\n const contractJsonWithMeta = {\n ...contractJsonObj,\n _generated: {\n warning: '⚠️ GENERATED FILE - DO NOT EDIT',\n message: 'This file is automatically generated by \"prisma-next emit\".',\n regenerate: 'To regenerate, run: prisma-next emit',\n },\n };\n const contractJsonString = JSON.stringify(contractJsonWithMeta, null, 2);\n\n const contractDtsRaw = targetFamily.generateContractTypes(\n ir,\n codecTypeImports ?? [],\n operationTypeImports ?? [],\n );\n const contractDts = await format(contractDtsRaw, {\n parser: 'typescript',\n singleQuote: true,\n semi: true,\n printWidth: 100,\n });\n\n return {\n contractJson: contractJsonString,\n contractDts,\n coreHash,\n profileHash,\n };\n}\n","import { createHash } from 'node:crypto';\nimport type { ContractIR } from '@prisma-next/contract/ir';\nimport { canonicalizeContract } from './canonicalization';\n\ntype ContractInput = {\n schemaVersion: string;\n targetFamily: string;\n target: string;\n models: Record<string, unknown>;\n relations: Record<string, unknown>;\n storage: Record<string, unknown>;\n extensions: Record<string, unknown>;\n sources: Record<string, unknown>;\n capabilities: Record<string, Record<string, boolean>>;\n meta: Record<string, unknown>;\n [key: string]: unknown;\n};\n\nfunction computeHash(content: string): string {\n const hash = createHash('sha256');\n hash.update(content);\n return `sha256:${hash.digest('hex')}`;\n}\n\nexport function computeCoreHash(contract: ContractInput): string {\n const coreContract: ContractIR = {\n schemaVersion: contract.schemaVersion,\n targetFamily: contract.targetFamily,\n target: contract.target,\n models: contract.models,\n relations: contract.relations,\n storage: contract.storage,\n extensions: contract.extensions,\n sources: contract.sources,\n capabilities: contract.capabilities,\n meta: contract.meta,\n };\n const canonical = canonicalizeContract(coreContract);\n return computeHash(canonical);\n}\n\nexport function computeProfileHash(contract: ContractInput): string {\n const profileContract: ContractIR = {\n schemaVersion: contract.schemaVersion,\n targetFamily: contract.targetFamily,\n target: contract.target,\n models: {},\n relations: {},\n storage: {},\n extensions: {},\n capabilities: contract.capabilities,\n meta: {},\n sources: {},\n };\n const canonical = canonicalizeContract(profileContract);\n return computeHash(canonical);\n}\n"],"mappings":"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","names":[]}
|
package/dist/exports/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { TargetBoundComponentDescriptor, FamilyInstance, DriverInstance, FamilyDescriptor, TargetInstance, TargetDescriptor, AdapterInstance, AdapterDescriptor, DriverDescriptor, ExtensionInstance, ExtensionDescriptor } from '@prisma-next/contract/framework-components';
|
|
1
2
|
import { ContractIR } from '@prisma-next/contract/ir';
|
|
2
|
-
import { ExtensionPackManifest } from '@prisma-next/contract/pack-manifest-types';
|
|
3
3
|
import { TargetFamilyHook } from '@prisma-next/contract/types';
|
|
4
4
|
import { Result } from '@prisma-next/utils/result';
|
|
5
5
|
import { CoreSchemaView } from './schema-view.js';
|
|
@@ -109,93 +109,195 @@ type MigrationRunnerResult = Result<MigrationRunnerSuccessValue, MigrationRunner
|
|
|
109
109
|
/**
|
|
110
110
|
* Migration planner interface for planning schema changes.
|
|
111
111
|
* This is the minimal interface that CLI commands use.
|
|
112
|
+
*
|
|
113
|
+
* @template TFamilyId - The family ID (e.g., 'sql', 'document')
|
|
114
|
+
* @template TTargetId - The target ID (e.g., 'postgres', 'mysql')
|
|
112
115
|
*/
|
|
113
|
-
interface MigrationPlanner {
|
|
116
|
+
interface MigrationPlanner<TFamilyId extends string = string, TTargetId extends string = string> {
|
|
114
117
|
plan(options: {
|
|
115
118
|
readonly contract: unknown;
|
|
116
119
|
readonly schema: unknown;
|
|
117
120
|
readonly policy: MigrationOperationPolicy;
|
|
121
|
+
/**
|
|
122
|
+
* Active framework components participating in this composition.
|
|
123
|
+
* Families/targets can interpret this list to derive family-specific metadata.
|
|
124
|
+
* All components must have matching familyId and targetId.
|
|
125
|
+
*/
|
|
126
|
+
readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>>;
|
|
118
127
|
}): MigrationPlannerResult;
|
|
119
128
|
}
|
|
120
129
|
/**
|
|
121
130
|
* Migration runner interface for executing migration plans.
|
|
122
131
|
* This is the minimal interface that CLI commands use.
|
|
132
|
+
*
|
|
133
|
+
* @template TFamilyId - The family ID (e.g., 'sql', 'document')
|
|
134
|
+
* @template TTargetId - The target ID (e.g., 'postgres', 'mysql')
|
|
123
135
|
*/
|
|
124
|
-
interface MigrationRunner {
|
|
136
|
+
interface MigrationRunner<TFamilyId extends string = string, TTargetId extends string = string> {
|
|
125
137
|
execute(options: {
|
|
126
138
|
readonly plan: MigrationPlan;
|
|
127
|
-
readonly driver: ControlDriverInstance
|
|
139
|
+
readonly driver: ControlDriverInstance<TFamilyId, TTargetId>;
|
|
128
140
|
readonly destinationContract: unknown;
|
|
129
141
|
readonly policy: MigrationOperationPolicy;
|
|
130
142
|
readonly callbacks?: {
|
|
131
143
|
onOperationStart?(op: MigrationPlanOperation): void;
|
|
132
144
|
onOperationComplete?(op: MigrationPlanOperation): void;
|
|
133
145
|
};
|
|
146
|
+
/**
|
|
147
|
+
* Active framework components participating in this composition.
|
|
148
|
+
* Families/targets can interpret this list to derive family-specific metadata.
|
|
149
|
+
* All components must have matching familyId and targetId.
|
|
150
|
+
*/
|
|
151
|
+
readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>>;
|
|
134
152
|
}): Promise<MigrationRunnerResult>;
|
|
135
153
|
}
|
|
136
154
|
/**
|
|
137
155
|
* Optional capability interface for targets that support migrations.
|
|
138
156
|
* Targets that implement migrations expose this via their descriptor.
|
|
139
157
|
*
|
|
158
|
+
* @template TFamilyId - The family ID (e.g., 'sql', 'document')
|
|
159
|
+
* @template TTargetId - The target ID (e.g., 'postgres', 'mysql')
|
|
140
160
|
* @template TFamilyInstance - The family instance type (e.g., SqlControlFamilyInstance)
|
|
141
161
|
*/
|
|
142
|
-
interface TargetMigrationsCapability<TFamilyInstance extends ControlFamilyInstance<
|
|
143
|
-
createPlanner(family: TFamilyInstance): MigrationPlanner
|
|
144
|
-
createRunner(family: TFamilyInstance): MigrationRunner
|
|
162
|
+
interface TargetMigrationsCapability<TFamilyId extends string = string, TTargetId extends string = string, TFamilyInstance extends ControlFamilyInstance<TFamilyId> = ControlFamilyInstance<TFamilyId>> {
|
|
163
|
+
createPlanner(family: TFamilyInstance): MigrationPlanner<TFamilyId, TTargetId>;
|
|
164
|
+
createRunner(family: TFamilyInstance): MigrationRunner<TFamilyId, TTargetId>;
|
|
145
165
|
}
|
|
146
166
|
|
|
147
167
|
/**
|
|
148
|
-
*
|
|
149
|
-
*
|
|
168
|
+
* Control-plane family instance interface.
|
|
169
|
+
* Extends the base FamilyInstance with control-plane domain actions.
|
|
150
170
|
*
|
|
151
171
|
* @template TFamilyId - The family ID (e.g., 'sql', 'document')
|
|
172
|
+
* @template TSchemaIR - The schema IR type returned by introspect() (family-specific)
|
|
152
173
|
*/
|
|
153
|
-
interface ControlFamilyInstance<TFamilyId extends string =
|
|
154
|
-
|
|
174
|
+
interface ControlFamilyInstance<TFamilyId extends string, TSchemaIR = unknown> extends FamilyInstance<TFamilyId> {
|
|
175
|
+
/**
|
|
176
|
+
* Validates a contract JSON and returns a validated ContractIR (without mappings).
|
|
177
|
+
* Mappings are runtime-only and should not be part of ContractIR.
|
|
178
|
+
*
|
|
179
|
+
* Note: The returned ContractIR may include additional fields from the emitted contract
|
|
180
|
+
* (like coreHash, profileHash) that are not part of the ContractIR type but are preserved
|
|
181
|
+
* for use by verify/sign operations.
|
|
182
|
+
*/
|
|
183
|
+
validateContractIR(contractJson: unknown): ContractIR;
|
|
184
|
+
/**
|
|
185
|
+
* Verifies the database marker against the contract.
|
|
186
|
+
* Compares target, coreHash, and profileHash.
|
|
187
|
+
*
|
|
188
|
+
* @param options.contractIR - The validated contract (from validateContractIR). Must have
|
|
189
|
+
* coreHash and target fields for verification. These fields are present in emitted
|
|
190
|
+
* contracts but not in the ContractIR type definition.
|
|
191
|
+
*/
|
|
192
|
+
verify(options: {
|
|
193
|
+
readonly driver: ControlDriverInstance<TFamilyId, string>;
|
|
194
|
+
readonly contractIR: unknown;
|
|
195
|
+
readonly expectedTargetId: string;
|
|
196
|
+
readonly contractPath: string;
|
|
197
|
+
readonly configPath?: string;
|
|
198
|
+
}): Promise<VerifyDatabaseResult>;
|
|
199
|
+
/**
|
|
200
|
+
* Verifies the database schema against the contract.
|
|
201
|
+
* Compares contract requirements against live database schema.
|
|
202
|
+
*/
|
|
203
|
+
schemaVerify(options: {
|
|
204
|
+
readonly driver: ControlDriverInstance<TFamilyId, string>;
|
|
205
|
+
readonly contractIR: unknown;
|
|
206
|
+
readonly strict: boolean;
|
|
207
|
+
readonly contractPath: string;
|
|
208
|
+
readonly configPath?: string;
|
|
209
|
+
/**
|
|
210
|
+
* Active framework components participating in this composition.
|
|
211
|
+
* All components must have matching familyId and targetId.
|
|
212
|
+
*/
|
|
213
|
+
readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, string>>;
|
|
214
|
+
}): Promise<VerifyDatabaseSchemaResult>;
|
|
215
|
+
/**
|
|
216
|
+
* Signs the database with the contract marker.
|
|
217
|
+
* Writes or updates the contract marker if schema verification passes.
|
|
218
|
+
* This operation is idempotent - if the marker already matches, no changes are made.
|
|
219
|
+
*/
|
|
220
|
+
sign(options: {
|
|
221
|
+
readonly driver: ControlDriverInstance<TFamilyId, string>;
|
|
222
|
+
readonly contractIR: unknown;
|
|
223
|
+
readonly contractPath: string;
|
|
224
|
+
readonly configPath?: string;
|
|
225
|
+
}): Promise<SignDatabaseResult>;
|
|
226
|
+
/**
|
|
227
|
+
* Introspects the database schema and returns a family-specific schema IR.
|
|
228
|
+
*
|
|
229
|
+
* This is a read-only operation that returns a snapshot of the live database schema.
|
|
230
|
+
* The method is family-owned and delegates to target/adapter-specific introspectors
|
|
231
|
+
* to perform the actual schema introspection.
|
|
232
|
+
*
|
|
233
|
+
* @param options - Introspection options
|
|
234
|
+
* @param options.driver - Control plane driver for database connection
|
|
235
|
+
* @param options.contractIR - Optional contract for contract-guided introspection.
|
|
236
|
+
* When provided, families may use it for filtering, optimization, or validation
|
|
237
|
+
* during introspection. The contract does not change the meaning of "what exists"
|
|
238
|
+
* in the database - it only guides how introspection is performed.
|
|
239
|
+
* @returns Promise resolving to the family-specific Schema IR (e.g., `SqlSchemaIR` for SQL).
|
|
240
|
+
* The IR represents the complete schema snapshot at the time of introspection.
|
|
241
|
+
*/
|
|
242
|
+
introspect(options: {
|
|
243
|
+
readonly driver: ControlDriverInstance<TFamilyId, string>;
|
|
244
|
+
readonly contractIR?: unknown;
|
|
245
|
+
}): Promise<TSchemaIR>;
|
|
246
|
+
/**
|
|
247
|
+
* Optionally projects a family-specific Schema IR into a core schema view.
|
|
248
|
+
* Families that provide this method enable rich tree output for CLI visualization.
|
|
249
|
+
* Families that do not provide it still support introspection via raw Schema IR.
|
|
250
|
+
*/
|
|
251
|
+
toSchemaView?(schema: TSchemaIR): CoreSchemaView;
|
|
252
|
+
/**
|
|
253
|
+
* Emits contract JSON and DTS as strings.
|
|
254
|
+
* Uses the instance's preassembled state (operation registry, type imports, extension IDs).
|
|
255
|
+
* Handles stripping mappings and validation internally.
|
|
256
|
+
*/
|
|
257
|
+
emitContract(options: {
|
|
258
|
+
readonly contractIR: ContractIR | unknown;
|
|
259
|
+
}): Promise<EmitContractResult>;
|
|
155
260
|
}
|
|
156
261
|
/**
|
|
157
|
-
*
|
|
262
|
+
* Control-plane target instance interface.
|
|
263
|
+
* Extends the base TargetInstance with control-plane specific behavior.
|
|
158
264
|
*
|
|
159
265
|
* @template TFamilyId - The family ID (e.g., 'sql', 'document')
|
|
160
266
|
* @template TTargetId - The target ID (e.g., 'postgres', 'mysql')
|
|
161
267
|
*/
|
|
162
|
-
interface ControlTargetInstance<TFamilyId extends string
|
|
163
|
-
readonly familyId: TFamilyId;
|
|
164
|
-
readonly targetId: TTargetId;
|
|
268
|
+
interface ControlTargetInstance<TFamilyId extends string, TTargetId extends string> extends TargetInstance<TFamilyId, TTargetId> {
|
|
165
269
|
}
|
|
166
270
|
/**
|
|
167
|
-
*
|
|
271
|
+
* Control-plane adapter instance interface.
|
|
272
|
+
* Extends the base AdapterInstance with control-plane specific behavior.
|
|
168
273
|
* Families extend this with family-specific adapter interfaces.
|
|
169
274
|
*
|
|
170
275
|
* @template TFamilyId - The family ID (e.g., 'sql', 'document')
|
|
171
276
|
* @template TTargetId - The target ID (e.g., 'postgres', 'mysql')
|
|
172
277
|
*/
|
|
173
|
-
interface ControlAdapterInstance<TFamilyId extends string
|
|
174
|
-
readonly familyId: TFamilyId;
|
|
175
|
-
readonly targetId: TTargetId;
|
|
278
|
+
interface ControlAdapterInstance<TFamilyId extends string, TTargetId extends string> extends AdapterInstance<TFamilyId, TTargetId> {
|
|
176
279
|
}
|
|
177
280
|
/**
|
|
178
|
-
*
|
|
179
|
-
*
|
|
281
|
+
* Control-plane driver instance interface.
|
|
282
|
+
* Extends the base DriverInstance with control-plane specific behavior.
|
|
180
283
|
*
|
|
284
|
+
* @template TFamilyId - The family ID (e.g., 'sql', 'document')
|
|
181
285
|
* @template TTargetId - The target ID (e.g., 'postgres', 'mysql')
|
|
182
286
|
*/
|
|
183
|
-
interface ControlDriverInstance<
|
|
184
|
-
readonly targetId?: TTargetId;
|
|
287
|
+
interface ControlDriverInstance<TFamilyId extends string, TTargetId extends string> extends DriverInstance<TFamilyId, TTargetId> {
|
|
185
288
|
query<Row = Record<string, unknown>>(sql: string, params?: readonly unknown[]): Promise<{
|
|
186
289
|
readonly rows: Row[];
|
|
187
290
|
}>;
|
|
188
291
|
close(): Promise<void>;
|
|
189
292
|
}
|
|
190
293
|
/**
|
|
191
|
-
*
|
|
294
|
+
* Control-plane extension instance interface.
|
|
295
|
+
* Extends the base ExtensionInstance with control-plane specific behavior.
|
|
192
296
|
*
|
|
193
297
|
* @template TFamilyId - The family ID (e.g., 'sql', 'document')
|
|
194
298
|
* @template TTargetId - The target ID (e.g., 'postgres', 'mysql')
|
|
195
299
|
*/
|
|
196
|
-
interface ControlExtensionInstance<TFamilyId extends string
|
|
197
|
-
readonly familyId: TFamilyId;
|
|
198
|
-
readonly targetId: TTargetId;
|
|
300
|
+
interface ControlExtensionInstance<TFamilyId extends string, TTargetId extends string> extends ExtensionInstance<TFamilyId, TTargetId> {
|
|
199
301
|
}
|
|
200
302
|
/**
|
|
201
303
|
* Operation context for propagating metadata through control-plane operation call chains.
|
|
@@ -239,11 +341,7 @@ interface OperationContext {
|
|
|
239
341
|
* @template TFamilyId - The family ID (e.g., 'sql', 'document')
|
|
240
342
|
* @template TFamilyInstance - The family instance type
|
|
241
343
|
*/
|
|
242
|
-
interface ControlFamilyDescriptor<TFamilyId extends string, TFamilyInstance extends ControlFamilyInstance<TFamilyId> = ControlFamilyInstance<TFamilyId>> {
|
|
243
|
-
readonly kind: 'family';
|
|
244
|
-
readonly id: string;
|
|
245
|
-
readonly familyId: TFamilyId;
|
|
246
|
-
readonly manifest: ExtensionPackManifest;
|
|
344
|
+
interface ControlFamilyDescriptor<TFamilyId extends string, TFamilyInstance extends ControlFamilyInstance<TFamilyId> = ControlFamilyInstance<TFamilyId>> extends FamilyDescriptor<TFamilyId> {
|
|
247
345
|
readonly hook: TargetFamilyHook;
|
|
248
346
|
create<TTargetId extends string>(options: {
|
|
249
347
|
readonly target: ControlTargetDescriptor<TFamilyId, TTargetId>;
|
|
@@ -253,150 +351,53 @@ interface ControlFamilyDescriptor<TFamilyId extends string, TFamilyInstance exte
|
|
|
253
351
|
}): TFamilyInstance;
|
|
254
352
|
}
|
|
255
353
|
/**
|
|
256
|
-
* Descriptor for a control-plane target
|
|
354
|
+
* Descriptor for a control-plane target component (e.g., Postgres target).
|
|
257
355
|
*
|
|
258
356
|
* @template TFamilyId - The family ID (e.g., 'sql', 'document')
|
|
259
357
|
* @template TTargetId - The target ID (e.g., 'postgres', 'mysql')
|
|
260
358
|
* @template TTargetInstance - The target instance type
|
|
261
359
|
* @template TFamilyInstance - The family instance type for migrations (optional)
|
|
262
360
|
*/
|
|
263
|
-
interface ControlTargetDescriptor<TFamilyId extends string, TTargetId extends string, TTargetInstance extends ControlTargetInstance<TFamilyId, TTargetId> = ControlTargetInstance<TFamilyId, TTargetId>, TFamilyInstance extends ControlFamilyInstance<TFamilyId> = ControlFamilyInstance<TFamilyId>> {
|
|
264
|
-
readonly kind: 'target';
|
|
265
|
-
readonly id: string;
|
|
266
|
-
readonly familyId: TFamilyId;
|
|
267
|
-
readonly targetId: TTargetId;
|
|
268
|
-
readonly manifest: ExtensionPackManifest;
|
|
361
|
+
interface ControlTargetDescriptor<TFamilyId extends string, TTargetId extends string, TTargetInstance extends ControlTargetInstance<TFamilyId, TTargetId> = ControlTargetInstance<TFamilyId, TTargetId>, TFamilyInstance extends ControlFamilyInstance<TFamilyId> = ControlFamilyInstance<TFamilyId>> extends TargetDescriptor<TFamilyId, TTargetId> {
|
|
269
362
|
/**
|
|
270
363
|
* Optional migrations capability.
|
|
271
364
|
* Targets that support migrations expose this property.
|
|
365
|
+
* The capability is parameterized by family and target IDs to ensure type-level
|
|
366
|
+
* compatibility of framework components.
|
|
272
367
|
*/
|
|
273
|
-
readonly migrations?: TargetMigrationsCapability<TFamilyInstance>;
|
|
368
|
+
readonly migrations?: TargetMigrationsCapability<TFamilyId, TTargetId, TFamilyInstance>;
|
|
274
369
|
create(): TTargetInstance;
|
|
275
370
|
}
|
|
276
371
|
/**
|
|
277
|
-
* Descriptor for a control-plane adapter
|
|
372
|
+
* Descriptor for a control-plane adapter component (e.g., Postgres adapter).
|
|
278
373
|
*
|
|
279
374
|
* @template TFamilyId - The family ID (e.g., 'sql', 'document')
|
|
280
375
|
* @template TTargetId - The target ID (e.g., 'postgres', 'mysql')
|
|
281
376
|
* @template TAdapterInstance - The adapter instance type
|
|
282
377
|
*/
|
|
283
|
-
interface ControlAdapterDescriptor<TFamilyId extends string, TTargetId extends string, TAdapterInstance extends ControlAdapterInstance<TFamilyId, TTargetId> = ControlAdapterInstance<TFamilyId, TTargetId>> {
|
|
284
|
-
readonly kind: 'adapter';
|
|
285
|
-
readonly id: string;
|
|
286
|
-
readonly familyId: TFamilyId;
|
|
287
|
-
readonly targetId: TTargetId;
|
|
288
|
-
readonly manifest: ExtensionPackManifest;
|
|
378
|
+
interface ControlAdapterDescriptor<TFamilyId extends string, TTargetId extends string, TAdapterInstance extends ControlAdapterInstance<TFamilyId, TTargetId> = ControlAdapterInstance<TFamilyId, TTargetId>> extends AdapterDescriptor<TFamilyId, TTargetId> {
|
|
289
379
|
create(): TAdapterInstance;
|
|
290
380
|
}
|
|
291
381
|
/**
|
|
292
|
-
* Descriptor for a control-plane driver
|
|
382
|
+
* Descriptor for a control-plane driver component (e.g., Postgres driver).
|
|
293
383
|
*
|
|
294
384
|
* @template TFamilyId - The family ID (e.g., 'sql', 'document')
|
|
295
385
|
* @template TTargetId - The target ID (e.g., 'postgres', 'mysql')
|
|
296
386
|
* @template TDriverInstance - The driver instance type
|
|
297
387
|
*/
|
|
298
|
-
interface ControlDriverDescriptor<TFamilyId extends string, TTargetId extends string, TDriverInstance extends ControlDriverInstance<TTargetId> = ControlDriverInstance<TTargetId>> {
|
|
299
|
-
readonly kind: 'driver';
|
|
300
|
-
readonly id: string;
|
|
301
|
-
readonly familyId: TFamilyId;
|
|
302
|
-
readonly targetId: TTargetId;
|
|
303
|
-
readonly manifest: ExtensionPackManifest;
|
|
388
|
+
interface ControlDriverDescriptor<TFamilyId extends string, TTargetId extends string, TDriverInstance extends ControlDriverInstance<TFamilyId, TTargetId> = ControlDriverInstance<TFamilyId, TTargetId>> extends DriverDescriptor<TFamilyId, TTargetId> {
|
|
304
389
|
create(url: string): Promise<TDriverInstance>;
|
|
305
390
|
}
|
|
306
391
|
/**
|
|
307
|
-
* Descriptor for a control-plane extension
|
|
392
|
+
* Descriptor for a control-plane extension component (e.g., pgvector).
|
|
308
393
|
*
|
|
309
394
|
* @template TFamilyId - The family ID (e.g., 'sql', 'document')
|
|
310
395
|
* @template TTargetId - The target ID (e.g., 'postgres', 'mysql')
|
|
311
396
|
* @template TExtensionInstance - The extension instance type
|
|
312
397
|
*/
|
|
313
|
-
interface ControlExtensionDescriptor<TFamilyId extends string, TTargetId extends string, TExtensionInstance extends ControlExtensionInstance<TFamilyId, TTargetId> = ControlExtensionInstance<TFamilyId, TTargetId>> {
|
|
314
|
-
readonly kind: 'extension';
|
|
315
|
-
readonly id: string;
|
|
316
|
-
readonly familyId: TFamilyId;
|
|
317
|
-
readonly targetId: TTargetId;
|
|
318
|
-
readonly manifest: ExtensionPackManifest;
|
|
398
|
+
interface ControlExtensionDescriptor<TFamilyId extends string, TTargetId extends string, TExtensionInstance extends ControlExtensionInstance<TFamilyId, TTargetId> = ControlExtensionInstance<TFamilyId, TTargetId>> extends ExtensionDescriptor<TFamilyId, TTargetId> {
|
|
319
399
|
create(): TExtensionInstance;
|
|
320
400
|
}
|
|
321
|
-
/**
|
|
322
|
-
* Family instance interface for control-plane domain actions.
|
|
323
|
-
* Each family implements this interface with family-specific types.
|
|
324
|
-
*/
|
|
325
|
-
interface FamilyInstance<TFamilyId extends string, TSchemaIR = unknown, TVerifyResult = unknown, TSchemaVerifyResult = unknown, TSignResult = unknown> {
|
|
326
|
-
readonly familyId: TFamilyId;
|
|
327
|
-
/**
|
|
328
|
-
* Validates a contract JSON and returns a validated ContractIR (without mappings).
|
|
329
|
-
* Mappings are runtime-only and should not be part of ContractIR.
|
|
330
|
-
*/
|
|
331
|
-
validateContractIR(contractJson: unknown): unknown;
|
|
332
|
-
/**
|
|
333
|
-
* Verifies the database marker against the contract.
|
|
334
|
-
* Compares target, coreHash, and profileHash.
|
|
335
|
-
*/
|
|
336
|
-
verify(options: {
|
|
337
|
-
readonly driver: ControlDriverInstance;
|
|
338
|
-
readonly contractIR: unknown;
|
|
339
|
-
readonly expectedTargetId: string;
|
|
340
|
-
readonly contractPath: string;
|
|
341
|
-
readonly configPath?: string;
|
|
342
|
-
}): Promise<TVerifyResult>;
|
|
343
|
-
/**
|
|
344
|
-
* Verifies the database schema against the contract.
|
|
345
|
-
* Compares contract requirements against live database schema.
|
|
346
|
-
*/
|
|
347
|
-
schemaVerify(options: {
|
|
348
|
-
readonly driver: ControlDriverInstance;
|
|
349
|
-
readonly contractIR: unknown;
|
|
350
|
-
readonly strict: boolean;
|
|
351
|
-
readonly contractPath: string;
|
|
352
|
-
readonly configPath?: string;
|
|
353
|
-
}): Promise<TSchemaVerifyResult>;
|
|
354
|
-
/**
|
|
355
|
-
* Signs the database with the contract marker.
|
|
356
|
-
* Writes or updates the contract marker if schema verification passes.
|
|
357
|
-
* This operation is idempotent - if the marker already matches, no changes are made.
|
|
358
|
-
*/
|
|
359
|
-
sign(options: {
|
|
360
|
-
readonly driver: ControlDriverInstance;
|
|
361
|
-
readonly contractIR: unknown;
|
|
362
|
-
readonly contractPath: string;
|
|
363
|
-
readonly configPath?: string;
|
|
364
|
-
}): Promise<TSignResult>;
|
|
365
|
-
/**
|
|
366
|
-
* Introspects the database schema and returns a family-specific schema IR.
|
|
367
|
-
*
|
|
368
|
-
* This is a read-only operation that returns a snapshot of the live database schema.
|
|
369
|
-
* The method is family-owned and delegates to target/adapter-specific introspectors
|
|
370
|
-
* to perform the actual schema introspection.
|
|
371
|
-
*
|
|
372
|
-
* @param options - Introspection options
|
|
373
|
-
* @param options.driver - Control plane driver for database connection
|
|
374
|
-
* @param options.contractIR - Optional contract IR for contract-guided introspection.
|
|
375
|
-
* When provided, families may use it for filtering, optimization, or validation
|
|
376
|
-
* during introspection. The contract IR does not change the meaning of "what exists"
|
|
377
|
-
* in the database - it only guides how introspection is performed.
|
|
378
|
-
* @returns Promise resolving to the family-specific Schema IR (e.g., `SqlSchemaIR` for SQL).
|
|
379
|
-
* The IR represents the complete schema snapshot at the time of introspection.
|
|
380
|
-
*/
|
|
381
|
-
introspect(options: {
|
|
382
|
-
readonly driver: ControlDriverInstance;
|
|
383
|
-
readonly contractIR?: unknown;
|
|
384
|
-
}): Promise<TSchemaIR>;
|
|
385
|
-
/**
|
|
386
|
-
* Optionally projects a family-specific Schema IR into a core schema view.
|
|
387
|
-
* Families that provide this method enable rich tree output for CLI visualization.
|
|
388
|
-
* Families that do not provide it still support introspection via raw Schema IR.
|
|
389
|
-
*/
|
|
390
|
-
toSchemaView?(schema: TSchemaIR): CoreSchemaView;
|
|
391
|
-
/**
|
|
392
|
-
* Emits contract JSON and DTS as strings.
|
|
393
|
-
* Uses the instance's preassembled state (operation registry, type imports, extension IDs).
|
|
394
|
-
* Handles stripping mappings and validation internally.
|
|
395
|
-
*/
|
|
396
|
-
emitContract(options: {
|
|
397
|
-
readonly contractIR: ContractIR | unknown;
|
|
398
|
-
}): Promise<EmitContractResult>;
|
|
399
|
-
}
|
|
400
401
|
/**
|
|
401
402
|
* Result type for database marker verification operations.
|
|
402
403
|
*/
|
|
@@ -502,7 +503,7 @@ interface EmitContractResult {
|
|
|
502
503
|
*
|
|
503
504
|
* @template TSchemaIR - The family-specific Schema IR type (e.g., `SqlSchemaIR` for SQL)
|
|
504
505
|
*/
|
|
505
|
-
interface IntrospectSchemaResult<TSchemaIR
|
|
506
|
+
interface IntrospectSchemaResult<TSchemaIR> {
|
|
506
507
|
readonly ok: true;
|
|
507
508
|
readonly summary: string;
|
|
508
509
|
readonly target: {
|
|
@@ -550,4 +551,4 @@ interface SignDatabaseResult {
|
|
|
550
551
|
};
|
|
551
552
|
}
|
|
552
553
|
|
|
553
|
-
export type { ControlAdapterDescriptor, ControlAdapterInstance, ControlDriverDescriptor, ControlDriverInstance, ControlExtensionDescriptor, ControlExtensionInstance, ControlFamilyDescriptor, ControlFamilyInstance, ControlTargetDescriptor, ControlTargetInstance, EmitContractResult,
|
|
554
|
+
export type { ControlAdapterDescriptor, ControlAdapterInstance, ControlDriverDescriptor, ControlDriverInstance, ControlExtensionDescriptor, ControlExtensionInstance, ControlFamilyDescriptor, ControlFamilyInstance, ControlTargetDescriptor, ControlTargetInstance, EmitContractResult, IntrospectSchemaResult, MigrationOperationClass, MigrationOperationPolicy, MigrationPlan, MigrationPlanOperation, MigrationPlanner, MigrationPlannerConflict, MigrationPlannerFailureResult, MigrationPlannerResult, MigrationPlannerSuccessResult, MigrationRunner, MigrationRunnerFailure, MigrationRunnerResult, MigrationRunnerSuccessValue, OperationContext, SchemaIssue, SchemaVerificationNode, SignDatabaseResult, TargetMigrationsCapability, VerifyDatabaseResult, VerifyDatabaseSchemaResult };
|
package/package.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/core-control-plane",
|
|
3
|
-
"version": "0.1.0-pr.49.
|
|
3
|
+
"version": "0.1.0-pr.49.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"description": "Control plane domain actions, config types, validation, and error factories for Prisma Next",
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"arktype": "^2.1.26",
|
|
9
9
|
"prettier": "^3.3.3",
|
|
10
|
-
"@prisma-next/contract": "0.1.0-pr.49.
|
|
11
|
-
"@prisma-next/
|
|
12
|
-
"@prisma-next/
|
|
10
|
+
"@prisma-next/contract": "0.1.0-pr.49.5",
|
|
11
|
+
"@prisma-next/utils": "0.1.0-pr.49.5",
|
|
12
|
+
"@prisma-next/operations": "0.1.0-pr.49.5"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"tsup": "^8.3.0",
|
|
16
16
|
"typescript": "^5.9.3",
|
|
17
|
-
"vitest": "^
|
|
17
|
+
"vitest": "^4.0.16",
|
|
18
18
|
"@prisma-next/test-utils": "0.0.1"
|
|
19
19
|
},
|
|
20
20
|
"files": [
|