@prisma-next/cli 0.3.0-dev.17 → 0.3.0-dev.19

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.
Files changed (58) hide show
  1. package/dist/{chunk-ZG5T6OB5.js → chunk-AGOTG4L3.js} +43 -1
  2. package/dist/chunk-AGOTG4L3.js.map +1 -0
  3. package/dist/chunk-HLLI4YL7.js +180 -0
  4. package/dist/chunk-HLLI4YL7.js.map +1 -0
  5. package/dist/chunk-VG2R7DGF.js +735 -0
  6. package/dist/chunk-VG2R7DGF.js.map +1 -0
  7. package/dist/cli.js +1621 -1382
  8. package/dist/cli.js.map +1 -1
  9. package/dist/commands/contract-emit.d.ts.map +1 -1
  10. package/dist/commands/contract-emit.js +3 -4
  11. package/dist/commands/db-init.js +4 -49
  12. package/dist/commands/db-init.js.map +1 -1
  13. package/dist/commands/db-introspect.d.ts.map +1 -1
  14. package/dist/commands/db-introspect.js +106 -136
  15. package/dist/commands/db-introspect.js.map +1 -1
  16. package/dist/commands/db-schema-verify.d.ts.map +1 -1
  17. package/dist/commands/db-schema-verify.js +118 -110
  18. package/dist/commands/db-schema-verify.js.map +1 -1
  19. package/dist/commands/db-sign.d.ts.map +1 -1
  20. package/dist/commands/db-sign.js +150 -153
  21. package/dist/commands/db-sign.js.map +1 -1
  22. package/dist/commands/db-verify.d.ts.map +1 -1
  23. package/dist/commands/db-verify.js +140 -119
  24. package/dist/commands/db-verify.js.map +1 -1
  25. package/dist/control-api/client.d.ts.map +1 -1
  26. package/dist/control-api/types.d.ts +132 -1
  27. package/dist/control-api/types.d.ts.map +1 -1
  28. package/dist/exports/control-api.d.ts +1 -1
  29. package/dist/exports/control-api.d.ts.map +1 -1
  30. package/dist/exports/control-api.js +1 -3
  31. package/dist/exports/index.js +3 -4
  32. package/dist/exports/index.js.map +1 -1
  33. package/package.json +10 -10
  34. package/src/commands/contract-emit.ts +179 -102
  35. package/src/commands/db-introspect.ts +151 -178
  36. package/src/commands/db-schema-verify.ts +150 -143
  37. package/src/commands/db-sign.ts +202 -196
  38. package/src/commands/db-verify.ts +179 -149
  39. package/src/control-api/client.ts +352 -22
  40. package/src/control-api/types.ts +149 -1
  41. package/src/exports/control-api.ts +9 -0
  42. package/dist/chunk-5MPKZYVI.js +0 -47
  43. package/dist/chunk-5MPKZYVI.js.map +0 -1
  44. package/dist/chunk-6EPKRATC.js +0 -91
  45. package/dist/chunk-6EPKRATC.js.map +0 -1
  46. package/dist/chunk-74IELXRA.js +0 -371
  47. package/dist/chunk-74IELXRA.js.map +0 -1
  48. package/dist/chunk-U6QI3AZ3.js +0 -133
  49. package/dist/chunk-U6QI3AZ3.js.map +0 -1
  50. package/dist/chunk-VI2YETW7.js +0 -38
  51. package/dist/chunk-VI2YETW7.js.map +0 -1
  52. package/dist/chunk-ZG5T6OB5.js.map +0 -1
  53. package/dist/utils/action.d.ts +0 -16
  54. package/dist/utils/action.d.ts.map +0 -1
  55. package/dist/utils/spinner.d.ts +0 -29
  56. package/dist/utils/spinner.d.ts.map +0 -1
  57. package/src/utils/action.ts +0 -43
  58. package/src/utils/spinner.ts +0 -67
@@ -1,4 +1,5 @@
1
1
  import type { TargetBoundComponentDescriptor } from '@prisma-next/contract/framework-components';
2
+ import type { CoreSchemaView } from '@prisma-next/core-control-plane/schema-view';
2
3
  import { createControlPlaneStack } from '@prisma-next/core-control-plane/stack';
