@prisma-next/cli 0.3.0-dev.53 → 0.3.0-dev.55
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 +24 -0
- package/dist/cli.mjs +5 -3
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-BSZKpZTF.mjs → client-B7f4PZZ1.mjs} +367 -170
- package/dist/client-B7f4PZZ1.mjs.map +1 -0
- package/dist/commands/contract-emit.d.mts.map +1 -1
- package/dist/commands/contract-emit.mjs +7 -6
- package/dist/commands/contract-emit.mjs.map +1 -1
- package/dist/commands/db-init.d.mts.map +1 -1
- package/dist/commands/db-init.mjs +28 -76
- package/dist/commands/db-init.mjs.map +1 -1
- package/dist/commands/db-introspect.d.mts.map +1 -1
- package/dist/commands/db-introspect.mjs +12 -17
- package/dist/commands/db-introspect.mjs.map +1 -1
- package/dist/commands/db-schema-verify.d.mts.map +1 -1
- package/dist/commands/db-schema-verify.mjs +5 -4
- package/dist/commands/db-schema-verify.mjs.map +1 -1
- package/dist/commands/db-sign.d.mts.map +1 -1
- package/dist/commands/db-sign.mjs +6 -5
- package/dist/commands/db-sign.mjs.map +1 -1
- package/dist/commands/db-update.d.mts +7 -0
- package/dist/commands/db-update.d.mts.map +1 -0
- package/dist/commands/db-update.mjs +120 -0
- package/dist/commands/db-update.mjs.map +1 -0
- package/dist/commands/db-verify.d.mts.map +1 -1
- package/dist/commands/db-verify.mjs +5 -4
- package/dist/commands/db-verify.mjs.map +1 -1
- package/dist/{config-loader-BJ8HsEdA.mjs → config-loader-DqKf1qSa.mjs} +1 -1
- package/dist/{config-loader-BJ8HsEdA.mjs.map → config-loader-DqKf1qSa.mjs.map} +1 -1
- package/dist/config-loader.mjs +1 -1
- package/dist/exports/control-api.d.mts +96 -6
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +2 -2
- package/dist/exports/index.mjs +1 -3
- package/dist/exports/index.mjs.map +1 -1
- package/dist/migration-command-scaffold-BELw_do2.mjs +95 -0
- package/dist/migration-command-scaffold-BELw_do2.mjs.map +1 -0
- package/dist/{result-handler-BZPY7HX4.mjs → result-handler-BhmrXIvT.mjs} +63 -13
- package/dist/result-handler-BhmrXIvT.mjs.map +1 -0
- package/package.json +14 -10
- package/src/cli.ts +5 -0
- package/src/commands/contract-emit.ts +22 -6
- package/src/commands/db-init.ts +89 -197
- package/src/commands/db-introspect.ts +4 -8
- package/src/commands/db-schema-verify.ts +11 -2
- package/src/commands/db-sign.ts +13 -4
- package/src/commands/db-update.ts +220 -0
- package/src/commands/db-verify.ts +11 -2
- package/src/control-api/client.ts +109 -145
- package/src/control-api/errors.ts +9 -0
- package/src/control-api/operations/db-init.ts +39 -34
- package/src/control-api/operations/db-update.ts +221 -0
- package/src/control-api/operations/extract-sql-ddl.ts +47 -0
- package/src/control-api/operations/migration-helpers.ts +49 -0
- package/src/control-api/types.ts +104 -4
- package/src/exports/control-api.ts +5 -0
- package/src/utils/cli-errors.ts +2 -0
- package/src/utils/command-helpers.ts +81 -3
- package/src/utils/migration-command-scaffold.ts +189 -0
- package/src/utils/output.ts +43 -13
- package/dist/client-BSZKpZTF.mjs.map +0 -1
- package/dist/result-handler-BZPY7HX4.mjs.map +0 -1
|
@@ -33,7 +33,7 @@ interface ControlClientOptions {
|
|
|
33
33
|
/**
|
|
34
34
|
* Action names for control-api operations that can emit progress events.
|
|
35
35
|
*/
|
|
36
|
-
type ControlActionName = 'dbInit' | 'verify' | 'schemaVerify' | 'sign' | 'introspect' | 'emit';
|
|
36
|
+
type ControlActionName = 'dbInit' | 'dbUpdate' | 'verify' | 'schemaVerify' | 'sign' | 'introspect' | 'emit';
|
|
37
37
|
/**
|
|
38
38
|
* Progress event emitted during control-api operation execution.
|
|
39
39
|
*
|
|
@@ -145,6 +145,35 @@ interface DbInitOptions {
|
|
|
145
145
|
/** Optional progress callback for observing operation progress */
|
|
146
146
|
readonly onProgress?: OnControlProgress;
|
|
147
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* Options for the dbUpdate operation.
|
|
150
|
+
*/
|
|
151
|
+
interface DbUpdateOptions {
|
|
152
|
+
/** Contract IR or unvalidated JSON - validated at runtime via familyInstance.validateContractIR() */
|
|
153
|
+
readonly contractIR: unknown;
|
|
154
|
+
/**
|
|
155
|
+
* Mode for the dbUpdate operation.
|
|
156
|
+
* - 'plan': Returns planned operations without applying
|
|
157
|
+
* - 'apply': Applies operations and writes marker/ledger
|
|
158
|
+
*/
|
|
159
|
+
readonly mode: 'plan' | 'apply';
|
|
160
|
+
/**
|
|
161
|
+
* Database connection. If provided, dbUpdate will connect before executing.
|
|
162
|
+
* If omitted, the client must already be connected.
|
|
163
|
+
* The type is driver-specific (e.g., string URL for Postgres).
|
|
164
|
+
*/
|
|
165
|
+
readonly connection?: unknown;
|
|
166
|
+
/**
|
|
167
|
+
* When true, allows applying plans that contain destructive operations
|
|
168
|
+
* (e.g., DROP TABLE, DROP COLUMN, ALTER TYPE).
|
|
169
|
+
* When false (default), the operation returns a failure if the plan
|
|
170
|
+
* includes destructive operations, prompting the user to use --plan
|
|
171
|
+
* to preview and then re-run with --accept-data-loss.
|
|
172
|
+
*/
|
|
173
|
+
readonly acceptDataLoss?: boolean;
|
|
174
|
+
/** Optional progress callback for observing operation progress */
|
|
175
|
+
readonly onProgress?: OnControlProgress;
|
|
176
|
+
}
|
|
148
177
|
/**
|
|
149
178
|
* Options for the introspect operation.
|
|
150
179
|
*/
|
|
@@ -198,6 +227,11 @@ interface DbInitSuccess {
|
|
|
198
227
|
readonly label: string;
|
|
199
228
|
readonly operationClass: string;
|
|
200
229
|
}>;
|
|
230
|
+
readonly sql?: ReadonlyArray<string>;
|
|
231
|
+
};
|
|
232
|
+
readonly destination: {
|
|
233
|
+
readonly storageHash: string;
|
|
234
|
+
readonly profileHash?: string;
|
|
201
235
|
};
|
|
202
236
|
readonly execution?: {
|
|
203
237
|
readonly operationsPlanned: number;
|
|
@@ -236,6 +270,52 @@ interface DbInitFailure {
|
|
|
236
270
|
* Uses Result pattern: success returns DbInitSuccess, failure returns DbInitFailure.
|
|
237
271
|
*/
|
|
238
272
|
type DbInitResult = Result<DbInitSuccess, DbInitFailure>;
|
|
273
|
+
/**
|
|
274
|
+
* Successful dbUpdate result.
|
|
275
|
+
*/
|
|
276
|
+
interface DbUpdateSuccess {
|
|
277
|
+
readonly mode: 'plan' | 'apply';
|
|
278
|
+
readonly plan: {
|
|
279
|
+
readonly operations: ReadonlyArray<{
|
|
280
|
+
readonly id: string;
|
|
281
|
+
readonly label: string;
|
|
282
|
+
readonly operationClass: string;
|
|
283
|
+
}>;
|
|
284
|
+
readonly sql?: ReadonlyArray<string>;
|
|
285
|
+
};
|
|
286
|
+
readonly destination: {
|
|
287
|
+
readonly storageHash: string;
|
|
288
|
+
readonly profileHash?: string;
|
|
289
|
+
};
|
|
290
|
+
readonly execution?: {
|
|
291
|
+
readonly operationsPlanned: number;
|
|
292
|
+
readonly operationsExecuted: number;
|
|
293
|
+
};
|
|
294
|
+
readonly marker?: {
|
|
295
|
+
readonly storageHash: string;
|
|
296
|
+
readonly profileHash?: string;
|
|
297
|
+
};
|
|
298
|
+
readonly summary: string;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Failure codes for dbUpdate operation.
|
|
302
|
+
*/
|
|
303
|
+
type DbUpdateFailureCode = 'PLANNING_FAILED' | 'RUNNER_FAILED' | 'DESTRUCTIVE_CHANGES';
|
|
304
|
+
/**
|
|
305
|
+
* Failure details for dbUpdate operation.
|
|
306
|
+
*/
|
|
307
|
+
interface DbUpdateFailure {
|
|
308
|
+
readonly code: DbUpdateFailureCode;
|
|
309
|
+
readonly summary: string;
|
|
310
|
+
readonly why: string | undefined;
|
|
311
|
+
readonly conflicts: ReadonlyArray<MigrationPlannerConflict> | undefined;
|
|
312
|
+
readonly meta: Record<string, unknown> | undefined;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Result type for dbUpdate operation.
|
|
316
|
+
* Uses Result pattern: success returns DbUpdateSuccess, failure returns DbUpdateFailure.
|
|
317
|
+
*/
|
|
318
|
+
type DbUpdateResult = Result<DbUpdateSuccess, DbUpdateFailure>;
|
|
239
319
|
/**
|
|
240
320
|
* Successful emit result.
|
|
241
321
|
* Contains the hashes and paths of emitted files.
|
|
@@ -255,7 +335,7 @@ interface EmitSuccess {
|
|
|
255
335
|
/**
|
|
256
336
|
* Failure codes for emit operation.
|
|
257
337
|
*/
|
|
258
|
-
type EmitFailureCode = 'CONTRACT_SOURCE_INVALID' | 'EMIT_FAILED';
|
|
338
|
+
type EmitFailureCode = 'CONTRACT_SOURCE_INVALID' | 'CONTRACT_VALIDATION_FAILED' | 'EMIT_FAILED';
|
|
259
339
|
/**
|
|
260
340
|
* Failure details for emit operation.
|
|
261
341
|
*/
|
|
@@ -354,9 +434,9 @@ interface ControlClient {
|
|
|
354
434
|
*/
|
|
355
435
|
schemaVerify(options: SchemaVerifyOptions): Promise<VerifyDatabaseSchemaResult$1>;
|
|
356
436
|
/**
|
|
357
|
-
* Signs the database with a contract
|
|
358
|
-
* Writes or updates the
|
|
359
|
-
* Idempotent (no-op if
|
|
437
|
+
* Signs the database with a contract signature.
|
|
438
|
+
* Writes or updates the signature if schema verification passes.
|
|
439
|
+
* Idempotent (no-op if signature already matches).
|
|
360
440
|
*
|
|
361
441
|
* @returns Structured result
|
|
362
442
|
* @throws If not connected or infrastructure failure
|
|
@@ -371,6 +451,16 @@ interface ControlClient {
|
|
|
371
451
|
* @throws If not connected, target doesn't support migrations, or infrastructure failure
|
|
372
452
|
*/
|
|
373
453
|
dbInit(options: DbInitOptions): Promise<DbInitResult>;
|
|
454
|
+
/**
|
|
455
|
+
* Updates a database schema to match the current contract.
|
|
456
|
+
* Creates the signature table if it does not exist. No preconditions required.
|
|
457
|
+
* Allows additive, widening, and destructive operation classes.
|
|
458
|
+
*
|
|
459
|
+
* @param options.mode - 'plan' to preview, 'apply' to execute
|
|
460
|
+
* @returns Result pattern: Ok with planned/executed operations, NotOk with failure details
|
|
461
|
+
* @throws If not connected, target doesn't support migrations, or infrastructure failure
|
|
462
|
+
*/
|
|
463
|
+
dbUpdate(options: DbUpdateOptions): Promise<DbUpdateResult>;
|
|
374
464
|
/**
|
|
375
465
|
* Introspects the database schema.
|
|
376
466
|
*
|
|
@@ -429,5 +519,5 @@ declare function createControlClient(options: ControlClientOptions): ControlClie
|
|
|
429
519
|
*/
|
|
430
520
|
declare function executeContractEmit(options: ContractEmitOptions): Promise<ContractEmitResult>;
|
|
431
521
|
//#endregion
|
|
432
|
-
export { type ContractEmitOptions, type ContractEmitResult, type ControlActionName, type ControlClient, type ControlClientOptions, type ControlPlaneStack, type ControlProgressEvent, type DbInitFailure, type DbInitFailureCode, type DbInitOptions, type DbInitResult, type DbInitSuccess, type EmitContractConfig, type EmitFailure, type EmitFailureCode, type EmitOptions, type EmitResult, type EmitSuccess, type IntrospectOptions, type OnControlProgress, type SchemaVerifyOptions, type SignDatabaseResult, type SignOptions, type VerifyDatabaseResult, type VerifyDatabaseSchemaResult, type VerifyOptions, createControlClient, executeContractEmit };
|
|
522
|
+
export { type ContractEmitOptions, type ContractEmitResult, type ControlActionName, type ControlClient, type ControlClientOptions, type ControlPlaneStack, type ControlProgressEvent, type DbInitFailure, type DbInitFailureCode, type DbInitOptions, type DbInitResult, type DbInitSuccess, type DbUpdateFailure, type DbUpdateFailureCode, type DbUpdateOptions, type DbUpdateResult, type DbUpdateSuccess, type EmitContractConfig, type EmitFailure, type EmitFailureCode, type EmitOptions, type EmitResult, type EmitSuccess, type IntrospectOptions, type OnControlProgress, type SchemaVerifyOptions, type SignDatabaseResult, type SignOptions, type VerifyDatabaseResult, type VerifyDatabaseSchemaResult, type VerifyOptions, createControlClient, executeContractEmit };
|
|
433
523
|
//# sourceMappingURL=control-api.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control-api.d.mts","names":[],"sources":["../../src/control-api/types.ts","../../src/control-api/client.ts","../../src/control-api/operations/contract-emit.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AAiCA;;;;;;;;AA2BA;
|
|
1
|
+
{"version":3,"file":"control-api.d.mts","names":[],"sources":["../../src/control-api/types.ts","../../src/control-api/client.ts","../../src/control-api/operations/contract-emit.ts"],"sourcesContent":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as loadConfig } from "../config-loader-
|
|
2
|
-
import {
|
|
1
|
+
import { t as loadConfig } from "../config-loader-DqKf1qSa.mjs";
|
|
2
|
+
import { h as errorRuntime, i as errorContractConfigMissing, t as createControlClient } from "../client-B7f4PZZ1.mjs";
|
|
3
3
|
import { dirname, isAbsolute, join, resolve } from "pathe";
|
|
4
4
|
import { createControlPlaneStack } from "@prisma-next/core-control-plane/stack";
|
|
5
5
|
import { ifDefined } from "@prisma-next/utils/defined";
|
package/dist/exports/index.mjs
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import "../config-loader-
|
|
2
|
-
import "../client-BSZKpZTF.mjs";
|
|
3
|
-
import "../result-handler-BZPY7HX4.mjs";
|
|
1
|
+
import "../config-loader-DqKf1qSa.mjs";
|
|
4
2
|
import { createContractEmitCommand } from "../commands/contract-emit.mjs";
|
|
5
3
|
import { existsSync, unlinkSync, writeFileSync } from "node:fs";
|
|
6
4
|
import { join } from "node:path";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["value","disallowedImports: string[]","contract: unknown"],"sources":["../../src/load-ts-contract.ts"],"sourcesContent":["import { existsSync, unlinkSync, writeFileSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport type { ContractIR } from '@prisma-next/contract/ir';\nimport type { Plugin } from 'esbuild';\nimport { build } from 'esbuild';\n\nexport interface LoadTsContractOptions {\n readonly allowlist?: ReadonlyArray<string>;\n}\n\nconst DEFAULT_ALLOWLIST = ['@prisma-next/*'];\n\nfunction isAllowedImport(importPath: string, allowlist: ReadonlyArray<string>): boolean {\n for (const pattern of allowlist) {\n if (pattern.endsWith('/*')) {\n const prefix = pattern.slice(0, -2);\n if (importPath === prefix || importPath.startsWith(`${prefix}/`)) {\n return true;\n }\n } else if (importPath === pattern) {\n return true;\n }\n }\n return false;\n}\n\nfunction validatePurity(value: unknown): void {\n if (typeof value !== 'object' || value === null) {\n return;\n }\n\n const path = new WeakSet();\n\n function check(value: unknown): void {\n if (value === null || typeof value !== 'object') {\n return;\n }\n\n if (path.has(value)) {\n throw new Error('Contract export contains circular references');\n }\n path.add(value);\n\n try {\n for (const key in value) {\n const descriptor = Object.getOwnPropertyDescriptor(value, key);\n if (descriptor && (descriptor.get || descriptor.set)) {\n throw new Error(`Contract export contains getter/setter at key \"${key}\"`);\n }\n if (descriptor && typeof descriptor.value === 'function') {\n throw new Error(`Contract export contains function at key \"${key}\"`);\n }\n check((value as Record<string, unknown>)[key]);\n }\n } finally {\n path.delete(value);\n }\n }\n\n try {\n check(value);\n JSON.stringify(value);\n } catch (error) {\n if (error instanceof Error) {\n if (error.message.includes('getter') || error.message.includes('circular')) {\n throw error;\n }\n throw new Error(`Contract export is not JSON-serializable: ${error.message}`);\n }\n throw new Error('Contract export is not JSON-serializable');\n }\n}\n\nfunction createImportAllowlistPlugin(allowlist: ReadonlyArray<string>, entryPath: string): Plugin {\n return {\n name: 'import-allowlist',\n setup(build) {\n build.onResolve({ filter: /.*/ }, (args) => {\n if (args.kind === 'entry-point') {\n return undefined;\n }\n if (args.path.startsWith('.') || args.path.startsWith('/')) {\n return undefined;\n }\n const isFromEntryPoint = args.importer === entryPath || args.importer === '<stdin>';\n if (isFromEntryPoint && !isAllowedImport(args.path, allowlist)) {\n return {\n path: args.path,\n external: true,\n };\n }\n return undefined;\n });\n },\n };\n}\n\n/**\n * Loads a contract from a TypeScript file and returns it as ContractIR.\n *\n * **Responsibility: Parsing Only**\n * This function loads and parses a TypeScript contract file. It does NOT normalize the contract.\n * The contract should already be normalized if it was built using the contract builder.\n *\n * Normalization must happen in the contract builder when the contract is created.\n * This function only validates that the contract is JSON-serializable and returns it as-is.\n *\n * @param entryPath - Path to the TypeScript contract file\n * @param options - Optional configuration (import allowlist)\n * @returns The contract as ContractIR (should already be normalized)\n * @throws Error if the contract cannot be loaded or is not JSON-serializable\n */\nexport async function loadContractFromTs(\n entryPath: string,\n options?: LoadTsContractOptions,\n): Promise<ContractIR> {\n const allowlist = options?.allowlist ?? DEFAULT_ALLOWLIST;\n\n if (!existsSync(entryPath)) {\n throw new Error(`Contract file not found: ${entryPath}`);\n }\n\n const tempFile = join(\n tmpdir(),\n `prisma-next-contract-${Date.now()}-${Math.random().toString(36).slice(2)}.mjs`,\n );\n\n try {\n const result = await build({\n entryPoints: [entryPath],\n bundle: true,\n format: 'esm',\n platform: 'node',\n target: 'es2022',\n outfile: tempFile,\n write: false,\n metafile: true,\n plugins: [createImportAllowlistPlugin(allowlist, entryPath)],\n logLevel: 'error',\n });\n\n if (result.errors.length > 0) {\n const errorMessages = result.errors.map((e: { text: string }) => e.text).join('\\n');\n throw new Error(`Failed to bundle contract file: ${errorMessages}`);\n }\n\n if (!result.outputFiles || result.outputFiles.length === 0) {\n throw new Error('No output files generated from bundling');\n }\n\n const disallowedImports: string[] = [];\n if (result.metafile) {\n const inputs = result.metafile.inputs;\n for (const [, inputData] of Object.entries(inputs)) {\n const imports =\n (inputData as { imports?: Array<{ path: string; external?: boolean }> }).imports || [];\n for (const imp of imports) {\n if (\n imp.external &&\n !imp.path.startsWith('.') &&\n !imp.path.startsWith('/') &&\n !isAllowedImport(imp.path, allowlist)\n ) {\n disallowedImports.push(imp.path);\n }\n }\n }\n }\n\n if (disallowedImports.length > 0) {\n throw new Error(\n `Disallowed imports detected. Only imports matching the allowlist are permitted:\\n Allowlist: ${allowlist.join(', ')}\\n Disallowed imports: ${disallowedImports.join(', ')}\\n\\nOnly @prisma-next/* packages are allowed in contract files.`,\n );\n }\n\n const bundleContent = result.outputFiles[0]?.text;\n if (bundleContent === undefined) {\n throw new Error('Bundle content is undefined');\n }\n writeFileSync(tempFile, bundleContent, 'utf-8');\n\n const module = (await import(`file://${tempFile}`)) as {\n default?: unknown;\n contract?: unknown;\n };\n unlinkSync(tempFile);\n\n let contract: unknown;\n\n if (module.default !== undefined) {\n contract = module.default;\n } else if (module.contract !== undefined) {\n contract = module.contract;\n } else {\n throw new Error(\n `Contract file must export a contract as default export or named export 'contract'. Found exports: ${Object.keys(module as Record<string, unknown>).join(', ') || 'none'}`,\n );\n }\n\n if (typeof contract !== 'object' || contract === null) {\n throw new Error(`Contract export must be an object, got ${typeof contract}`);\n }\n\n validatePurity(contract);\n\n return contract as ContractIR;\n } catch (error) {\n try {\n if (tempFile) {\n unlinkSync(tempFile);\n }\n } catch {\n // Ignore cleanup errors\n }\n\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Failed to load contract from ${entryPath}: ${String(error)}`);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["value","disallowedImports: string[]","contract: unknown"],"sources":["../../src/load-ts-contract.ts"],"sourcesContent":["import { existsSync, unlinkSync, writeFileSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport type { ContractIR } from '@prisma-next/contract/ir';\nimport type { Plugin } from 'esbuild';\nimport { build } from 'esbuild';\n\nexport interface LoadTsContractOptions {\n readonly allowlist?: ReadonlyArray<string>;\n}\n\nconst DEFAULT_ALLOWLIST = ['@prisma-next/*'];\n\nfunction isAllowedImport(importPath: string, allowlist: ReadonlyArray<string>): boolean {\n for (const pattern of allowlist) {\n if (pattern.endsWith('/*')) {\n const prefix = pattern.slice(0, -2);\n if (importPath === prefix || importPath.startsWith(`${prefix}/`)) {\n return true;\n }\n } else if (importPath === pattern) {\n return true;\n }\n }\n return false;\n}\n\nfunction validatePurity(value: unknown): void {\n if (typeof value !== 'object' || value === null) {\n return;\n }\n\n const path = new WeakSet();\n\n function check(value: unknown): void {\n if (value === null || typeof value !== 'object') {\n return;\n }\n\n if (path.has(value)) {\n throw new Error('Contract export contains circular references');\n }\n path.add(value);\n\n try {\n for (const key in value) {\n const descriptor = Object.getOwnPropertyDescriptor(value, key);\n if (descriptor && (descriptor.get || descriptor.set)) {\n throw new Error(`Contract export contains getter/setter at key \"${key}\"`);\n }\n if (descriptor && typeof descriptor.value === 'function') {\n throw new Error(`Contract export contains function at key \"${key}\"`);\n }\n check((value as Record<string, unknown>)[key]);\n }\n } finally {\n path.delete(value);\n }\n }\n\n try {\n check(value);\n JSON.stringify(value);\n } catch (error) {\n if (error instanceof Error) {\n if (error.message.includes('getter') || error.message.includes('circular')) {\n throw error;\n }\n throw new Error(`Contract export is not JSON-serializable: ${error.message}`);\n }\n throw new Error('Contract export is not JSON-serializable');\n }\n}\n\nfunction createImportAllowlistPlugin(allowlist: ReadonlyArray<string>, entryPath: string): Plugin {\n return {\n name: 'import-allowlist',\n setup(build) {\n build.onResolve({ filter: /.*/ }, (args) => {\n if (args.kind === 'entry-point') {\n return undefined;\n }\n if (args.path.startsWith('.') || args.path.startsWith('/')) {\n return undefined;\n }\n const isFromEntryPoint = args.importer === entryPath || args.importer === '<stdin>';\n if (isFromEntryPoint && !isAllowedImport(args.path, allowlist)) {\n return {\n path: args.path,\n external: true,\n };\n }\n return undefined;\n });\n },\n };\n}\n\n/**\n * Loads a contract from a TypeScript file and returns it as ContractIR.\n *\n * **Responsibility: Parsing Only**\n * This function loads and parses a TypeScript contract file. It does NOT normalize the contract.\n * The contract should already be normalized if it was built using the contract builder.\n *\n * Normalization must happen in the contract builder when the contract is created.\n * This function only validates that the contract is JSON-serializable and returns it as-is.\n *\n * @param entryPath - Path to the TypeScript contract file\n * @param options - Optional configuration (import allowlist)\n * @returns The contract as ContractIR (should already be normalized)\n * @throws Error if the contract cannot be loaded or is not JSON-serializable\n */\nexport async function loadContractFromTs(\n entryPath: string,\n options?: LoadTsContractOptions,\n): Promise<ContractIR> {\n const allowlist = options?.allowlist ?? DEFAULT_ALLOWLIST;\n\n if (!existsSync(entryPath)) {\n throw new Error(`Contract file not found: ${entryPath}`);\n }\n\n const tempFile = join(\n tmpdir(),\n `prisma-next-contract-${Date.now()}-${Math.random().toString(36).slice(2)}.mjs`,\n );\n\n try {\n const result = await build({\n entryPoints: [entryPath],\n bundle: true,\n format: 'esm',\n platform: 'node',\n target: 'es2022',\n outfile: tempFile,\n write: false,\n metafile: true,\n plugins: [createImportAllowlistPlugin(allowlist, entryPath)],\n logLevel: 'error',\n });\n\n if (result.errors.length > 0) {\n const errorMessages = result.errors.map((e: { text: string }) => e.text).join('\\n');\n throw new Error(`Failed to bundle contract file: ${errorMessages}`);\n }\n\n if (!result.outputFiles || result.outputFiles.length === 0) {\n throw new Error('No output files generated from bundling');\n }\n\n const disallowedImports: string[] = [];\n if (result.metafile) {\n const inputs = result.metafile.inputs;\n for (const [, inputData] of Object.entries(inputs)) {\n const imports =\n (inputData as { imports?: Array<{ path: string; external?: boolean }> }).imports || [];\n for (const imp of imports) {\n if (\n imp.external &&\n !imp.path.startsWith('.') &&\n !imp.path.startsWith('/') &&\n !isAllowedImport(imp.path, allowlist)\n ) {\n disallowedImports.push(imp.path);\n }\n }\n }\n }\n\n if (disallowedImports.length > 0) {\n throw new Error(\n `Disallowed imports detected. Only imports matching the allowlist are permitted:\\n Allowlist: ${allowlist.join(', ')}\\n Disallowed imports: ${disallowedImports.join(', ')}\\n\\nOnly @prisma-next/* packages are allowed in contract files.`,\n );\n }\n\n const bundleContent = result.outputFiles[0]?.text;\n if (bundleContent === undefined) {\n throw new Error('Bundle content is undefined');\n }\n writeFileSync(tempFile, bundleContent, 'utf-8');\n\n const module = (await import(`file://${tempFile}`)) as {\n default?: unknown;\n contract?: unknown;\n };\n unlinkSync(tempFile);\n\n let contract: unknown;\n\n if (module.default !== undefined) {\n contract = module.default;\n } else if (module.contract !== undefined) {\n contract = module.contract;\n } else {\n throw new Error(\n `Contract file must export a contract as default export or named export 'contract'. Found exports: ${Object.keys(module as Record<string, unknown>).join(', ') || 'none'}`,\n );\n }\n\n if (typeof contract !== 'object' || contract === null) {\n throw new Error(`Contract export must be an object, got ${typeof contract}`);\n }\n\n validatePurity(contract);\n\n return contract as ContractIR;\n } catch (error) {\n try {\n if (tempFile) {\n unlinkSync(tempFile);\n }\n } catch {\n // Ignore cleanup errors\n }\n\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Failed to load contract from ${entryPath}: ${String(error)}`);\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { t as loadConfig } from "./config-loader-DqKf1qSa.mjs";
|
|
2
|
+
import { a as errorContractValidationFailed, c as errorDriverRequired, g as errorTargetMigrationNotSupported, l as errorFileNotFound, o as errorDatabaseConnectionRequired, t as createControlClient, v as errorUnexpected } from "./client-B7f4PZZ1.mjs";
|
|
3
|
+
import { g as formatStyledHeader, n as createProgressAdapter, x as maskConnectionUrl } from "./result-handler-BhmrXIvT.mjs";
|
|
4
|
+
import { notOk, ok } from "@prisma-next/utils/result";
|
|
5
|
+
import { relative, resolve } from "node:path";
|
|
6
|
+
import { readFile } from "node:fs/promises";
|
|
7
|
+
|
|
8
|
+
//#region src/utils/migration-command-scaffold.ts
|
|
9
|
+
/**
|
|
10
|
+
* Prepares the shared context for migration commands (db init, db update).
|
|
11
|
+
*
|
|
12
|
+
* Handles: config loading, contract file reading, JSON parsing, connection resolution,
|
|
13
|
+
* driver/migration-support validation, client creation, and header output.
|
|
14
|
+
*
|
|
15
|
+
* Returns a Result with either the resolved context or a structured error.
|
|
16
|
+
*/
|
|
17
|
+
async function prepareMigrationContext(options, flags, descriptor) {
|
|
18
|
+
const config = await loadConfig(options.config);
|
|
19
|
+
const configPath = options.config ? relative(process.cwd(), resolve(options.config)) : "prisma-next.config.ts";
|
|
20
|
+
const contractPathAbsolute = config.contract?.output ? resolve(config.contract.output) : resolve("src/prisma/contract.json");
|
|
21
|
+
const contractPath = relative(process.cwd(), contractPathAbsolute);
|
|
22
|
+
if (flags.json !== "object" && !flags.quiet) {
|
|
23
|
+
const details = [{
|
|
24
|
+
label: "config",
|
|
25
|
+
value: configPath
|
|
26
|
+
}, {
|
|
27
|
+
label: "contract",
|
|
28
|
+
value: contractPath
|
|
29
|
+
}];
|
|
30
|
+
if (options.db) details.push({
|
|
31
|
+
label: "database",
|
|
32
|
+
value: maskConnectionUrl(options.db)
|
|
33
|
+
});
|
|
34
|
+
if (options.plan) details.push({
|
|
35
|
+
label: "mode",
|
|
36
|
+
value: "plan (dry run)"
|
|
37
|
+
});
|
|
38
|
+
const header = formatStyledHeader({
|
|
39
|
+
command: descriptor.commandName,
|
|
40
|
+
description: descriptor.description,
|
|
41
|
+
url: descriptor.url,
|
|
42
|
+
details,
|
|
43
|
+
flags
|
|
44
|
+
});
|
|
45
|
+
console.log(header);
|
|
46
|
+
}
|
|
47
|
+
let contractJsonContent;
|
|
48
|
+
try {
|
|
49
|
+
contractJsonContent = await readFile(contractPathAbsolute, "utf-8");
|
|
50
|
+
} catch (error) {
|
|
51
|
+
if (error instanceof Error && error.code === "ENOENT") return notOk(errorFileNotFound(contractPathAbsolute, {
|
|
52
|
+
why: `Contract file not found at ${contractPathAbsolute}`,
|
|
53
|
+
fix: `Run \`prisma-next contract emit\` to generate ${contractPath}, or update \`config.contract.output\` in ${configPath}`
|
|
54
|
+
}));
|
|
55
|
+
return notOk(errorUnexpected(error instanceof Error ? error.message : String(error), { why: `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}` }));
|
|
56
|
+
}
|
|
57
|
+
let contractJson;
|
|
58
|
+
try {
|
|
59
|
+
contractJson = JSON.parse(contractJsonContent);
|
|
60
|
+
} catch (error) {
|
|
61
|
+
return notOk(errorContractValidationFailed(`Contract JSON is invalid: ${error instanceof Error ? error.message : String(error)}`, { where: { path: contractPathAbsolute } }));
|
|
62
|
+
}
|
|
63
|
+
const dbConnection = options.db ?? config.db?.connection;
|
|
64
|
+
if (!dbConnection) return notOk(errorDatabaseConnectionRequired({ why: `Database connection is required for ${descriptor.commandName} (set db.connection in ${configPath}, or pass --db <url>)` }));
|
|
65
|
+
if (!config.driver) return notOk(errorDriverRequired({ why: `Config.driver is required for ${descriptor.commandName}` }));
|
|
66
|
+
if (!config.target.migrations) return notOk(errorTargetMigrationNotSupported({ why: `Target "${config.target.id}" does not support migrations` }));
|
|
67
|
+
const client = createControlClient({
|
|
68
|
+
family: config.family,
|
|
69
|
+
target: config.target,
|
|
70
|
+
adapter: config.adapter,
|
|
71
|
+
driver: config.driver,
|
|
72
|
+
extensionPacks: config.extensionPacks ?? []
|
|
73
|
+
});
|
|
74
|
+
const onProgress = createProgressAdapter({ flags });
|
|
75
|
+
return ok({
|
|
76
|
+
client,
|
|
77
|
+
contractJson,
|
|
78
|
+
dbConnection,
|
|
79
|
+
onProgress,
|
|
80
|
+
configPath,
|
|
81
|
+
contractPath,
|
|
82
|
+
contractPathAbsolute,
|
|
83
|
+
config
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Registers the shared CLI options for migration commands (db init, db update).
|
|
88
|
+
*/
|
|
89
|
+
function addMigrationCommandOptions(command) {
|
|
90
|
+
return command.option("--db <url>", "Database connection string").option("--config <path>", "Path to prisma-next.config.ts").option("--plan", "Preview planned operations without applying", false).option("--json [format]", "Output as JSON (object)", false).option("-q, --quiet", "Quiet mode: errors only").option("-v, --verbose", "Verbose output: debug info, timings").option("-vv, --trace", "Trace output: deep internals, stack traces").option("--timestamps", "Add timestamps to output").option("--color", "Force color output").option("--no-color", "Disable color output");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
//#endregion
|
|
94
|
+
export { prepareMigrationContext as n, addMigrationCommandOptions as t };
|
|
95
|
+
//# sourceMappingURL=migration-command-scaffold-BELw_do2.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration-command-scaffold-BELw_do2.mjs","names":["details: Array<{ label: string; value: string }>","contractJsonContent: string","contractJson: Record<string, unknown>"],"sources":["../src/utils/migration-command-scaffold.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { relative, resolve } from 'node:path';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport type { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport { createControlClient } from '../control-api/client';\nimport type { ControlClient } from '../control-api/types';\nimport {\n type CliStructuredError,\n errorContractValidationFailed,\n errorDatabaseConnectionRequired,\n errorDriverRequired,\n errorFileNotFound,\n errorTargetMigrationNotSupported,\n errorUnexpected,\n} from './cli-errors';\nimport { maskConnectionUrl } from './command-helpers';\nimport type { GlobalFlags } from './global-flags';\nimport { formatStyledHeader } from './output';\nimport { createProgressAdapter } from './progress-adapter';\n\n/**\n * Resolved context for a migration command.\n * Contains everything needed to invoke a control-api operation.\n */\nexport interface MigrationContext {\n readonly client: ControlClient;\n readonly contractJson: Record<string, unknown>;\n readonly dbConnection: unknown;\n readonly onProgress: ReturnType<typeof createProgressAdapter>;\n readonly configPath: string;\n readonly contractPath: string;\n readonly contractPathAbsolute: string;\n readonly config: Awaited<ReturnType<typeof loadConfig>>;\n}\n\n/**\n * Command-specific configuration for the shared scaffold.\n */\nexport interface MigrationCommandDescriptor {\n readonly commandName: string;\n readonly description: string;\n readonly url: string;\n}\n\n/**\n * Prepares the shared context for migration commands (db init, db update).\n *\n * Handles: config loading, contract file reading, JSON parsing, connection resolution,\n * driver/migration-support validation, client creation, and header output.\n *\n * Returns a Result with either the resolved context or a structured error.\n */\nexport async function prepareMigrationContext(\n options: { readonly db?: string; readonly config?: string; readonly plan?: boolean },\n flags: GlobalFlags,\n descriptor: MigrationCommandDescriptor,\n): Promise<Result<MigrationContext, CliStructuredError>> {\n // Load config\n const config = await loadConfig(options.config);\n const configPath = options.config\n ? relative(process.cwd(), resolve(options.config))\n : 'prisma-next.config.ts';\n const contractPathAbsolute = config.contract?.output\n ? resolve(config.contract.output)\n : resolve('src/prisma/contract.json');\n const contractPath = relative(process.cwd(), contractPathAbsolute);\n\n // Output header\n if (flags.json !== 'object' && !flags.quiet) {\n const details: Array<{ label: string; value: string }> = [\n { label: 'config', value: configPath },\n { label: 'contract', value: contractPath },\n ];\n if (options.db) {\n details.push({ label: 'database', value: maskConnectionUrl(options.db) });\n }\n if (options.plan) {\n details.push({ label: 'mode', value: 'plan (dry run)' });\n }\n const header = formatStyledHeader({\n command: descriptor.commandName,\n description: descriptor.description,\n url: descriptor.url,\n details,\n flags,\n });\n console.log(header);\n }\n\n // Load contract file\n let contractJsonContent: string;\n try {\n contractJsonContent = await readFile(contractPathAbsolute, 'utf-8');\n } catch (error) {\n if (error instanceof Error && (error as { code?: string }).code === 'ENOENT') {\n return notOk(\n errorFileNotFound(contractPathAbsolute, {\n why: `Contract file not found at ${contractPathAbsolute}`,\n fix: `Run \\`prisma-next contract emit\\` to generate ${contractPath}, or update \\`config.contract.output\\` in ${configPath}`,\n }),\n );\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n\n // Parse contract JSON\n let contractJson: Record<string, unknown>;\n try {\n contractJson = JSON.parse(contractJsonContent) as Record<string, unknown>;\n } catch (error) {\n return notOk(\n errorContractValidationFailed(\n `Contract JSON is invalid: ${error instanceof Error ? error.message : String(error)}`,\n { where: { path: contractPathAbsolute } },\n ),\n );\n }\n\n // Resolve database connection (--db flag or config.db.connection)\n const dbConnection = options.db ?? config.db?.connection;\n if (!dbConnection) {\n return notOk(\n errorDatabaseConnectionRequired({\n why: `Database connection is required for ${descriptor.commandName} (set db.connection in ${configPath}, or pass --db <url>)`,\n }),\n );\n }\n\n // Check for driver\n if (!config.driver) {\n return notOk(\n errorDriverRequired({ why: `Config.driver is required for ${descriptor.commandName}` }),\n );\n }\n\n // Check target supports migrations\n if (!config.target.migrations) {\n return notOk(\n errorTargetMigrationNotSupported({\n why: `Target \"${config.target.id}\" does not support migrations`,\n }),\n );\n }\n\n // Create control client\n const client = createControlClient({\n family: config.family,\n target: config.target,\n adapter: config.adapter,\n driver: config.driver,\n extensionPacks: config.extensionPacks ?? [],\n });\n\n // Create progress adapter\n const onProgress = createProgressAdapter({ flags });\n\n return ok({\n client,\n contractJson,\n dbConnection,\n onProgress,\n configPath,\n contractPath,\n contractPathAbsolute,\n config,\n });\n}\n\n/**\n * Registers the shared CLI options for migration commands (db init, db update).\n */\nexport function addMigrationCommandOptions(command: Command): Command {\n return command\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--plan', 'Preview planned operations without applying', false)\n .option('--json [format]', 'Output as JSON (object)', false)\n .option('-q, --quiet', 'Quiet mode: errors only')\n .option('-v, --verbose', 'Verbose output: debug info, timings')\n .option('-vv, --trace', 'Trace output: deep internals, stack traces')\n .option('--timestamps', 'Add timestamps to output')\n .option('--color', 'Force color output')\n .option('--no-color', 'Disable color output');\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAqDA,eAAsB,wBACpB,SACA,OACA,YACuD;CAEvD,MAAM,SAAS,MAAM,WAAW,QAAQ,OAAO;CAC/C,MAAM,aAAa,QAAQ,SACvB,SAAS,QAAQ,KAAK,EAAE,QAAQ,QAAQ,OAAO,CAAC,GAChD;CACJ,MAAM,uBAAuB,OAAO,UAAU,SAC1C,QAAQ,OAAO,SAAS,OAAO,GAC/B,QAAQ,2BAA2B;CACvC,MAAM,eAAe,SAAS,QAAQ,KAAK,EAAE,qBAAqB;AAGlE,KAAI,MAAM,SAAS,YAAY,CAAC,MAAM,OAAO;EAC3C,MAAMA,UAAmD,CACvD;GAAE,OAAO;GAAU,OAAO;GAAY,EACtC;GAAE,OAAO;GAAY,OAAO;GAAc,CAC3C;AACD,MAAI,QAAQ,GACV,SAAQ,KAAK;GAAE,OAAO;GAAY,OAAO,kBAAkB,QAAQ,GAAG;GAAE,CAAC;AAE3E,MAAI,QAAQ,KACV,SAAQ,KAAK;GAAE,OAAO;GAAQ,OAAO;GAAkB,CAAC;EAE1D,MAAM,SAAS,mBAAmB;GAChC,SAAS,WAAW;GACpB,aAAa,WAAW;GACxB,KAAK,WAAW;GAChB;GACA;GACD,CAAC;AACF,UAAQ,IAAI,OAAO;;CAIrB,IAAIC;AACJ,KAAI;AACF,wBAAsB,MAAM,SAAS,sBAAsB,QAAQ;UAC5D,OAAO;AACd,MAAI,iBAAiB,SAAU,MAA4B,SAAS,SAClE,QAAO,MACL,kBAAkB,sBAAsB;GACtC,KAAK,8BAA8B;GACnC,KAAK,iDAAiD,aAAa,4CAA4C;GAChH,CAAC,CACH;AAEH,SAAO,MACL,gBAAgB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EAAE,EACtE,KAAK,iCAAiC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,IAC7F,CAAC,CACH;;CAIH,IAAIC;AACJ,KAAI;AACF,iBAAe,KAAK,MAAM,oBAAoB;UACvC,OAAO;AACd,SAAO,MACL,8BACE,6BAA6B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,IACnF,EAAE,OAAO,EAAE,MAAM,sBAAsB,EAAE,CAC1C,CACF;;CAIH,MAAM,eAAe,QAAQ,MAAM,OAAO,IAAI;AAC9C,KAAI,CAAC,aACH,QAAO,MACL,gCAAgC,EAC9B,KAAK,uCAAuC,WAAW,YAAY,yBAAyB,WAAW,wBACxG,CAAC,CACH;AAIH,KAAI,CAAC,OAAO,OACV,QAAO,MACL,oBAAoB,EAAE,KAAK,iCAAiC,WAAW,eAAe,CAAC,CACxF;AAIH,KAAI,CAAC,OAAO,OAAO,WACjB,QAAO,MACL,iCAAiC,EAC/B,KAAK,WAAW,OAAO,OAAO,GAAG,gCAClC,CAAC,CACH;CAIH,MAAM,SAAS,oBAAoB;EACjC,QAAQ,OAAO;EACf,QAAQ,OAAO;EACf,SAAS,OAAO;EAChB,QAAQ,OAAO;EACf,gBAAgB,OAAO,kBAAkB,EAAE;EAC5C,CAAC;CAGF,MAAM,aAAa,sBAAsB,EAAE,OAAO,CAAC;AAEnD,QAAO,GAAG;EACR;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;;;;;AAMJ,SAAgB,2BAA2B,SAA2B;AACpE,QAAO,QACJ,OAAO,cAAc,6BAA6B,CAClD,OAAO,mBAAmB,gCAAgC,CAC1D,OAAO,UAAU,+CAA+C,MAAM,CACtE,OAAO,mBAAmB,2BAA2B,MAAM,CAC3D,OAAO,eAAe,0BAA0B,CAChD,OAAO,iBAAiB,sCAAsC,CAC9D,OAAO,gBAAgB,6CAA6C,CACpE,OAAO,gBAAgB,2BAA2B,CAClD,OAAO,WAAW,qBAAqB,CACvC,OAAO,cAAc,uBAAuB"}
|
|
@@ -7,6 +7,7 @@ import wrapAnsi from "wrap-ansi";
|
|
|
7
7
|
import ora from "ora";
|
|
8
8
|
|
|
9
9
|
//#region src/utils/command-helpers.ts
|
|
10
|
+
const longDescriptions = /* @__PURE__ */ new WeakMap();
|
|
10
11
|
/**
|
|
11
12
|
* Sets both short and long descriptions for a command.
|
|
12
13
|
* The short description is used in command trees and headers.
|
|
@@ -14,14 +15,46 @@ import ora from "ora";
|
|
|
14
15
|
*/
|
|
15
16
|
function setCommandDescriptions(command, shortDescription, longDescription) {
|
|
16
17
|
command.description(shortDescription);
|
|
17
|
-
if (longDescription) command
|
|
18
|
+
if (longDescription) longDescriptions.set(command, longDescription);
|
|
18
19
|
return command;
|
|
19
20
|
}
|
|
20
21
|
/**
|
|
21
22
|
* Gets the long description from a command if it was set via setCommandDescriptions.
|
|
22
23
|
*/
|
|
23
24
|
function getLongDescription(command) {
|
|
24
|
-
return command
|
|
25
|
+
return longDescriptions.get(command);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Masks credentials in a database connection URL.
|
|
29
|
+
* Handles standard URLs (username + password + query params) and libpq-style key=value strings.
|
|
30
|
+
*/
|
|
31
|
+
function maskConnectionUrl(url) {
|
|
32
|
+
try {
|
|
33
|
+
const parsed = new URL(url);
|
|
34
|
+
if (parsed.username) parsed.username = "****";
|
|
35
|
+
if (parsed.password) parsed.password = "****";
|
|
36
|
+
for (const key of [...parsed.searchParams.keys()]) if (/password/i.test(key)) parsed.searchParams.set(key, "****");
|
|
37
|
+
return parsed.toString();
|
|
38
|
+
} catch {
|
|
39
|
+
return url.replace(/password\s*=\s*\S+/gi, "password=****").replace(/user\s*=\s*\S+/gi, "user=****");
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Strips raw connection URL fragments from an error message to prevent credential leakage.
|
|
44
|
+
* Call this before surfacing driver errors to the user.
|
|
45
|
+
*/
|
|
46
|
+
function sanitizeErrorMessage(message, connectionUrl) {
|
|
47
|
+
if (!connectionUrl) return message;
|
|
48
|
+
try {
|
|
49
|
+
const parsed = new URL(connectionUrl);
|
|
50
|
+
let sanitized = message;
|
|
51
|
+
sanitized = sanitized.replaceAll(connectionUrl, maskConnectionUrl(connectionUrl));
|
|
52
|
+
if (parsed.password) sanitized = sanitized.replaceAll(parsed.password, "****");
|
|
53
|
+
if (parsed.username) sanitized = sanitized.replaceAll(parsed.username, "****");
|
|
54
|
+
return sanitized;
|
|
55
|
+
} catch {
|
|
56
|
+
return message.replace(/password\s*=\s*\S+/gi, "password=****").replace(/user\s*=\s*\S+/gi, "user=****");
|
|
57
|
+
}
|
|
25
58
|
}
|
|
26
59
|
|
|
27
60
|
//#endregion
|
|
@@ -542,9 +575,9 @@ function formatSignJson(result) {
|
|
|
542
575
|
return JSON.stringify(result, null, 2);
|
|
543
576
|
}
|
|
544
577
|
/**
|
|
545
|
-
* Formats human-readable output for db init plan mode.
|
|
578
|
+
* Formats human-readable output for migration commands (db init, db update) in plan mode.
|
|
546
579
|
*/
|
|
547
|
-
function
|
|
580
|
+
function formatMigrationPlanOutput(result, flags) {
|
|
548
581
|
if (flags.quiet) return "";
|
|
549
582
|
const lines = [];
|
|
550
583
|
const prefix = createPrefix(flags);
|
|
@@ -567,6 +600,21 @@ function formatDbInitPlanOutput(result, flags) {
|
|
|
567
600
|
lines.push(`${prefix}`);
|
|
568
601
|
lines.push(`${prefix}${formatDimText(`Destination hash: ${result.plan.destination.storageHash}`)}`);
|
|
569
602
|
}
|
|
603
|
+
const planSql = result.plan?.sql;
|
|
604
|
+
if (planSql) {
|
|
605
|
+
lines.push(`${prefix}`);
|
|
606
|
+
lines.push(`${prefix}${formatDimText("DDL preview")}`);
|
|
607
|
+
if (planSql.length === 0) lines.push(`${prefix}${formatDimText("No DDL operations.")}`);
|
|
608
|
+
else {
|
|
609
|
+
lines.push(`${prefix}`);
|
|
610
|
+
for (const statement of planSql) {
|
|
611
|
+
const trimmed = statement.trim();
|
|
612
|
+
if (!trimmed) continue;
|
|
613
|
+
const line = trimmed.endsWith(";") ? trimmed : `${trimmed};`;
|
|
614
|
+
lines.push(`${prefix}${line}`);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
570
618
|
if (isVerbose(flags, 1)) lines.push(`${prefix}${formatDimText(`Total time: ${result.timings.total}ms`)}`);
|
|
571
619
|
lines.push(`${prefix}`);
|
|
572
620
|
lines.push(`${prefix}${formatDimText("This is a dry run. No changes were applied.")}`);
|
|
@@ -574,9 +622,9 @@ function formatDbInitPlanOutput(result, flags) {
|
|
|
574
622
|
return lines.join("\n");
|
|
575
623
|
}
|
|
576
624
|
/**
|
|
577
|
-
* Formats human-readable output for db init apply mode.
|
|
625
|
+
* Formats human-readable output for migration commands (db init, db update) in apply mode.
|
|
578
626
|
*/
|
|
579
|
-
function
|
|
627
|
+
function formatMigrationApplyOutput(result, flags) {
|
|
580
628
|
if (flags.quiet) return "";
|
|
581
629
|
const lines = [];
|
|
582
630
|
const prefix = createPrefix(flags);
|
|
@@ -585,9 +633,10 @@ function formatDbInitApplyOutput(result, flags) {
|
|
|
585
633
|
const formatDimText = (text) => formatDim(useColor, text);
|
|
586
634
|
if (result.ok) {
|
|
587
635
|
const executed = result.execution?.operationsExecuted ?? 0;
|
|
588
|
-
lines.push(`${prefix}${formatGreen("✔")}
|
|
636
|
+
if (executed === 0) lines.push(`${prefix}${formatGreen("✔")} Database already matches contract`);
|
|
637
|
+
else lines.push(`${prefix}${formatGreen("✔")} Applied ${executed} operation(s)`);
|
|
589
638
|
if (result.marker) {
|
|
590
|
-
lines.push(`${prefix}${formatDimText(`
|
|
639
|
+
lines.push(`${prefix}${formatDimText(` Signature: ${result.marker.storageHash}`)}`);
|
|
591
640
|
if (result.marker.profileHash) lines.push(`${prefix}${formatDimText(` Profile hash: ${result.marker.profileHash}`)}`);
|
|
592
641
|
}
|
|
593
642
|
if (isVerbose(flags, 1)) lines.push(`${prefix}${formatDimText(` Total time: ${result.timings.total}ms`)}`);
|
|
@@ -595,9 +644,9 @@ function formatDbInitApplyOutput(result, flags) {
|
|
|
595
644
|
return lines.join("\n");
|
|
596
645
|
}
|
|
597
646
|
/**
|
|
598
|
-
* Formats JSON output for db init
|
|
647
|
+
* Formats JSON output for migration commands (db init, db update).
|
|
599
648
|
*/
|
|
600
|
-
function
|
|
649
|
+
function formatMigrationJson(result) {
|
|
601
650
|
return JSON.stringify(result, null, 2);
|
|
602
651
|
}
|
|
603
652
|
/**
|
|
@@ -793,7 +842,8 @@ function formatSuccessMessage(flags) {
|
|
|
793
842
|
function getCommandDocsUrl(commandPath) {
|
|
794
843
|
return {
|
|
795
844
|
"contract emit": "https://pris.ly/contract-emit",
|
|
796
|
-
"db verify": "https://pris.ly/db-verify"
|
|
845
|
+
"db verify": "https://pris.ly/db-verify",
|
|
846
|
+
"db update": "https://pris.ly/db-update"
|
|
797
847
|
}[commandPath];
|
|
798
848
|
}
|
|
799
849
|
/**
|
|
@@ -1025,5 +1075,5 @@ function handleResult(result, flags, onSuccess) {
|
|
|
1025
1075
|
}
|
|
1026
1076
|
|
|
1027
1077
|
//#endregion
|
|
1028
|
-
export { formatSuccessMessage as _,
|
|
1029
|
-
//# sourceMappingURL=result-handler-
|
|
1078
|
+
export { setCommandDescriptions as C, sanitizeErrorMessage as S, formatSuccessMessage as _, formatEmitOutput as a, parseGlobalFlags as b, formatMigrationApplyOutput as c, formatRootHelp as d, formatSchemaVerifyJson as f, formatStyledHeader as g, formatSignOutput as h, formatEmitJson as i, formatMigrationJson as l, formatSignJson as m, createProgressAdapter as n, formatIntrospectJson as o, formatSchemaVerifyOutput as p, formatCommandHelp as r, formatIntrospectOutput as s, handleResult as t, formatMigrationPlanOutput as u, formatVerifyJson as v, maskConnectionUrl as x, formatVerifyOutput as y };
|
|
1079
|
+
//# sourceMappingURL=result-handler-BhmrXIvT.mjs.map
|