@prisma-next/cli 0.3.0-dev.45 → 0.3.0-dev.52
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 +20 -34
- package/dist/cli.mjs +2 -1
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-Lm9Q6aQM.mjs → client-BSZKpZTF.mjs} +26 -9
- package/dist/{client-Lm9Q6aQM.mjs.map → client-BSZKpZTF.mjs.map} +1 -1
- package/dist/commands/contract-emit.d.mts.map +1 -1
- package/dist/commands/contract-emit.mjs +26 -19
- package/dist/commands/contract-emit.mjs.map +1 -1
- package/dist/commands/db-init.mjs +3 -3
- package/dist/commands/db-introspect.mjs +3 -3
- package/dist/commands/db-schema-verify.mjs +3 -3
- package/dist/commands/db-sign.mjs +3 -3
- package/dist/commands/db-verify.mjs +3 -3
- package/dist/{config-loader-CnnWuluc.mjs → config-loader-BJ8HsEdA.mjs} +2 -2
- package/dist/{config-loader-CnnWuluc.mjs.map → config-loader-BJ8HsEdA.mjs.map} +1 -1
- package/dist/config-loader.mjs +1 -1
- package/dist/exports/control-api.d.mts +5 -23
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +44 -7
- package/dist/exports/control-api.mjs.map +1 -1
- package/dist/exports/index.mjs +3 -1
- package/dist/exports/index.mjs.map +1 -1
- package/package.json +10 -10
- package/src/commands/contract-emit.ts +32 -16
- package/src/control-api/client.ts +28 -9
- package/src/control-api/operations/contract-emit.ts +72 -14
- package/src/control-api/types.ts +7 -25
- package/src/exports/control-api.ts +0 -3
|
@@ -506,7 +506,6 @@ class ControlClientImpl implements ControlClient {
|
|
|
506
506
|
throw new Error('Family instance was not initialized. This is a bug.');
|
|
507
507
|
}
|
|
508
508
|
|
|
509
|
-
// Resolve contract source
|
|
510
509
|
let contractRaw: unknown;
|
|
511
510
|
onProgress?.({
|
|
512
511
|
action: 'emit',
|
|
@@ -516,14 +515,24 @@ class ControlClientImpl implements ControlClient {
|
|
|
516
515
|
});
|
|
517
516
|
|
|
518
517
|
try {
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
518
|
+
const providerResult = await contractConfig.sourceProvider();
|
|
519
|
+
if (!providerResult.ok) {
|
|
520
|
+
onProgress?.({
|
|
521
|
+
action: 'emit',
|
|
522
|
+
kind: 'spanEnd',
|
|
523
|
+
spanId: 'resolveSource',
|
|
524
|
+
outcome: 'error',
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
return notOk({
|
|
528
|
+
code: 'CONTRACT_SOURCE_INVALID',
|
|
529
|
+
summary: providerResult.failure.summary,
|
|
530
|
+
why: providerResult.failure.summary,
|
|
531
|
+
meta: providerResult.failure.meta,
|
|
532
|
+
diagnostics: providerResult.failure,
|
|
533
|
+
});
|
|
526
534
|
}
|
|
535
|
+
contractRaw = providerResult.value;
|
|
527
536
|
|
|
528
537
|
onProgress?.({
|
|
529
538
|
action: 'emit',
|
|
@@ -539,10 +548,20 @@ class ControlClientImpl implements ControlClient {
|
|
|
539
548
|
outcome: 'error',
|
|
540
549
|
});
|
|
541
550
|
|
|
551
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
542
552
|
return notOk({
|
|
543
553
|
code: 'CONTRACT_SOURCE_INVALID',
|
|
544
554
|
summary: 'Failed to resolve contract source',
|
|
545
|
-
why:
|
|
555
|
+
why: message,
|
|
556
|
+
diagnostics: {
|
|
557
|
+
summary: 'Contract source provider threw an exception',
|
|
558
|
+
diagnostics: [
|
|
559
|
+
{
|
|
560
|
+
code: 'PROVIDER_THROW',
|
|
561
|
+
message,
|
|
562
|
+
},
|
|
563
|
+
],
|
|
564
|
+
},
|
|
546
565
|
meta: undefined,
|
|
547
566
|
});
|
|
548
567
|
}
|
|
@@ -4,9 +4,29 @@ import { abortable } from '@prisma-next/utils/abortable';
|
|
|
4
4
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
5
5
|
import { dirname, isAbsolute, join, resolve } from 'pathe';
|
|
6
6
|
import { loadConfig } from '../../config-loader';
|
|
7
|
-
import { errorContractConfigMissing } from '../../utils/cli-errors';
|
|
7
|
+
import { errorContractConfigMissing, errorRuntime } from '../../utils/cli-errors';
|
|
8
8
|
import type { ContractEmitOptions, ContractEmitResult } from '../types';
|
|
9
9
|
|
|
10
|
+
interface ProviderFailureLike {
|
|
11
|
+
readonly summary: string;
|
|
12
|
+
readonly diagnostics: readonly unknown[];
|
|
13
|
+
readonly meta?: unknown;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
17
|
+
return typeof value === 'object' && value !== null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function isAbortError(error: unknown): boolean {
|
|
21
|
+
return isRecord(error) && typeof error['name'] === 'string' && error['name'] === 'AbortError';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function isProviderFailureLike(value: unknown): value is ProviderFailureLike {
|
|
25
|
+
return (
|
|
26
|
+
isRecord(value) && typeof value['summary'] === 'string' && Array.isArray(value['diagnostics'])
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
10
30
|
/**
|
|
11
31
|
* Executes the contract emit operation.
|
|
12
32
|
*
|
|
@@ -54,13 +74,10 @@ export async function executeContractEmit(
|
|
|
54
74
|
});
|
|
55
75
|
}
|
|
56
76
|
|
|
57
|
-
// Validate source
|
|
58
|
-
if (
|
|
59
|
-
contractConfig.source === null ||
|
|
60
|
-
(typeof contractConfig.source !== 'function' && typeof contractConfig.source !== 'object')
|
|
61
|
-
) {
|
|
77
|
+
// Validate source exists and is callable
|
|
78
|
+
if (typeof contractConfig.source !== 'function') {
|
|
62
79
|
throw errorContractConfigMissing({
|
|
63
|
-
why: 'Contract config must include a valid source
|
|
80
|
+
why: 'Contract config must include a valid source provider function',
|
|
64
81
|
});
|
|
65
82
|
}
|
|
66
83
|
|
|
@@ -73,18 +90,59 @@ export async function executeContractEmit(
|
|
|
73
90
|
// Colocate .d.ts with .json (contract.json → contract.d.ts)
|
|
74
91
|
const outputDtsPath = `${outputJsonPath.slice(0, -5)}.d.ts`;
|
|
75
92
|
|
|
93
|
+
let providerResult: Awaited<ReturnType<typeof contractConfig.source>>;
|
|
94
|
+
try {
|
|
95
|
+
providerResult = await unlessAborted(contractConfig.source());
|
|
96
|
+
} catch (error) {
|
|
97
|
+
if (signal.aborted || isAbortError(error)) {
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
throw errorRuntime('Failed to resolve contract source', {
|
|
101
|
+
why: error instanceof Error ? error.message : String(error),
|
|
102
|
+
fix: 'Ensure contract.source resolves to ok(contractIR) or returns structured diagnostics.',
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (!isRecord(providerResult) || typeof providerResult.ok !== 'boolean') {
|
|
107
|
+
throw errorRuntime('Failed to resolve contract source', {
|
|
108
|
+
why: 'Contract source provider returned malformed result shape.',
|
|
109
|
+
fix: 'Ensure contract.source resolves to ok(contractIR) or notOk({ summary, diagnostics }).',
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (providerResult.ok && !('value' in providerResult)) {
|
|
114
|
+
throw errorRuntime('Failed to resolve contract source', {
|
|
115
|
+
why: 'Contract source provider returned malformed success result: missing value.',
|
|
116
|
+
fix: 'Ensure contract.source success payload is ok(contractIR).',
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (!providerResult.ok && !isProviderFailureLike(providerResult.failure)) {
|
|
121
|
+
throw errorRuntime('Failed to resolve contract source', {
|
|
122
|
+
why: 'Contract source provider returned malformed failure result: expected summary and diagnostics.',
|
|
123
|
+
fix: 'Ensure contract.source failure payload is notOk({ summary, diagnostics, meta? }).',
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!providerResult.ok) {
|
|
128
|
+
throw errorRuntime('Failed to resolve contract source', {
|
|
129
|
+
why: providerResult.failure.summary,
|
|
130
|
+
fix: 'Fix contract source diagnostics and return ok(contractIR).',
|
|
131
|
+
meta: {
|
|
132
|
+
diagnostics: providerResult.failure.diagnostics,
|
|
133
|
+
...ifDefined('providerMeta', providerResult.failure.meta),
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
76
138
|
// Create control plane stack from config
|
|
77
139
|
const stack = createControlPlaneStack(config);
|
|
78
140
|
const familyInstance = config.family.create(stack);
|
|
79
141
|
|
|
80
|
-
// Resolve contract source from config
|
|
81
|
-
const contractRaw =
|
|
82
|
-
typeof contractConfig.source === 'function'
|
|
83
|
-
? await unlessAborted(contractConfig.source())
|
|
84
|
-
: contractConfig.source;
|
|
85
|
-
|
|
86
142
|
// Emit contract via family instance
|
|
87
|
-
const emitResult = await unlessAborted(
|
|
143
|
+
const emitResult = await unlessAborted(
|
|
144
|
+
familyInstance.emitContract({ contractIR: providerResult.value }),
|
|
145
|
+
);
|
|
88
146
|
|
|
89
147
|
// Create directory if needed and write files (both colocated)
|
|
90
148
|
await unlessAborted(mkdir(dirname(outputJsonPath), { recursive: true }));
|
package/src/control-api/types.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ContractSourceDiagnostics,
|
|
3
|
+
ContractSourceProvider,
|
|
4
|
+
} from '@prisma-next/core-control-plane/config-types';
|
|
1
5
|
import type { CoreSchemaView } from '@prisma-next/core-control-plane/schema-view';
|
|
2
6
|
import type {
|
|
3
7
|
ControlAdapterDescriptor,
|
|
@@ -203,37 +207,14 @@ export interface IntrospectOptions {
|
|
|
203
207
|
readonly onProgress?: OnControlProgress;
|
|
204
208
|
}
|
|
205
209
|
|
|
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
210
|
/**
|
|
229
211
|
* Contract configuration for emit operation.
|
|
230
212
|
*/
|
|
231
213
|
export interface EmitContractConfig {
|
|
232
214
|
/**
|
|
233
|
-
* Contract source
|
|
234
|
-
* Switch on `source.kind` to determine how to resolve.
|
|
215
|
+
* Contract source provider.
|
|
235
216
|
*/
|
|
236
|
-
readonly
|
|
217
|
+
readonly sourceProvider: ContractSourceProvider;
|
|
237
218
|
/**
|
|
238
219
|
* Output path for contract.json.
|
|
239
220
|
* The .d.ts types file will be colocated (e.g., contract.json → contract.d.ts).
|
|
@@ -340,6 +321,7 @@ export interface EmitFailure {
|
|
|
340
321
|
readonly summary: string;
|
|
341
322
|
readonly why: string | undefined;
|
|
342
323
|
readonly meta: Record<string, unknown> | undefined;
|
|
324
|
+
readonly diagnostics?: ContractSourceDiagnostics;
|
|
343
325
|
}
|
|
344
326
|
|
|
345
327
|
/**
|
|
@@ -25,8 +25,6 @@ export { executeContractEmit } from '../control-api/operations/contract-emit';
|
|
|
25
25
|
export type {
|
|
26
26
|
ContractEmitOptions,
|
|
27
27
|
ContractEmitResult,
|
|
28
|
-
ContractSourceLoader,
|
|
29
|
-
ContractSourceValue,
|
|
30
28
|
ControlActionName,
|
|
31
29
|
ControlClient,
|
|
32
30
|
ControlClientOptions,
|
|
@@ -37,7 +35,6 @@ export type {
|
|
|
37
35
|
DbInitResult,
|
|
38
36
|
DbInitSuccess,
|
|
39
37
|
EmitContractConfig,
|
|
40
|
-
EmitContractSource,
|
|
41
38
|
EmitFailure,
|
|
42
39
|
EmitFailureCode,
|
|
43
40
|
EmitOptions,
|