3
4
  import type {
4
5
  ControlDriverInstance,
@@ -8,6 +9,7 @@ import type {
8
9
  VerifyDatabaseResult,
9
10
  VerifyDatabaseSchemaResult,
10
11
  } from '@prisma-next/core-control-plane/types';
12
+ import { notOk, ok } from '@prisma-next/utils/result';
11
13
  import { assertFrameworkComponentsCompatible } from '../utils/framework-components';
12
14
  import { executeDbInit } from './operations/db-init';
13
15
  import type {
@@ -15,6 +17,8 @@ import type {
15
17
  ControlClientOptions,
16
18
  DbInitOptions,
17
19
  DbInitResult,
20
+ EmitOptions,
21
+ EmitResult,
18
22
  IntrospectOptions,
19
23
  SchemaVerifyOptions,
20
24
  SignOptions,
@@ -148,51 +152,220 @@ class ControlClientImpl implements ControlClient {
148
152
  }
149
153
 
150
154
  async verify(options: VerifyOptions): Promise<VerifyDatabaseResult> {
155
+ const { onProgress } = options;
156
+
157
+ // Connect with progress span if connection provided
158
+ if (options.connection !== undefined) {
159
+ onProgress?.({
160
+ action: 'verify',
161
+ kind: 'spanStart',
162
+ spanId: 'connect',
163
+ label: 'Connecting to database...',
164
+ });
165
+ try {
166
+ await this.connect(options.connection);
167
+ onProgress?.({
168
+ action: 'verify',
169
+ kind: 'spanEnd',
170
+ spanId: 'connect',
171
+ outcome: 'ok',
172
+ });
173
+ } catch (error) {
174
+ onProgress?.({
175
+ action: 'verify',
176
+ kind: 'spanEnd',
177
+ spanId: 'connect',
178
+ outcome: 'error',
179
+ });
180
+ throw error;
181
+ }
182
+ }
183
+
151
184
  const { driver, familyInstance } = await this.ensureConnected();
152
185
 
153
186
  // Validate contract using family instance
154
187
  const contractIR = familyInstance.validateContractIR(options.contractIR);
155
188
 
156
- // Delegate to family instance verify method
157
- // Note: We pass empty strings for contractPath/configPath since the programmatic
158
- // API doesn't deal with file paths. The family instance accepts these as optional
159
- // metadata for error reporting.
160
- return familyInstance.verify({
161
- driver,
162
- contractIR,
163
- expectedTargetId: this.options.target.targetId,
164
- contractPath: '',
189
+ // Emit verify span
190
+ onProgress?.({
191
+ action: 'verify',
192
+ kind: 'spanStart',
193
+ spanId: 'verify',
194
+ label: 'Verifying contract marker...',
165
195
  });
196
+
197
+ try {
198
+ // Delegate to family instance verify method
199
+ // Note: We pass empty strings for contractPath/configPath since the programmatic
200
+ // API doesn't deal with file paths. The family instance accepts these as optional
201
+ // metadata for error reporting.
202
+ const result = await familyInstance.verify({
203
+ driver,
204
+ contractIR,
205
+ expectedTargetId: this.options.target.targetId,
206
+ contractPath: '',
207
+ });
208
+
209
+ onProgress?.({
210
+ action: 'verify',
211
+ kind: 'spanEnd',
212
+ spanId: 'verify',
213
+ outcome: result.ok ? 'ok' : 'error',
214
+ });
215
+
216
+ return result;
217
+ } catch (error) {
218
+ onProgress?.({
219
+ action: 'verify',
220
+ kind: 'spanEnd',
221
+ spanId: 'verify',
222
+ outcome: 'error',
223
+ });
224
+ throw error;
225
+ }
166
226
  }
167
227
 
168
228
  async schemaVerify(options: SchemaVerifyOptions): Promise<VerifyDatabaseSchemaResult> {
229
+ const { onProgress } = options;
230
+
231
+ // Connect with progress span if connection provided
232
+ if (options.connection !== undefined) {
233
+ onProgress?.({
234
+ action: 'schemaVerify',
235
+ kind: 'spanStart',
236
+ spanId: 'connect',
237
+ label: 'Connecting to database...',
238
+ });
239
+ try {
240
+ await this.connect(options.connection);
241
+ onProgress?.({
242
+ action: 'schemaVerify',
243
+ kind: 'spanEnd',
244
+ spanId: 'connect',
245
+ outcome: 'ok',
246
+ });
247
+ } catch (error) {
248
+ onProgress?.({
249
+ action: 'schemaVerify',
250
+ kind: 'spanEnd',
251
+ spanId: 'connect',
252
+ outcome: 'error',
253
+ });
254
+ throw error;
255
+ }
256
+ }
257
+
169
258
  const { driver, familyInstance, frameworkComponents } = await this.ensureConnected();
170
259
 
171
260
  // Validate contract using family instance
172
261
  const contractIR = familyInstance.validateContractIR(options.contractIR);
173
262
 
174
- // Delegate to family instance schemaVerify method
175
- return familyInstance.schemaVerify({
176
- driver,
177
- contractIR,
178
- strict: options.strict ?? false,
179
- contractPath: '',
180
- frameworkComponents,
263
+ // Emit schemaVerify span
264
+ onProgress?.({
265
+ action: 'schemaVerify',
266
+ kind: 'spanStart',
267
+ spanId: 'schemaVerify',
268
+ label: 'Verifying database schema...',
181
269
  });
270
+
271
+ try {
272
+ // Delegate to family instance schemaVerify method
273
+ const result = await familyInstance.schemaVerify({
274
+ driver,
275
+ contractIR,
276
+ strict: options.strict ?? false,
277
+ contractPath: '',
278
+ frameworkComponents,
279
+ });
280
+
281
+ onProgress?.({
282
+ action: 'schemaVerify',
283
+ kind: 'spanEnd',
284
+ spanId: 'schemaVerify',
285
+ outcome: result.ok ? 'ok' : 'error',
286
+ });
287
+
288
+ return result;
289
+ } catch (error) {
290
+ onProgress?.({
291
+ action: 'schemaVerify',
292
+ kind: 'spanEnd',
293
+ spanId: 'schemaVerify',
294
+ outcome: 'error',
295
+ });
296
+ throw error;
297
+ }
182
298
  }
183
299
 
184
300
  async sign(options: SignOptions): Promise<SignDatabaseResult> {
301
+ const { onProgress } = options;
302
+
303
+ // Connect with progress span if connection provided
304
+ if (options.connection !== undefined) {
305
+ onProgress?.({
306
+ action: 'sign',
307
+ kind: 'spanStart',
308
+ spanId: 'connect',
309
+ label: 'Connecting to database...',
310
+ });
311
+ try {
312
+ await this.connect(options.connection);
313
+ onProgress?.({
314
+ action: 'sign',
315
+ kind: 'spanEnd',
316
+ spanId: 'connect',
317
+ outcome: 'ok',
318
+ });
319
+ } catch (error) {
320
+ onProgress?.({
321
+ action: 'sign',
322
+ kind: 'spanEnd',
323
+ spanId: 'connect',
324
+ outcome: 'error',
325
+ });
326
+ throw error;
327
+ }
328
+ }
329
+
185
330
  const { driver, familyInstance } = await this.ensureConnected();
186
331
 
187
332
  // Validate contract using family instance
188
333
  const contractIR = familyInstance.validateContractIR(options.contractIR);
189
334
 
190
- // Delegate to family instance sign method
191
- return familyInstance.sign({
192
- driver,
193
- contractIR,
194
- contractPath: '',
335
+ // Emit sign span
336
+ onProgress?.({
337
+ action: 'sign',
338
+ kind: 'spanStart',
339
+ spanId: 'sign',
340
+ label: 'Signing database...',
195
341
  });
342
+
343
+ try {
344
+ // Delegate to family instance sign method
345
+ const result = await familyInstance.sign({
346
+ driver,
347
+ contractIR,
348
+ contractPath: options.contractPath ?? '',
349
+ ...(options.configPath ? { configPath: options.configPath } : {}),
350
+ });
351
+
352
+ onProgress?.({
353
+ action: 'sign',
354
+ kind: 'spanEnd',
355
+ spanId: 'sign',
356
+ outcome: 'ok',
357
+ });
358
+
359
+ return result;
360
+ } catch (error) {
361
+ onProgress?.({
362
+ action: 'sign',
363
+ kind: 'spanEnd',
364
+ spanId: 'sign',
365
+ outcome: 'error',
366
+ });
367
+ throw error;
368
+ }
196
369
  }
197
370
 
198
371
  async dbInit(options: DbInitOptions): Promise<DbInitResult> {
@@ -248,12 +421,169 @@ class ControlClientImpl implements ControlClient {
248
421
  }
249
422
 
250
423
  async introspect(options?: IntrospectOptions): Promise<unknown> {
424
+ const onProgress = options?.onProgress;
425
+
426
+ // Connect with progress span if connection provided
427
+ if (options?.connection !== undefined) {
428
+ onProgress?.({
429
+ action: 'introspect',
430
+ kind: 'spanStart',
431
+ spanId: 'connect',
432
+ label: 'Connecting to database...',
433
+ });
434
+ try {
435
+ await this.connect(options.connection);
436
+ onProgress?.({
437
+ action: 'introspect',
438
+ kind: 'spanEnd',
439
+ spanId: 'connect',
440
+ outcome: 'ok',
441
+ });
442
+ } catch (error) {
443
+ onProgress?.({
444
+ action: 'introspect',
445
+ kind: 'spanEnd',
446
+ spanId: 'connect',
447
+ outcome: 'error',
448
+ });
449
+ throw error;
450
+ }
451
+ }
452
+
251
453
  const { driver, familyInstance } = await this.ensureConnected();
252
454
 
253
455
  // TODO: Pass schema option to familyInstance.introspect when schema filtering is implemented
254
456
  const _schema = options?.schema;
255
457
  void _schema;
256
458
 
257
- return familyInstance.introspect({ driver });
459
+ // Emit introspect span
460
+ onProgress?.({
461
+ action: 'introspect',
462
+ kind: 'spanStart',
463
+ spanId: 'introspect',
464
+ label: 'Introspecting database schema...',
465
+ });
466
+
467
+ try {
468
+ const result = await familyInstance.introspect({ driver });
469
+
470
+ onProgress?.({
471
+ action: 'introspect',
472
+ kind: 'spanEnd',
473
+ spanId: 'introspect',
474
+ outcome: 'ok',
475
+ });
476
+
477
+ return result;
478
+ } catch (error) {
479
+ onProgress?.({
480
+ action: 'introspect',
481
+ kind: 'spanEnd',
482
+ spanId: 'introspect',
483
+ outcome: 'error',
484
+ });
485
+ throw error;
486
+ }
487
+ }
488
+
489
+ toSchemaView(schemaIR: unknown): CoreSchemaView | undefined {
490
+ this.init();
491
+ if (this.familyInstance?.toSchemaView) {
492
+ return this.familyInstance.toSchemaView(schemaIR);
493
+ }
494
+ return undefined;
495
+ }
496
+
497
+ async emit(options: EmitOptions): Promise<EmitResult> {
498
+ const { onProgress, contractConfig } = options;
499
+
500
+ // Ensure initialized (creates stack and family instance)
501
+ // emit() does NOT require a database connection
502
+ this.init();
503
+
504
+ if (!this.familyInstance) {
505
+ throw new Error('Family instance was not initialized. This is a bug.');
506
+ }
507
+
508
+ // Resolve contract source
509
+ let contractRaw: unknown;
510
+ onProgress?.({
511
+ action: 'emit',
512
+ kind: 'spanStart',
513
+ spanId: 'resolveSource',
514
+ label: 'Resolving contract source...',
515
+ });
516
+
517
+ try {
518
+ switch (contractConfig.source.kind) {
519
+ case 'loader':
520
+ contractRaw = await contractConfig.source.load();
521
+ break;
522
+ case 'value':
523
+ contractRaw = contractConfig.source.value;
524
+ break;
525
+ }
526
+
527
+ onProgress?.({
528
+ action: 'emit',
529
+ kind: 'spanEnd',
530
+ spanId: 'resolveSource',
531
+ outcome: 'ok',
532
+ });
533
+ } catch (error) {
534
+ onProgress?.({
535
+ action: 'emit',
536
+ kind: 'spanEnd',
537
+ spanId: 'resolveSource',
538
+ outcome: 'error',
539
+ });
540
+
541
+ return notOk({
542
+ code: 'CONTRACT_SOURCE_INVALID',
543
+ summary: 'Failed to resolve contract source',
544
+ why: error instanceof Error ? error.message : String(error),
545
+ meta: undefined,
546
+ });
547
+ }
548
+
549
+ // Emit contract
550
+ onProgress?.({
551
+ action: 'emit',
552
+ kind: 'spanStart',
553
+ spanId: 'emit',
554
+ label: 'Emitting contract...',
555
+ });
556
+
557
+ try {
558
+ const emitResult = await this.familyInstance.emitContract({ contractIR: contractRaw });
559
+
560
+ onProgress?.({
561
+ action: 'emit',
562
+ kind: 'spanEnd',
563
+ spanId: 'emit',
564
+ outcome: 'ok',
565
+ });
566
+
567
+ return ok({
568
+ coreHash: emitResult.coreHash,
569
+ profileHash: emitResult.profileHash,
570
+ contractJson: emitResult.contractJson,
571
+ contractDts: emitResult.contractDts,
572
+ });
573
+ } catch (error) {
574
+ onProgress?.({
575
+ action: 'emit',
576
+ kind: 'spanEnd',
577
+ spanId: 'emit',
578
+ outcome: 'error',
579
+ });
580
+
581
+ return notOk({
582
+ code: 'EMIT_FAILED',
583
+ summary: 'Failed to emit contract',
584
+ why: error instanceof Error ? error.message : String(error),
585
+ meta: undefined,
586
+ });
587
+ }
258
588
  }
259
589
  }
@@ -1,3 +1,4 @@
1
+ import type { CoreSchemaView } from '@prisma-next/core-control-plane/schema-view';
1
2
  import type {
2
3
  ControlAdapterDescriptor,
3
4
  ControlDriverDescriptor,
@@ -53,7 +54,13 @@ export interface ControlClientOptions {
53
54
  /**
54
55
  * Action names for control-api operations that can emit progress events.
55
56
  */
56
- export type ControlActionName = 'dbInit' | 'verify' | 'schemaVerify' | 'sign' | 'introspect';
57
+ export type ControlActionName =
58
+ | 'dbInit'
59
+ | 'verify'
60
+ | 'schemaVerify'
61
+ | 'sign'
62
+ | 'introspect'
63
+ | 'emit';
57
64
 
58
65
  /**
59
66
  * Progress event emitted during control-api operation execution.
@@ -100,6 +107,12 @@ export type OnControlProgress = (event: ControlProgressEvent) => void;
100
107
  export interface VerifyOptions {
101
108
  /** Contract IR or unvalidated JSON - validated at runtime via familyInstance.validateContractIR() */
102
109
  readonly contractIR: unknown;
110
+ /**
111
+ * Database connection. If provided, verify will connect before executing.
112
+ * If omitted, the client must already be connected.
113
+ * The type is driver-specific (e.g., string URL for Postgres).
114
+ */
115
+ readonly connection?: unknown;
103
116
  /** Optional progress callback for observing operation progress */
104
117
  readonly onProgress?: OnControlProgress;
105
118
  }
@@ -116,6 +129,12 @@ export interface SchemaVerifyOptions {
116
129
  * Default: false (tolerant mode - allows superset)
117
130
  */
118
131
  readonly strict?: boolean;
132
+ /**
133
+ * Database connection. If provided, schemaVerify will connect before executing.
134
+ * If omitted, the client must already be connected.
135
+ * The type is driver-specific (e.g., string URL for Postgres).
136
+ */
137
+ readonly connection?: unknown;
119
138
  /** Optional progress callback for observing operation progress */
120
139
  readonly onProgress?: OnControlProgress;
121
140
  }
@@ -126,6 +145,20 @@ export interface SchemaVerifyOptions {
126
145
  export interface SignOptions {
127
146
  /** Contract IR or unvalidated JSON - validated at runtime via familyInstance.validateContractIR() */
128
147
  readonly contractIR: unknown;
148
+ /**
149
+ * Path to the contract file (for metadata in the result).
150
+ */
151
+ readonly contractPath?: string;
152
+ /**
153
+ * Path to the config file (for metadata in the result).
154
+ */
155
+ readonly configPath?: string;
156
+ /**
157
+ * Database connection. If provided, sign will connect before executing.
158
+ * If omitted, the client must already be connected.
159
+ * The type is driver-specific (e.g., string URL for Postgres).
160
+ */
161
+ readonly connection?: unknown;
129
162
  /** Optional progress callback for observing operation progress */
130
163
  readonly onProgress?: OnControlProgress;
131
164
  }
@@ -160,6 +193,67 @@ export interface IntrospectOptions {
160
193
  * Optional schema name to introspect.
161
194
  */
162
195
  readonly schema?: string;
196
+ /**
197
+ * Database connection. If provided, introspect will connect before executing.
198
+ * If omitted, the client must already be connected.
199
+ * The type is driver-specific (e.g., string URL for Postgres).
200
+ */
201
+ readonly connection?: unknown;
202
+ /** Optional progress callback for observing operation progress */
203
+ readonly onProgress?: OnControlProgress;
204
+ }
205
+
206
+ /**
207
+ * Contract source as a raw value (any JSON-serializable value).
208
+ */
209
+ export interface ContractSourceValue {
210
+ readonly kind: 'value';
211
+ readonly value: unknown;
212
+ }
213
+
214
+ /**
215
+ * Contract source as a lazy loader function.
216
+ */
217
+ export interface ContractSourceLoader {
218
+ readonly kind: 'loader';
219
+ readonly load: () => unknown | Promise<unknown>;
220
+ }
221
+
222
+ /**
223
+ * Discriminated union for contract source.
224
+ * Use `kind` to determine how to resolve the contract.
225
+ */
226
+ export type EmitContractSource = ContractSourceValue | ContractSourceLoader;
227
+
228
+ /**
229
+ * Contract configuration for emit operation.
230
+ */
231
+ export interface EmitContractConfig {
232
+ /**
233
+ * Contract source - either a raw value or a loader function.
234
+ * Switch on `source.kind` to determine how to resolve.
235
+ */
236
+ readonly source: EmitContractSource;
237
+ /**
238
+ * Output path for contract.json.
239
+ * Should be an absolute or relative path.
240
+ */
241
+ readonly output: string;
242
+ /**
243
+ * Output path for contract.d.ts.
244
+ * Should be an absolute or relative path.
245
+ */
246
+ readonly types: string;
247
+ }
248
+
249
+ /**
250
+ * Options for the emit operation.
251
+ */
252
+ export interface EmitOptions {
253
+ /**
254
+ * Contract configuration containing source, output, and types paths.
255
+ */
256
+ readonly contractConfig: EmitContractConfig;
163
257
  /** Optional progress callback for observing operation progress */
164
258
  readonly onProgress?: OnControlProgress;
165
259
  }
@@ -221,6 +315,42 @@ export interface DbInitFailure {
221
315
  */
222
316
  export type DbInitResult = Result<DbInitSuccess, DbInitFailure>;
223
317
 
318
+ /**
319
+ * Successful emit result.
320
+ * Contains the hashes and paths of emitted files.
321
+ */
322
+ export interface EmitSuccess {
323
+ /** Core hash of the emitted contract */
324
+ readonly coreHash: string;
325
+ /** Profile hash of the emitted contract (target-specific) */
326
+ readonly profileHash: string;
327
+ /** The emitted contract as JSON string */
328
+ readonly contractJson: string;
329
+ /** The emitted contract TypeScript declarations */
330
+ readonly contractDts: string;
331
+ }
332
+
333
+ /**
334
+ * Failure codes for emit operation.
335
+ */
336
+ export type EmitFailureCode = 'CONTRACT_SOURCE_INVALID' | 'EMIT_FAILED';
337
+
338
+ /**
339
+ * Failure details for emit operation.
340
+ */
341
+ export interface EmitFailure {
342
+ readonly code: EmitFailureCode;
343
+ readonly summary: string;
344
+ readonly why: string | undefined;
345
+ readonly meta: Record<string, unknown> | undefined;
346
+ }
347
+
348
+ /**
349
+ * Result type for emit operation.
350
+ * Uses Result pattern: success returns EmitSuccess, failure returns EmitFailure.
351
+ */
352
+ export type EmitResult = Result<EmitSuccess, EmitFailure>;
353
+
224
354
  // ============================================================================
225
355
  // Client Interface
226
356
  // ============================================================================
@@ -310,4 +440,22 @@ export interface ControlClient {
310
440
  * @throws If not connected or infrastructure failure
311
441
  */
312
442
  introspect(options?: IntrospectOptions): Promise<unknown>;
443
+
444
+ /**
445
+ * Converts a schema IR to a schema view for CLI tree rendering.
446
+ * Delegates to the family instance's toSchemaView method.
447
+ *
448
+ * @param schemaIR - The schema IR from introspect()
449
+ * @returns CoreSchemaView if the family supports it, undefined otherwise
450
+ */
451
+ toSchemaView(schemaIR: unknown): CoreSchemaView | undefined;
452
+
453
+ /**
454
+ * Emits the contract to JSON and TypeScript declarations.
455
+ * This is an offline operation that does NOT require a database connection.
456
+ * Uses `init()` to create the stack but does NOT call `connect()`.
457
+ *
458
+ * @returns Result pattern: Ok with emit details, NotOk with failure details
459
+ */
460
+ emit(options: EmitOptions): Promise<EmitResult>;
313
461
  }
@@ -20,6 +20,8 @@ export { createControlClient } from '../control-api/client';
20
20
 
21
21
  // CLI-specific types
22
22
  export type {
23
+ ContractSourceLoader,
24
+ ContractSourceValue,
23
25
  ControlActionName,
24
26
  ControlClient,
25
27
  ControlClientOptions,
@@ -29,6 +31,13 @@ export type {
29
31
  DbInitOptions,
30
32
  DbInitResult,
31
33
  DbInitSuccess,
34
+ EmitContractConfig,
35
+ EmitContractSource,
36
+ EmitFailure,
37
+ EmitFailureCode,
38
+ EmitOptions,
39
+ EmitResult,
40
+ EmitSuccess,
32
41
  IntrospectOptions,
33
42
  OnControlProgress,
34
43
  SchemaVerifyOptions,
@@ -1,47 +0,0 @@
1
- import {
2
- CliStructuredError
3
- } from "./chunk-VI2YETW7.js";
4
-
5
- // src/utils/action.ts
6
- import { notOk, ok } from "@prisma-next/utils/result";
7
- async function performAction(fn) {
8
- try {
9
- const value = await fn();
10
- return ok(value);
11
- } catch (error) {
12
- if (error instanceof CliStructuredError) {
13
- return notOk(error);
14
- }
15
- throw error;
16
- }
17
- }
18
-
19
- // src/utils/spinner.ts
20
- import ora from "ora";
21
- async function withSpinner(operation, options) {
22
- const { message, flags } = options;
23
- const shouldShowSpinner = !flags.quiet && flags.json !== "object" && process.stdout.isTTY;
24
- if (!shouldShowSpinner) {
25
- return operation();
26
- }
27
- const startTime = Date.now();
28
- const spinner = ora({
29
- text: message,
30
- color: flags.color !== false ? "cyan" : false
31
- }).start();
32
- try {
33
- const result = await operation();
34
- const elapsed = Date.now() - startTime;
35
- spinner.succeed(`${message} (${elapsed}ms)`);
36
- return result;
37
- } catch (error) {
38
- spinner.fail(`${message} failed: ${error instanceof Error ? error.message : String(error)}`);
39
- throw error;
40
- }
41
- }
42
-
43
- export {
44
- performAction,
45
- withSpinner
46
- };
47
- //# sourceMappingURL=chunk-5MPKZYVI.js.map