@prisma-next/core-control-plane 0.1.0-dev.17 → 0.1.0-dev.18

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,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;\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;AAwErB,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
+ {"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';
@@ -1,5 +1,5 @@
1
+ import { 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';
@@ -124,7 +124,7 @@ interface MigrationPlanner {
124
124
  interface MigrationRunner {
125
125
  execute(options: {
126
126
  readonly plan: MigrationPlan;
127
- readonly driver: ControlDriverInstance;
127
+ readonly driver: ControlDriverInstance<string, string>;
128
128
  readonly destinationContract: unknown;
129
129
  readonly policy: MigrationOperationPolicy;
130
130
  readonly callbacks?: {
@@ -145,57 +145,134 @@ interface TargetMigrationsCapability<TFamilyInstance extends ControlFamilyInstan
145
145
  }
146
146
 
147
147
  /**
148
- * Base interface for control-plane family instances.
149
- * Families extend this with domain-specific methods.
148
+ * Control-plane family instance interface.
149
+ * Extends the base FamilyInstance with control-plane domain actions.
150
150
  *
151
151
  * @template TFamilyId - The family ID (e.g., 'sql', 'document')
152
+ * @template TSchemaIR - The schema IR type returned by introspect() (family-specific)
152
153
  */
153
- interface ControlFamilyInstance<TFamilyId extends string = string> {
154
- readonly familyId: TFamilyId;
154
+ interface ControlFamilyInstance<TFamilyId extends string, TSchemaIR = unknown> extends FamilyInstance<TFamilyId> {
155
+ /**
156
+ * Validates a contract JSON and returns a validated ContractIR (without mappings).
157
+ * Mappings are runtime-only and should not be part of ContractIR.
158
+ *
159
+ * Note: The returned ContractIR may include additional fields from the emitted contract
160
+ * (like coreHash, profileHash) that are not part of the ContractIR type but are preserved
161
+ * for use by verify/sign operations.
162
+ */
163
+ validateContractIR(contractJson: unknown): ContractIR;
164
+ /**
165
+ * Verifies the database marker against the contract.
166
+ * Compares target, coreHash, and profileHash.
167
+ *
168
+ * @param options.contractIR - The validated contract (from validateContractIR). Must have
169
+ * coreHash and target fields for verification. These fields are present in emitted
170
+ * contracts but not in the ContractIR type definition.
171
+ */
172
+ verify(options: {
173
+ readonly driver: ControlDriverInstance<TFamilyId, string>;
174
+ readonly contractIR: unknown;
175
+ readonly expectedTargetId: string;
176
+ readonly contractPath: string;
177
+ readonly configPath?: string;
178
+ }): Promise<VerifyDatabaseResult>;
179
+ /**
180
+ * Verifies the database schema against the contract.
181
+ * Compares contract requirements against live database schema.
182
+ */
183
+ schemaVerify(options: {
184
+ readonly driver: ControlDriverInstance<TFamilyId, string>;
185
+ readonly contractIR: unknown;
186
+ readonly strict: boolean;
187
+ readonly contractPath: string;
188
+ readonly configPath?: string;
189
+ }): Promise<VerifyDatabaseSchemaResult>;
190
+ /**
191
+ * Signs the database with the contract marker.
192
+ * Writes or updates the contract marker if schema verification passes.
193
+ * This operation is idempotent - if the marker already matches, no changes are made.
194
+ */
195
+ sign(options: {
196
+ readonly driver: ControlDriverInstance<TFamilyId, string>;
197
+ readonly contractIR: unknown;
198
+ readonly contractPath: string;
199
+ readonly configPath?: string;
200
+ }): Promise<SignDatabaseResult>;
201
+ /**
202
+ * Introspects the database schema and returns a family-specific schema IR.
203
+ *
204
+ * This is a read-only operation that returns a snapshot of the live database schema.
205
+ * The method is family-owned and delegates to target/adapter-specific introspectors
206
+ * to perform the actual schema introspection.
207
+ *
208
+ * @param options - Introspection options
209
+ * @param options.driver - Control plane driver for database connection
210
+ * @param options.contractIR - Optional contract for contract-guided introspection.
211
+ * When provided, families may use it for filtering, optimization, or validation
212
+ * during introspection. The contract does not change the meaning of "what exists"
213
+ * in the database - it only guides how introspection is performed.
214
+ * @returns Promise resolving to the family-specific Schema IR (e.g., `SqlSchemaIR` for SQL).
215
+ * The IR represents the complete schema snapshot at the time of introspection.
216
+ */
217
+ introspect(options: {
218
+ readonly driver: ControlDriverInstance<TFamilyId, string>;
219
+ readonly contractIR?: unknown;
220
+ }): Promise<TSchemaIR>;
221
+ /**
222
+ * Optionally projects a family-specific Schema IR into a core schema view.
223
+ * Families that provide this method enable rich tree output for CLI visualization.
224
+ * Families that do not provide it still support introspection via raw Schema IR.
225
+ */
226
+ toSchemaView?(schema: TSchemaIR): CoreSchemaView;
227
+ /**
228
+ * Emits contract JSON and DTS as strings.
229
+ * Uses the instance's preassembled state (operation registry, type imports, extension IDs).
230
+ * Handles stripping mappings and validation internally.
231
+ */
232
+ emitContract(options: {
233
+ readonly contractIR: ContractIR | unknown;
234
+ }): Promise<EmitContractResult>;
155
235
  }
156
236
  /**
157
- * Base interface for control-plane target instances.
237
+ * Control-plane target instance interface.
238
+ * Extends the base TargetInstance with control-plane specific behavior.
158
239
  *
159
240
  * @template TFamilyId - The family ID (e.g., 'sql', 'document')
160
241
  * @template TTargetId - The target ID (e.g., 'postgres', 'mysql')
161
242
  */
162
- interface ControlTargetInstance<TFamilyId extends string = string, TTargetId extends string = string> {
163
- readonly familyId: TFamilyId;
164
- readonly targetId: TTargetId;
243
+ interface ControlTargetInstance<TFamilyId extends string, TTargetId extends string> extends TargetInstance<TFamilyId, TTargetId> {
165
244
  }
166
245
  /**
167
- * Base interface for control-plane adapter instances.
246
+ * Control-plane adapter instance interface.
247
+ * Extends the base AdapterInstance with control-plane specific behavior.
168
248
  * Families extend this with family-specific adapter interfaces.
169
249
  *
170
250
  * @template TFamilyId - The family ID (e.g., 'sql', 'document')
171
251
  * @template TTargetId - The target ID (e.g., 'postgres', 'mysql')
172
252
  */
173
- interface ControlAdapterInstance<TFamilyId extends string = string, TTargetId extends string = string> {
174
- readonly familyId: TFamilyId;
175
- readonly targetId: TTargetId;
253
+ interface ControlAdapterInstance<TFamilyId extends string, TTargetId extends string> extends AdapterInstance<TFamilyId, TTargetId> {
176
254
  }
177
255
  /**
178
- * Base interface for control-plane driver instances.
179
- * Replaces ControlPlaneDriver with plane-first naming.
256
+ * Control-plane driver instance interface.
257
+ * Extends the base DriverInstance with control-plane specific behavior.
180
258
  *
259
+ * @template TFamilyId - The family ID (e.g., 'sql', 'document')
181
260
  * @template TTargetId - The target ID (e.g., 'postgres', 'mysql')
182
261
  */
183
- interface ControlDriverInstance<TTargetId extends string = string> {
184
- readonly targetId?: TTargetId;
262
+ interface ControlDriverInstance<TFamilyId extends string, TTargetId extends string> extends DriverInstance<TFamilyId, TTargetId> {
185
263
  query<Row = Record<string, unknown>>(sql: string, params?: readonly unknown[]): Promise<{
186
264
  readonly rows: Row[];
187
265
  }>;
188
266
  close(): Promise<void>;
189
267
  }
190
268
  /**
191
- * Base interface for control-plane extension instances.
269
+ * Control-plane extension instance interface.
270
+ * Extends the base ExtensionInstance with control-plane specific behavior.
192
271
  *
193
272
  * @template TFamilyId - The family ID (e.g., 'sql', 'document')
194
273
  * @template TTargetId - The target ID (e.g., 'postgres', 'mysql')
195
274
  */
196
- interface ControlExtensionInstance<TFamilyId extends string = string, TTargetId extends string = string> {
197
- readonly familyId: TFamilyId;
198
- readonly targetId: TTargetId;
275
+ interface ControlExtensionInstance<TFamilyId extends string, TTargetId extends string> extends ExtensionInstance<TFamilyId, TTargetId> {
199
276
  }
200
277
  /**
201
278
  * Operation context for propagating metadata through control-plane operation call chains.
@@ -239,11 +316,7 @@ interface OperationContext {
239
316
  * @template TFamilyId - The family ID (e.g., 'sql', 'document')
240
317
  * @template TFamilyInstance - The family instance type
241
318
  */
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;
319
+ interface ControlFamilyDescriptor<TFamilyId extends string, TFamilyInstance extends ControlFamilyInstance<TFamilyId> = ControlFamilyInstance<TFamilyId>> extends FamilyDescriptor<TFamilyId> {
247
320
  readonly hook: TargetFamilyHook;
248
321
  create<TTargetId extends string>(options: {
249
322
  readonly target: ControlTargetDescriptor<TFamilyId, TTargetId>;
@@ -253,19 +326,14 @@ interface ControlFamilyDescriptor<TFamilyId extends string, TFamilyInstance exte
253
326
  }): TFamilyInstance;
254
327
  }
255
328
  /**
256
- * Descriptor for a control-plane target pack (e.g., Postgres target).
329
+ * Descriptor for a control-plane target component (e.g., Postgres target).
257
330
  *
258
331
  * @template TFamilyId - The family ID (e.g., 'sql', 'document')
259
332
  * @template TTargetId - The target ID (e.g., 'postgres', 'mysql')
260
333
  * @template TTargetInstance - The target instance type
261
334
  * @template TFamilyInstance - The family instance type for migrations (optional)
262
335
  */
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;
336
+ 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
337
  /**
270
338
  * Optional migrations capability.
271
339
  * Targets that support migrations expose this property.
@@ -274,129 +342,35 @@ interface ControlTargetDescriptor<TFamilyId extends string, TTargetId extends st
274
342
  create(): TTargetInstance;
275
343
  }
276
344
  /**
277
- * Descriptor for a control-plane adapter pack (e.g., Postgres adapter).
345
+ * Descriptor for a control-plane adapter component (e.g., Postgres adapter).
278
346
  *
279
347
  * @template TFamilyId - The family ID (e.g., 'sql', 'document')
280
348
  * @template TTargetId - The target ID (e.g., 'postgres', 'mysql')
281
349
  * @template TAdapterInstance - The adapter instance type
282
350
  */
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;
351
+ interface ControlAdapterDescriptor<TFamilyId extends string, TTargetId extends string, TAdapterInstance extends ControlAdapterInstance<TFamilyId, TTargetId> = ControlAdapterInstance<TFamilyId, TTargetId>> extends AdapterDescriptor<TFamilyId, TTargetId> {
289
352
  create(): TAdapterInstance;
290
353
  }
291
354
  /**
292
- * Descriptor for a control-plane driver pack (e.g., Postgres driver).
355
+ * Descriptor for a control-plane driver component (e.g., Postgres driver).
293
356
  *
294
357
  * @template TFamilyId - The family ID (e.g., 'sql', 'document')
295
358
  * @template TTargetId - The target ID (e.g., 'postgres', 'mysql')
296
359
  * @template TDriverInstance - The driver instance type
297
360
  */
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;
361
+ interface ControlDriverDescriptor<TFamilyId extends string, TTargetId extends string, TDriverInstance extends ControlDriverInstance<TFamilyId, TTargetId> = ControlDriverInstance<TFamilyId, TTargetId>> extends DriverDescriptor<TFamilyId, TTargetId> {
304
362
  create(url: string): Promise<TDriverInstance>;
305
363
  }
306
364
  /**
307
- * Descriptor for a control-plane extension pack (e.g., pgvector).
365
+ * Descriptor for a control-plane extension component (e.g., pgvector).
308
366
  *
309
367
  * @template TFamilyId - The family ID (e.g., 'sql', 'document')
310
368
  * @template TTargetId - The target ID (e.g., 'postgres', 'mysql')
311
369
  * @template TExtensionInstance - The extension instance type
312
370
  */
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;
371
+ interface ControlExtensionDescriptor<TFamilyId extends string, TTargetId extends string, TExtensionInstance extends ControlExtensionInstance<TFamilyId, TTargetId> = ControlExtensionInstance<TFamilyId, TTargetId>> extends ExtensionDescriptor<TFamilyId, TTargetId> {
319
372
  create(): TExtensionInstance;
320
373
  }
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
374
  /**
401
375
  * Result type for database marker verification operations.
402
376
  */
@@ -502,7 +476,7 @@ interface EmitContractResult {
502
476
  *
503
477
  * @template TSchemaIR - The family-specific Schema IR type (e.g., `SqlSchemaIR` for SQL)
504
478
  */
505
- interface IntrospectSchemaResult<TSchemaIR = unknown> {
479
+ interface IntrospectSchemaResult<TSchemaIR> {
506
480
  readonly ok: true;
507
481
  readonly summary: string;
508
482
  readonly target: {
@@ -550,4 +524,4 @@ interface SignDatabaseResult {
550
524
  };
551
525
  }
552
526
 
553
- export type { ControlAdapterDescriptor, ControlAdapterInstance, ControlDriverDescriptor, ControlDriverInstance, ControlExtensionDescriptor, ControlExtensionInstance, ControlFamilyDescriptor, ControlFamilyInstance, ControlTargetDescriptor, ControlTargetInstance, EmitContractResult, FamilyInstance, IntrospectSchemaResult, MigrationOperationClass, MigrationOperationPolicy, MigrationPlan, MigrationPlanOperation, MigrationPlanner, MigrationPlannerConflict, MigrationPlannerFailureResult, MigrationPlannerResult, MigrationPlannerSuccessResult, MigrationRunner, MigrationRunnerFailure, MigrationRunnerResult, MigrationRunnerSuccessValue, OperationContext, SchemaIssue, SchemaVerificationNode, SignDatabaseResult, TargetMigrationsCapability, VerifyDatabaseResult, VerifyDatabaseSchemaResult };
527
+ 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,15 +1,15 @@
1
1
  {
2
2
  "name": "@prisma-next/core-control-plane",
3
- "version": "0.1.0-dev.17",
3
+ "version": "0.1.0-dev.18",
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-dev.17",
11
- "@prisma-next/operations": "0.1.0-dev.17",
12
- "@prisma-next/utils": "0.1.0-dev.17"
10
+ "@prisma-next/operations": "0.1.0-dev.18",
11
+ "@prisma-next/utils": "0.1.0-dev.18",
12
+ "@prisma-next/contract": "0.1.0-dev.18"
13
13
  },
14
14
  "devDependencies": {
15
15
  "tsup": "^8.3.0",