@prisma-next/cli 0.3.0-dev.12 → 0.3.0-dev.122
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/LICENSE +201 -0
- package/README.md +470 -134
- package/dist/cli-errors-ByGuoqNj.mjs +3 -0
- package/dist/cli-errors-D6HxRn3A.d.mts +2 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.js +1 -2350
- package/dist/cli.mjs +242 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/client-612RJJD_.mjs +1069 -0
- package/dist/client-612RJJD_.mjs.map +1 -0
- package/dist/commands/contract-emit.d.mts +7 -0
- package/dist/commands/contract-emit.d.mts.map +1 -0
- package/dist/commands/contract-emit.mjs +8 -0
- package/dist/commands/contract-infer.d.mts +7 -0
- package/dist/commands/contract-infer.d.mts.map +1 -0
- package/dist/commands/contract-infer.mjs +9 -0
- package/dist/commands/db-init.d.mts +7 -0
- package/dist/commands/db-init.d.mts.map +1 -0
- package/dist/commands/db-init.mjs +125 -0
- package/dist/commands/db-init.mjs.map +1 -0
- package/dist/commands/db-schema.d.mts +7 -0
- package/dist/commands/db-schema.d.mts.map +1 -0
- package/dist/commands/db-schema.mjs +55 -0
- package/dist/commands/db-schema.mjs.map +1 -0
- package/dist/commands/db-sign.d.mts +7 -0
- package/dist/commands/db-sign.d.mts.map +1 -0
- package/dist/commands/db-sign.mjs +136 -0
- package/dist/commands/db-sign.mjs.map +1 -0
- 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 +122 -0
- package/dist/commands/db-update.mjs.map +1 -0
- package/dist/commands/db-verify.d.mts +7 -0
- package/dist/commands/db-verify.d.mts.map +1 -0
- package/dist/commands/db-verify.mjs +311 -0
- package/dist/commands/db-verify.mjs.map +1 -0
- package/dist/commands/migration-apply.d.mts +36 -0
- package/dist/commands/migration-apply.d.mts.map +1 -0
- package/dist/commands/migration-apply.mjs +241 -0
- package/dist/commands/migration-apply.mjs.map +1 -0
- package/dist/commands/migration-plan.d.mts +47 -0
- package/dist/commands/migration-plan.d.mts.map +1 -0
- package/dist/commands/migration-plan.mjs +288 -0
- package/dist/commands/migration-plan.mjs.map +1 -0
- package/dist/commands/migration-ref.d.mts +43 -0
- package/dist/commands/migration-ref.d.mts.map +1 -0
- package/dist/commands/migration-ref.mjs +194 -0
- package/dist/commands/migration-ref.mjs.map +1 -0
- package/dist/commands/migration-show.d.mts +28 -0
- package/dist/commands/migration-show.d.mts.map +1 -0
- package/dist/commands/migration-show.mjs +139 -0
- package/dist/commands/migration-show.mjs.map +1 -0
- package/dist/commands/migration-status.d.mts +85 -0
- package/dist/commands/migration-status.d.mts.map +1 -0
- package/dist/commands/migration-status.mjs +8 -0
- package/dist/commands/migration-verify.d.mts +16 -0
- package/dist/commands/migration-verify.d.mts.map +1 -0
- package/dist/commands/migration-verify.mjs +87 -0
- package/dist/commands/migration-verify.mjs.map +1 -0
- package/dist/config-loader-d_KF19Tw.mjs +43 -0
- package/dist/config-loader-d_KF19Tw.mjs.map +1 -0
- package/dist/{config-loader.d.ts → config-loader.d.mts} +8 -3
- package/dist/config-loader.d.mts.map +1 -0
- package/dist/config-loader.mjs +3 -0
- package/dist/contract-emit-CVv7dbQ9.mjs +187 -0
- package/dist/contract-emit-CVv7dbQ9.mjs.map +1 -0
- package/dist/contract-infer-Bvw8u8Eu.mjs +83 -0
- package/dist/contract-infer-Bvw8u8Eu.mjs.map +1 -0
- package/dist/exports/config-types.d.mts +2 -0
- package/dist/exports/config-types.mjs +3 -0
- package/dist/exports/control-api.d.mts +626 -0
- package/dist/exports/control-api.d.mts.map +1 -0
- package/dist/exports/control-api.mjs +107 -0
- package/dist/exports/control-api.mjs.map +1 -0
- package/dist/{load-ts-contract.d.ts → exports/index.d.mts} +10 -5
- package/dist/exports/index.d.mts.map +1 -0
- package/dist/exports/index.mjs +134 -0
- package/dist/exports/index.mjs.map +1 -0
- package/dist/extract-sql-ddl-Jf5blEO0.mjs +26 -0
- package/dist/extract-sql-ddl-Jf5blEO0.mjs.map +1 -0
- package/dist/framework-components-M2j-qPfr.mjs +59 -0
- package/dist/framework-components-M2j-qPfr.mjs.map +1 -0
- package/dist/inspect-live-schema-BQe5i4YE.mjs +90 -0
- package/dist/inspect-live-schema-BQe5i4YE.mjs.map +1 -0
- package/dist/migration-command-scaffold-SLrjcKXS.mjs +104 -0
- package/dist/migration-command-scaffold-SLrjcKXS.mjs.map +1 -0
- package/dist/migration-status-B7OVZ-Ka.mjs +1576 -0
- package/dist/migration-status-B7OVZ-Ka.mjs.map +1 -0
- package/dist/migrations-Db_ea9eE.mjs +173 -0
- package/dist/migrations-Db_ea9eE.mjs.map +1 -0
- package/dist/progress-adapter-DRNe2idZ.mjs +43 -0
- package/dist/progress-adapter-DRNe2idZ.mjs.map +1 -0
- package/dist/terminal-ui-DAcMBRKf.mjs +980 -0
- package/dist/terminal-ui-DAcMBRKf.mjs.map +1 -0
- package/dist/verify-DXKxBFvU.mjs +385 -0
- package/dist/verify-DXKxBFvU.mjs.map +1 -0
- package/package.json +85 -40
- package/src/cli.ts +109 -58
- package/src/commands/contract-emit.ts +236 -143
- package/src/commands/contract-infer-paths.ts +32 -0
- package/src/commands/contract-infer.ts +131 -0
- package/src/commands/db-init.ts +211 -425
- package/src/commands/db-schema.ts +77 -0
- package/src/commands/db-sign.ts +207 -228
- package/src/commands/db-update.ts +236 -0
- package/src/commands/db-verify.ts +484 -186
- package/src/commands/inspect-live-schema.ts +171 -0
- package/src/commands/migration-apply.ts +416 -0
- package/src/commands/migration-plan.ts +451 -0
- package/src/commands/migration-ref.ts +305 -0
- package/src/commands/migration-show.ts +246 -0
- package/src/commands/migration-status.ts +838 -0
- package/src/commands/migration-verify.ts +134 -0
- package/src/config-loader.ts +13 -3
- package/src/control-api/client.ts +614 -0
- package/src/control-api/contract-enrichment.ts +135 -0
- package/src/control-api/errors.ts +9 -0
- package/src/control-api/operations/contract-emit.ts +173 -0
- package/src/control-api/operations/db-init.ts +286 -0
- 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-apply.ts +194 -0
- package/src/control-api/operations/migration-helpers.ts +49 -0
- package/src/control-api/types.ts +683 -0
- package/src/exports/config-types.ts +4 -3
- package/src/exports/control-api.ts +56 -0
- package/src/load-ts-contract.ts +16 -11
- package/src/utils/cli-errors.ts +5 -2
- package/src/utils/command-helpers.ts +293 -3
- package/src/utils/formatters/emit.ts +67 -0
- package/src/utils/formatters/errors.ts +82 -0
- package/src/utils/formatters/graph-migration-mapper.ts +220 -0
- package/src/utils/formatters/graph-render.ts +1317 -0
- package/src/utils/formatters/graph-types.ts +114 -0
- package/src/utils/formatters/help.ts +380 -0
- package/src/utils/formatters/helpers.ts +28 -0
- package/src/utils/formatters/migrations.ts +346 -0
- package/src/utils/formatters/styled.ts +212 -0
- package/src/utils/formatters/verify.ts +620 -0
- package/src/utils/global-flags.ts +41 -23
- package/src/utils/migration-command-scaffold.ts +187 -0
- package/src/utils/migration-types.ts +12 -0
- package/src/utils/progress-adapter.ts +75 -0
- package/src/utils/result-handler.ts +12 -13
- package/src/utils/shutdown.ts +92 -0
- package/src/utils/suggest-command.ts +31 -0
- package/src/utils/terminal-ui.ts +276 -0
- package/dist/chunk-BZMBKEEQ.js +0 -997
- package/dist/chunk-BZMBKEEQ.js.map +0 -1
- package/dist/chunk-CVNWLFXO.js +0 -91
- package/dist/chunk-CVNWLFXO.js.map +0 -1
- package/dist/chunk-HWYQOCAJ.js +0 -47
- package/dist/chunk-HWYQOCAJ.js.map +0 -1
- package/dist/chunk-QUPBU4KV.js +0 -131
- package/dist/chunk-QUPBU4KV.js.map +0 -1
- package/dist/cli.d.ts +0 -2
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/commands/contract-emit.d.ts +0 -3
- package/dist/commands/contract-emit.d.ts.map +0 -1
- package/dist/commands/contract-emit.js +0 -9
- package/dist/commands/contract-emit.js.map +0 -1
- package/dist/commands/db-init.d.ts +0 -3
- package/dist/commands/db-init.d.ts.map +0 -1
- package/dist/commands/db-init.js +0 -337
- package/dist/commands/db-init.js.map +0 -1
- package/dist/commands/db-introspect.d.ts +0 -3
- package/dist/commands/db-introspect.d.ts.map +0 -1
- package/dist/commands/db-introspect.js +0 -186
- package/dist/commands/db-introspect.js.map +0 -1
- package/dist/commands/db-schema-verify.d.ts +0 -3
- package/dist/commands/db-schema-verify.d.ts.map +0 -1
- package/dist/commands/db-schema-verify.js +0 -160
- package/dist/commands/db-schema-verify.js.map +0 -1
- package/dist/commands/db-sign.d.ts +0 -3
- package/dist/commands/db-sign.d.ts.map +0 -1
- package/dist/commands/db-sign.js +0 -195
- package/dist/commands/db-sign.js.map +0 -1
- package/dist/commands/db-verify.d.ts +0 -3
- package/dist/commands/db-verify.d.ts.map +0 -1
- package/dist/commands/db-verify.js +0 -169
- package/dist/commands/db-verify.js.map +0 -1
- package/dist/config-loader.d.ts.map +0 -1
- package/dist/config-loader.js +0 -7
- package/dist/config-loader.js.map +0 -1
- package/dist/exports/config-types.d.ts +0 -3
- package/dist/exports/config-types.d.ts.map +0 -1
- package/dist/exports/config-types.js +0 -6
- package/dist/exports/config-types.js.map +0 -1
- package/dist/exports/index.d.ts +0 -4
- package/dist/exports/index.d.ts.map +0 -1
- package/dist/exports/index.js +0 -175
- package/dist/exports/index.js.map +0 -1
- package/dist/load-ts-contract.d.ts.map +0 -1
- package/dist/utils/action.d.ts +0 -16
- package/dist/utils/action.d.ts.map +0 -1
- package/dist/utils/cli-errors.d.ts +0 -7
- package/dist/utils/cli-errors.d.ts.map +0 -1
- package/dist/utils/command-helpers.d.ts +0 -12
- package/dist/utils/command-helpers.d.ts.map +0 -1
- package/dist/utils/framework-components.d.ts +0 -70
- package/dist/utils/framework-components.d.ts.map +0 -1
- package/dist/utils/global-flags.d.ts +0 -25
- package/dist/utils/global-flags.d.ts.map +0 -1
- package/dist/utils/output.d.ts +0 -142
- package/dist/utils/output.d.ts.map +0 -1
- package/dist/utils/result-handler.d.ts +0 -15
- package/dist/utils/result-handler.d.ts.map +0 -1
- package/dist/utils/spinner.d.ts +0 -29
- package/dist/utils/spinner.d.ts.map +0 -1
- package/src/commands/db-introspect.ts +0 -256
- package/src/commands/db-schema-verify.ts +0 -232
- package/src/utils/action.ts +0 -43
- package/src/utils/output.ts +0 -1471
- package/src/utils/spinner.ts +0 -67
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
|
|
3
|
+
//#region src/commands/migration-verify.d.ts
|
|
4
|
+
interface MigrationVerifyResult {
|
|
5
|
+
readonly ok: boolean;
|
|
6
|
+
readonly status: 'verified' | 'attested';
|
|
7
|
+
readonly dir: string;
|
|
8
|
+
readonly migrationId?: string;
|
|
9
|
+
readonly storedMigrationId?: string;
|
|
10
|
+
readonly computedMigrationId?: string;
|
|
11
|
+
readonly summary: string;
|
|
12
|
+
}
|
|
13
|
+
declare function createMigrationVerifyCommand(): Command;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { MigrationVerifyResult, createMigrationVerifyCommand };
|
|
16
|
+
//# sourceMappingURL=migration-verify.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration-verify.d.mts","names":[],"sources":["../../src/commands/migration-verify.ts"],"sourcesContent":[],"mappings":";;;UAsBiB,qBAAA;;EAAA,SAAA,MAAA,EAAA,UAAqB,GAAA,UAAA;EAiFtB,SAAA,GAAA,EAAA,MAAA;;;;;;iBAAA,4BAAA,CAAA,GAAgC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { _ as errorUnexpected, m as errorRuntime } from "../cli-errors-ByGuoqNj.mjs";
|
|
2
|
+
import { f as setCommandDescriptions, g as parseGlobalFlags, i as addGlobalOptions, p as setCommandExamples, r as handleResult, t as TerminalUI, y as formatStyledHeader } from "../terminal-ui-DAcMBRKf.mjs";
|
|
3
|
+
import { o as formatMigrationVerifyCommandOutput } from "../migrations-Db_ea9eE.mjs";
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import { notOk, ok } from "@prisma-next/utils/result";
|
|
6
|
+
import { ifDefined } from "@prisma-next/utils/defined";
|
|
7
|
+
import { MigrationToolsError } from "@prisma-next/migration-tools/types";
|
|
8
|
+
import { attestMigration, verifyMigration } from "@prisma-next/migration-tools/attestation";
|
|
9
|
+
|
|
10
|
+
//#region src/commands/migration-verify.ts
|
|
11
|
+
async function executeMigrationVerifyCommand(options, flags, ui) {
|
|
12
|
+
const dir = options.dir;
|
|
13
|
+
if (!flags.json && !flags.quiet) {
|
|
14
|
+
const header = formatStyledHeader({
|
|
15
|
+
command: "migration verify",
|
|
16
|
+
description: "Verify migration package integrity",
|
|
17
|
+
details: [{
|
|
18
|
+
label: "dir",
|
|
19
|
+
value: dir
|
|
20
|
+
}],
|
|
21
|
+
flags
|
|
22
|
+
});
|
|
23
|
+
ui.stderr(header);
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
const result = await verifyMigration(dir);
|
|
27
|
+
if (result.ok) return ok({
|
|
28
|
+
ok: true,
|
|
29
|
+
status: "verified",
|
|
30
|
+
dir,
|
|
31
|
+
...ifDefined("migrationId", result.storedMigrationId),
|
|
32
|
+
...ifDefined("storedMigrationId", result.storedMigrationId),
|
|
33
|
+
...ifDefined("computedMigrationId", result.computedMigrationId),
|
|
34
|
+
summary: "Migration package verified — migrationId matches"
|
|
35
|
+
});
|
|
36
|
+
if (result.reason === "draft") {
|
|
37
|
+
const migrationId = await attestMigration(dir);
|
|
38
|
+
return ok({
|
|
39
|
+
ok: true,
|
|
40
|
+
status: "attested",
|
|
41
|
+
dir,
|
|
42
|
+
migrationId,
|
|
43
|
+
summary: `Draft migration attested with migrationId: ${migrationId}`
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
return notOk(errorRuntime("migrationId mismatch — migration has been modified", {
|
|
47
|
+
why: `stored=${result.storedMigrationId}, computed=${result.computedMigrationId}`,
|
|
48
|
+
fix: "If the change was intentional, set \"migrationId\" to null in migration.json and rerun `migration verify` to re-attest. Otherwise, restore the original migration.",
|
|
49
|
+
meta: {
|
|
50
|
+
storedMigrationId: result.storedMigrationId,
|
|
51
|
+
computedMigrationId: result.computedMigrationId
|
|
52
|
+
}
|
|
53
|
+
}));
|
|
54
|
+
} catch (error) {
|
|
55
|
+
if (MigrationToolsError.is(error)) return notOk(errorRuntime(error.message, {
|
|
56
|
+
why: error.why,
|
|
57
|
+
fix: error.fix,
|
|
58
|
+
meta: {
|
|
59
|
+
code: error.code,
|
|
60
|
+
...error.details ?? {}
|
|
61
|
+
}
|
|
62
|
+
}));
|
|
63
|
+
return notOk(errorUnexpected(error instanceof Error ? error.message : String(error), { why: `Failed to verify migration: ${error instanceof Error ? error.message : String(error)}` }));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function createMigrationVerifyCommand() {
|
|
67
|
+
const command = new Command("verify");
|
|
68
|
+
setCommandDescriptions(command, "Verify a migration package migrationId", "Recomputes the content-addressed migrationId for a migration package and compares\nit against the stored value. Draft migrations (migrationId: null) are automatically\nattested.");
|
|
69
|
+
setCommandExamples(command, ["prisma-next migration verify --dir migrations/20250101-add-users"]);
|
|
70
|
+
addGlobalOptions(command).requiredOption("--dir <path>", "Path to the migration package directory").action(async (options) => {
|
|
71
|
+
const flags = parseGlobalFlags(options);
|
|
72
|
+
const ui = new TerminalUI({
|
|
73
|
+
color: flags.color,
|
|
74
|
+
interactive: flags.interactive
|
|
75
|
+
});
|
|
76
|
+
const exitCode = handleResult(await executeMigrationVerifyCommand(options, flags, ui), flags, ui, (verifyResult) => {
|
|
77
|
+
if (flags.json) ui.output(JSON.stringify(verifyResult, null, 2));
|
|
78
|
+
else if (!flags.quiet) ui.log(formatMigrationVerifyCommandOutput(verifyResult, flags));
|
|
79
|
+
});
|
|
80
|
+
process.exit(exitCode);
|
|
81
|
+
});
|
|
82
|
+
return command;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
//#endregion
|
|
86
|
+
export { createMigrationVerifyCommand };
|
|
87
|
+
//# sourceMappingURL=migration-verify.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration-verify.mjs","names":[],"sources":["../../src/commands/migration-verify.ts"],"sourcesContent":["import { attestMigration, verifyMigration } from '@prisma-next/migration-tools/attestation';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/types';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { type CliStructuredError, errorRuntime, errorUnexpected } from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n setCommandDescriptions,\n setCommandExamples,\n} from '../utils/command-helpers';\nimport { formatMigrationVerifyCommandOutput } from '../utils/formatters/migrations';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlags } from '../utils/global-flags';\nimport { handleResult } from '../utils/result-handler';\nimport { TerminalUI } from '../utils/terminal-ui';\n\ninterface MigrationVerifyOptions extends CommonCommandOptions {\n readonly dir: string;\n}\n\nexport interface MigrationVerifyResult {\n readonly ok: boolean;\n readonly status: 'verified' | 'attested';\n readonly dir: string;\n readonly migrationId?: string;\n readonly storedMigrationId?: string;\n readonly computedMigrationId?: string;\n readonly summary: string;\n}\n\nasync function executeMigrationVerifyCommand(\n options: MigrationVerifyOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<MigrationVerifyResult, CliStructuredError>> {\n const dir = options.dir;\n\n if (!flags.json && !flags.quiet) {\n const header = formatStyledHeader({\n command: 'migration verify',\n description: 'Verify migration package integrity',\n details: [{ label: 'dir', value: dir }],\n flags,\n });\n ui.stderr(header);\n }\n\n try {\n const result = await verifyMigration(dir);\n\n if (result.ok) {\n return ok({\n ok: true,\n status: 'verified',\n dir,\n ...ifDefined('migrationId', result.storedMigrationId),\n ...ifDefined('storedMigrationId', result.storedMigrationId),\n ...ifDefined('computedMigrationId', result.computedMigrationId),\n summary: 'Migration package verified — migrationId matches',\n });\n }\n\n if (result.reason === 'draft') {\n const migrationId = await attestMigration(dir);\n return ok({\n ok: true,\n status: 'attested',\n dir,\n migrationId,\n summary: `Draft migration attested with migrationId: ${migrationId}`,\n });\n }\n\n return notOk(\n errorRuntime('migrationId mismatch — migration has been modified', {\n why: `stored=${result.storedMigrationId}, computed=${result.computedMigrationId}`,\n fix: 'If the change was intentional, set \"migrationId\" to null in migration.json and rerun `migration verify` to re-attest. Otherwise, restore the original migration.',\n meta: {\n storedMigrationId: result.storedMigrationId,\n computedMigrationId: result.computedMigrationId,\n },\n }),\n );\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n return notOk(\n errorRuntime(error.message, {\n why: error.why,\n fix: error.fix,\n meta: { code: error.code, ...(error.details ?? {}) },\n }),\n );\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to verify migration: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n}\n\nexport function createMigrationVerifyCommand(): Command {\n const command = new Command('verify');\n setCommandDescriptions(\n command,\n 'Verify a migration package migrationId',\n 'Recomputes the content-addressed migrationId for a migration package and compares\\n' +\n 'it against the stored value. Draft migrations (migrationId: null) are automatically\\n' +\n 'attested.',\n );\n setCommandExamples(command, ['prisma-next migration verify --dir migrations/20250101-add-users']);\n addGlobalOptions(command)\n .requiredOption('--dir <path>', 'Path to the migration package directory')\n .action(async (options: MigrationVerifyOptions) => {\n const flags = parseGlobalFlags(options);\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\n\n const result = await executeMigrationVerifyCommand(options, flags, ui);\n\n const exitCode = handleResult(result, flags, ui, (verifyResult) => {\n if (flags.json) {\n ui.output(JSON.stringify(verifyResult, null, 2));\n } else if (!flags.quiet) {\n ui.log(formatMigrationVerifyCommandOutput(verifyResult, flags));\n }\n });\n\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":";;;;;;;;;;AAgCA,eAAe,8BACb,SACA,OACA,IAC4D;CAC5D,MAAM,MAAM,QAAQ;AAEpB,KAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,OAAO;EAC/B,MAAM,SAAS,mBAAmB;GAChC,SAAS;GACT,aAAa;GACb,SAAS,CAAC;IAAE,OAAO;IAAO,OAAO;IAAK,CAAC;GACvC;GACD,CAAC;AACF,KAAG,OAAO,OAAO;;AAGnB,KAAI;EACF,MAAM,SAAS,MAAM,gBAAgB,IAAI;AAEzC,MAAI,OAAO,GACT,QAAO,GAAG;GACR,IAAI;GACJ,QAAQ;GACR;GACA,GAAG,UAAU,eAAe,OAAO,kBAAkB;GACrD,GAAG,UAAU,qBAAqB,OAAO,kBAAkB;GAC3D,GAAG,UAAU,uBAAuB,OAAO,oBAAoB;GAC/D,SAAS;GACV,CAAC;AAGJ,MAAI,OAAO,WAAW,SAAS;GAC7B,MAAM,cAAc,MAAM,gBAAgB,IAAI;AAC9C,UAAO,GAAG;IACR,IAAI;IACJ,QAAQ;IACR;IACA;IACA,SAAS,8CAA8C;IACxD,CAAC;;AAGJ,SAAO,MACL,aAAa,sDAAsD;GACjE,KAAK,UAAU,OAAO,kBAAkB,aAAa,OAAO;GAC5D,KAAK;GACL,MAAM;IACJ,mBAAmB,OAAO;IAC1B,qBAAqB,OAAO;IAC7B;GACF,CAAC,CACH;UACM,OAAO;AACd,MAAI,oBAAoB,GAAG,MAAM,CAC/B,QAAO,MACL,aAAa,MAAM,SAAS;GAC1B,KAAK,MAAM;GACX,KAAK,MAAM;GACX,MAAM;IAAE,MAAM,MAAM;IAAM,GAAI,MAAM,WAAW,EAAE;IAAG;GACrD,CAAC,CACH;AAEH,SAAO,MACL,gBAAgB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EAAE,EACtE,KAAK,+BAA+B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,IAC3F,CAAC,CACH;;;AAIL,SAAgB,+BAAwC;CACtD,MAAM,UAAU,IAAI,QAAQ,SAAS;AACrC,wBACE,SACA,0CACA,oLAGD;AACD,oBAAmB,SAAS,CAAC,mEAAmE,CAAC;AACjG,kBAAiB,QAAQ,CACtB,eAAe,gBAAgB,0CAA0C,CACzE,OAAO,OAAO,YAAoC;EACjD,MAAM,QAAQ,iBAAiB,QAAQ;EACvC,MAAM,KAAK,IAAI,WAAW;GAAE,OAAO,MAAM;GAAO,aAAa,MAAM;GAAa,CAAC;EAIjF,MAAM,WAAW,aAFF,MAAM,8BAA8B,SAAS,OAAO,GAAG,EAEhC,OAAO,KAAK,iBAAiB;AACjE,OAAI,MAAM,KACR,IAAG,OAAO,KAAK,UAAU,cAAc,MAAM,EAAE,CAAC;YACvC,CAAC,MAAM,MAChB,IAAG,IAAI,mCAAmC,cAAc,MAAM,CAAC;IAEjE;AAEF,UAAQ,KAAK,SAAS;GACtB;AAEJ,QAAO"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { errorConfigFileNotFound, errorConfigValidation, errorUnexpected } from "@prisma-next/core-control-plane/errors";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { ConfigValidationError, validateConfig } from "@prisma-next/config/config-validation";
|
|
4
|
+
import { loadConfig } from "c12";
|
|
5
|
+
|
|
6
|
+
//#region src/config-loader.ts
|
|
7
|
+
/**
|
|
8
|
+
* Loads the Prisma Next config from a TypeScript file.
|
|
9
|
+
* Supports both default export and named export.
|
|
10
|
+
* Uses c12 to automatically handle TypeScript compilation and config file discovery.
|
|
11
|
+
*
|
|
12
|
+
* @param configPath - Optional path to config file. Defaults to `./prisma-next.config.ts` in current directory.
|
|
13
|
+
* @returns The loaded config object.
|
|
14
|
+
* @throws Error if config file doesn't exist or is invalid.
|
|
15
|
+
*/
|
|
16
|
+
async function loadConfig$1(configPath) {
|
|
17
|
+
try {
|
|
18
|
+
const cwd = process.cwd();
|
|
19
|
+
const resolvedConfigPath = configPath ? resolve(cwd, configPath) : void 0;
|
|
20
|
+
const configCwd = resolvedConfigPath ? dirname(resolvedConfigPath) : cwd;
|
|
21
|
+
const result = await loadConfig({
|
|
22
|
+
name: "prisma-next",
|
|
23
|
+
...resolvedConfigPath ? { configFile: resolvedConfigPath } : {},
|
|
24
|
+
cwd: configCwd
|
|
25
|
+
});
|
|
26
|
+
if (resolvedConfigPath && result.configFile !== resolvedConfigPath) throw errorConfigFileNotFound(resolvedConfigPath);
|
|
27
|
+
if (!result.config || Object.keys(result.config).length === 0) throw errorConfigFileNotFound(result.configFile || resolvedConfigPath || configPath);
|
|
28
|
+
validateConfig(result.config);
|
|
29
|
+
return result.config;
|
|
30
|
+
} catch (error) {
|
|
31
|
+
if (error instanceof ConfigValidationError) throw errorConfigValidation(error.field, { why: error.why });
|
|
32
|
+
if (error instanceof Error && "code" in error && typeof error.code === "string") throw error;
|
|
33
|
+
if (error instanceof Error) {
|
|
34
|
+
if (error.message.includes("not found") || error.message.includes("Cannot find") || error.message.includes("ENOENT")) throw errorConfigFileNotFound(configPath ? resolve(process.cwd(), configPath) : void 0, { why: error.message });
|
|
35
|
+
throw errorUnexpected(error.message, { why: `Failed to load config: ${error.message}` });
|
|
36
|
+
}
|
|
37
|
+
throw errorUnexpected(String(error));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
//#endregion
|
|
42
|
+
export { loadConfig$1 as t };
|
|
43
|
+
//# sourceMappingURL=config-loader-d_KF19Tw.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-loader-d_KF19Tw.mjs","names":["loadConfig","loadConfigC12"],"sources":["../src/config-loader.ts"],"sourcesContent":["import { dirname, resolve } from 'node:path';\nimport type { PrismaNextConfig } from '@prisma-next/config/config-types';\nimport { ConfigValidationError, validateConfig } from '@prisma-next/config/config-validation';\nimport {\n errorConfigFileNotFound,\n errorConfigValidation,\n errorUnexpected,\n} from '@prisma-next/core-control-plane/errors';\nimport { loadConfig as loadConfigC12 } from 'c12';\n\n/**\n * Loads the Prisma Next config from a TypeScript file.\n * Supports both default export and named export.\n * Uses c12 to automatically handle TypeScript compilation and config file discovery.\n *\n * @param configPath - Optional path to config file. Defaults to `./prisma-next.config.ts` in current directory.\n * @returns The loaded config object.\n * @throws Error if config file doesn't exist or is invalid.\n */\nexport async function loadConfig(configPath?: string): Promise<PrismaNextConfig> {\n try {\n const cwd = process.cwd();\n // Resolve config path to absolute path and set cwd to config directory when path is provided\n const resolvedConfigPath = configPath ? resolve(cwd, configPath) : undefined;\n const configCwd = resolvedConfigPath ? dirname(resolvedConfigPath) : cwd;\n\n const result = await loadConfigC12<PrismaNextConfig>({\n name: 'prisma-next',\n ...(resolvedConfigPath ? { configFile: resolvedConfigPath } : {}),\n cwd: configCwd,\n });\n\n // When a specific config file was requested, verify it was actually loaded\n // (c12 falls back to searching by name if the specified file doesn't exist)\n if (resolvedConfigPath && result.configFile !== resolvedConfigPath) {\n throw errorConfigFileNotFound(resolvedConfigPath);\n }\n\n // Check if config is missing or empty (c12 may return empty object when file doesn't exist)\n if (!result.config || Object.keys(result.config).length === 0) {\n // Use c12's configFile if available, otherwise use explicit configPath, otherwise omit path\n const displayPath = result.configFile || resolvedConfigPath || configPath;\n throw errorConfigFileNotFound(displayPath);\n }\n\n // Validate config structure\n validateConfig(result.config);\n\n return result.config;\n } catch (error) {\n if (error instanceof ConfigValidationError) {\n throw errorConfigValidation(error.field, {\n why: error.why,\n });\n }\n\n // Re-throw structured errors as-is\n if (\n error instanceof Error &&\n 'code' in error &&\n typeof (error as { code: string }).code === 'string'\n ) {\n throw error;\n }\n\n if (error instanceof Error) {\n // Check for file not found errors\n if (\n error.message.includes('not found') ||\n error.message.includes('Cannot find') ||\n error.message.includes('ENOENT')\n ) {\n // Use resolved path if available, otherwise use original configPath\n const displayPath = configPath ? resolve(process.cwd(), configPath) : undefined;\n throw errorConfigFileNotFound(displayPath, {\n why: error.message,\n });\n }\n // For other errors, wrap in unexpected error\n throw errorUnexpected(error.message, {\n why: `Failed to load config: ${error.message}`,\n });\n }\n throw errorUnexpected(String(error));\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAmBA,eAAsBA,aAAW,YAAgD;AAC/E,KAAI;EACF,MAAM,MAAM,QAAQ,KAAK;EAEzB,MAAM,qBAAqB,aAAa,QAAQ,KAAK,WAAW,GAAG;EACnE,MAAM,YAAY,qBAAqB,QAAQ,mBAAmB,GAAG;EAErE,MAAM,SAAS,MAAMC,WAAgC;GACnD,MAAM;GACN,GAAI,qBAAqB,EAAE,YAAY,oBAAoB,GAAG,EAAE;GAChE,KAAK;GACN,CAAC;AAIF,MAAI,sBAAsB,OAAO,eAAe,mBAC9C,OAAM,wBAAwB,mBAAmB;AAInD,MAAI,CAAC,OAAO,UAAU,OAAO,KAAK,OAAO,OAAO,CAAC,WAAW,EAG1D,OAAM,wBADc,OAAO,cAAc,sBAAsB,WACrB;AAI5C,iBAAe,OAAO,OAAO;AAE7B,SAAO,OAAO;UACP,OAAO;AACd,MAAI,iBAAiB,sBACnB,OAAM,sBAAsB,MAAM,OAAO,EACvC,KAAK,MAAM,KACZ,CAAC;AAIJ,MACE,iBAAiB,SACjB,UAAU,SACV,OAAQ,MAA2B,SAAS,SAE5C,OAAM;AAGR,MAAI,iBAAiB,OAAO;AAE1B,OACE,MAAM,QAAQ,SAAS,YAAY,IACnC,MAAM,QAAQ,SAAS,cAAc,IACrC,MAAM,QAAQ,SAAS,SAAS,CAIhC,OAAM,wBADc,aAAa,QAAQ,QAAQ,KAAK,EAAE,WAAW,GAAG,QAC3B,EACzC,KAAK,MAAM,SACZ,CAAC;AAGJ,SAAM,gBAAgB,MAAM,SAAS,EACnC,KAAK,0BAA0B,MAAM,WACtC,CAAC;;AAEJ,QAAM,gBAAgB,OAAO,MAAM,CAAC"}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { PrismaNextConfig } from "@prisma-next/config/config-types";
|
|
2
|
+
|
|
3
|
+
//#region src/config-loader.d.ts
|
|
4
|
+
|
|
2
5
|
/**
|
|
3
6
|
* Loads the Prisma Next config from a TypeScript file.
|
|
4
7
|
* Supports both default export and named export.
|
|
@@ -8,5 +11,7 @@ import type { PrismaNextConfig } from '@prisma-next/core-control-plane/config-ty
|
|
|
8
11
|
* @returns The loaded config object.
|
|
9
12
|
* @throws Error if config file doesn't exist or is invalid.
|
|
10
13
|
*/
|
|
11
|
-
|
|
12
|
-
//#
|
|
14
|
+
declare function loadConfig(configPath?: string): Promise<PrismaNextConfig>;
|
|
15
|
+
//#endregion
|
|
16
|
+
export { loadConfig };
|
|
17
|
+
//# sourceMappingURL=config-loader.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-loader.d.mts","names":[],"sources":["../src/config-loader.ts"],"sourcesContent":[],"mappings":";;;;;;AAmBA;;;;;;;iBAAsB,UAAA,uBAAiC,QAAQ"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { t as loadConfig } from "./config-loader-d_KF19Tw.mjs";
|
|
2
|
+
import { _ as errorUnexpected$1, a as errorContractValidationFailed, m as errorRuntime, t as CliStructuredError } from "./cli-errors-ByGuoqNj.mjs";
|
|
3
|
+
import { t as createControlClient } from "./client-612RJJD_.mjs";
|
|
4
|
+
import { C as isVerbose, b as formatSuccessMessage, f as setCommandDescriptions, g as parseGlobalFlags, i as addGlobalOptions, p as setCommandExamples, r as handleResult, t as TerminalUI, y as formatStyledHeader } from "./terminal-ui-DAcMBRKf.mjs";
|
|
5
|
+
import { t as createProgressAdapter } from "./progress-adapter-DRNe2idZ.mjs";
|
|
6
|
+
import { Command } from "commander";
|
|
7
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { errorContractConfigMissing } from "@prisma-next/core-control-plane/errors";
|
|
9
|
+
import { notOk, ok } from "@prisma-next/utils/result";
|
|
10
|
+
import { dirname, isAbsolute, join, relative, resolve } from "pathe";
|
|
11
|
+
import { ifDefined } from "@prisma-next/utils/defined";
|
|
12
|
+
|
|
13
|
+
//#region src/utils/formatters/emit.ts
|
|
14
|
+
/**
|
|
15
|
+
* Formats human-readable output for contract emit.
|
|
16
|
+
*/
|
|
17
|
+
function formatEmitOutput(result, flags) {
|
|
18
|
+
if (flags.quiet) return "";
|
|
19
|
+
const lines = [];
|
|
20
|
+
const jsonPath = relative(process.cwd(), result.files.json);
|
|
21
|
+
const dtsPath = relative(process.cwd(), result.files.dts);
|
|
22
|
+
lines.push(`✔ Emitted contract.json → ${jsonPath}`);
|
|
23
|
+
lines.push(`✔ Emitted contract.d.ts → ${dtsPath}`);
|
|
24
|
+
lines.push(` storageHash: ${result.storageHash}`);
|
|
25
|
+
if (result.executionHash) lines.push(` executionHash: ${result.executionHash}`);
|
|
26
|
+
if (result.profileHash) lines.push(` profileHash: ${result.profileHash}`);
|
|
27
|
+
if (isVerbose(flags, 1)) lines.push(` Total time: ${result.timings.total}ms`);
|
|
28
|
+
return lines.join("\n");
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Formats JSON output for contract emit.
|
|
32
|
+
*/
|
|
33
|
+
function formatEmitJson(result) {
|
|
34
|
+
const output = {
|
|
35
|
+
ok: true,
|
|
36
|
+
storageHash: result.storageHash,
|
|
37
|
+
...ifDefined("executionHash", result.executionHash),
|
|
38
|
+
...result.profileHash ? { profileHash: result.profileHash } : {},
|
|
39
|
+
outDir: result.outDir,
|
|
40
|
+
files: result.files,
|
|
41
|
+
timings: result.timings
|
|
42
|
+
};
|
|
43
|
+
return JSON.stringify(output, null, 2);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
//#endregion
|
|
47
|
+
//#region src/commands/contract-emit.ts
|
|
48
|
+
function mapDiagnosticsToIssues(failure) {
|
|
49
|
+
return (failure.diagnostics?.diagnostics ?? []).map((diagnostic) => {
|
|
50
|
+
const location = diagnostic.sourceId && diagnostic.span ? ` (${diagnostic.sourceId}:${diagnostic.span.start.line}:${diagnostic.span.start.column})` : diagnostic.sourceId ? ` (${diagnostic.sourceId})` : "";
|
|
51
|
+
return {
|
|
52
|
+
kind: diagnostic.code,
|
|
53
|
+
message: `${diagnostic.message}${location}`
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Maps an EmitFailure to a CliStructuredError for consistent error handling.
|
|
59
|
+
*/
|
|
60
|
+
function mapEmitFailure(failure, context) {
|
|
61
|
+
if (failure.code === "CONTRACT_SOURCE_INVALID") {
|
|
62
|
+
const issues = mapDiagnosticsToIssues(failure);
|
|
63
|
+
return errorRuntime(failure.summary, {
|
|
64
|
+
why: failure.why ?? "Contract source provider failed",
|
|
65
|
+
fix: "Check your contract source provider in prisma-next.config.ts and ensure it returns Result<ContractIR, Diagnostics>",
|
|
66
|
+
...issues.length > 0 ? { meta: { issues } } : {}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
if (failure.code === "CONTRACT_VALIDATION_FAILED") return errorContractValidationFailed(failure.why ?? "Contract validation failed while emitting", context?.configPath ? { where: { path: context.configPath } } : void 0);
|
|
70
|
+
if (failure.code === "EMIT_FAILED") return errorRuntime(failure.summary, {
|
|
71
|
+
why: failure.why ?? "Failed to emit contract",
|
|
72
|
+
fix: "Check your contract configuration and ensure the source is valid"
|
|
73
|
+
});
|
|
74
|
+
const exhaustive = failure.code;
|
|
75
|
+
throw new Error(`Unhandled EmitFailure code: ${exhaustive}`);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Executes the contract emit command and returns a structured Result.
|
|
79
|
+
*/
|
|
80
|
+
async function executeContractEmitCommand(options, flags, ui, startTime) {
|
|
81
|
+
let config;
|
|
82
|
+
try {
|
|
83
|
+
config = await loadConfig(options.config);
|
|
84
|
+
} catch (error) {
|
|
85
|
+
if (error instanceof CliStructuredError) return notOk(error);
|
|
86
|
+
return notOk(errorUnexpected$1(error instanceof Error ? error.message : String(error), { why: "Failed to load config" }));
|
|
87
|
+
}
|
|
88
|
+
const configPath = options.config ? relative(process.cwd(), resolve(options.config)) : "prisma-next.config.ts";
|
|
89
|
+
if (!config.contract) return notOk(errorContractConfigMissing({ why: "Config.contract is required for emit. Define it in your config: contract: { source: ..., output: ... }" }));
|
|
90
|
+
const contractConfig = config.contract;
|
|
91
|
+
if (!contractConfig.output) return notOk(errorContractConfigMissing({ why: "Contract config must have output path. This should not happen if defineConfig() was used." }));
|
|
92
|
+
if (!contractConfig.output.endsWith(".json")) return notOk(errorContractConfigMissing({ why: "Contract config output path must end with .json (e.g., \"src/prisma/contract.json\")" }));
|
|
93
|
+
const configDir = options.config ? dirname(resolve(options.config)) : process.cwd();
|
|
94
|
+
const outputJsonPath = isAbsolute(contractConfig.output) ? contractConfig.output : join(configDir, contractConfig.output);
|
|
95
|
+
const outputDtsPath = `${outputJsonPath.slice(0, -5)}.d.ts`;
|
|
96
|
+
if (!flags.json && !flags.quiet) {
|
|
97
|
+
const contractPath = relative(process.cwd(), outputJsonPath);
|
|
98
|
+
const typesPath = relative(process.cwd(), outputDtsPath);
|
|
99
|
+
const header = formatStyledHeader({
|
|
100
|
+
command: "contract emit",
|
|
101
|
+
description: "Emit your contract artifacts",
|
|
102
|
+
url: "https://pris.ly/contract-emit",
|
|
103
|
+
details: [
|
|
104
|
+
{
|
|
105
|
+
label: "config",
|
|
106
|
+
value: configPath
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
label: "contract",
|
|
110
|
+
value: contractPath
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
label: "types",
|
|
114
|
+
value: typesPath
|
|
115
|
+
}
|
|
116
|
+
],
|
|
117
|
+
flags
|
|
118
|
+
});
|
|
119
|
+
ui.stderr(header);
|
|
120
|
+
}
|
|
121
|
+
const client = createControlClient({
|
|
122
|
+
family: config.family,
|
|
123
|
+
target: config.target,
|
|
124
|
+
adapter: config.adapter,
|
|
125
|
+
extensionPacks: config.extensionPacks ?? []
|
|
126
|
+
});
|
|
127
|
+
const onProgress = createProgressAdapter({
|
|
128
|
+
ui,
|
|
129
|
+
flags
|
|
130
|
+
});
|
|
131
|
+
try {
|
|
132
|
+
const result = await client.emit({
|
|
133
|
+
contractConfig: {
|
|
134
|
+
sourceProvider: contractConfig.source,
|
|
135
|
+
output: outputJsonPath
|
|
136
|
+
},
|
|
137
|
+
onProgress
|
|
138
|
+
});
|
|
139
|
+
if (!result.ok) return notOk(mapEmitFailure(result.failure, { configPath }));
|
|
140
|
+
mkdirSync(dirname(outputJsonPath), { recursive: true });
|
|
141
|
+
mkdirSync(dirname(outputDtsPath), { recursive: true });
|
|
142
|
+
writeFileSync(outputJsonPath, result.value.contractJson, "utf-8");
|
|
143
|
+
writeFileSync(outputDtsPath, result.value.contractDts, "utf-8");
|
|
144
|
+
return ok({
|
|
145
|
+
storageHash: result.value.storageHash,
|
|
146
|
+
...result.value.executionHash ? { executionHash: result.value.executionHash } : {},
|
|
147
|
+
profileHash: result.value.profileHash,
|
|
148
|
+
outDir: dirname(outputJsonPath),
|
|
149
|
+
files: {
|
|
150
|
+
json: outputJsonPath,
|
|
151
|
+
dts: outputDtsPath
|
|
152
|
+
},
|
|
153
|
+
timings: { total: Date.now() - startTime }
|
|
154
|
+
});
|
|
155
|
+
} catch (error) {
|
|
156
|
+
if (CliStructuredError.is(error)) return notOk(error);
|
|
157
|
+
return notOk(errorUnexpected$1("Unexpected error during contract emit", { why: error instanceof Error ? error.message : String(error) }));
|
|
158
|
+
} finally {
|
|
159
|
+
await client.close();
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function createContractEmitCommand() {
|
|
163
|
+
const command = new Command("emit");
|
|
164
|
+
setCommandDescriptions(command, "Emit your contract artifacts", "Reads your contract source (TypeScript or Prisma schema) and emits contract.json and\ncontract.d.ts. The contract.json contains the canonical contract structure, and\ncontract.d.ts provides TypeScript types for type-safe query building.");
|
|
165
|
+
setCommandExamples(command, ["prisma-next contract emit", "prisma-next contract emit --config ./custom-config.ts"]);
|
|
166
|
+
addGlobalOptions(command).option("--config <path>", "Path to prisma-next.config.ts").action(async (options) => {
|
|
167
|
+
const flags = parseGlobalFlags(options);
|
|
168
|
+
const ui = new TerminalUI({
|
|
169
|
+
color: flags.color,
|
|
170
|
+
interactive: flags.interactive
|
|
171
|
+
});
|
|
172
|
+
const exitCode = handleResult(await executeContractEmitCommand(options, flags, ui, Date.now()), flags, ui, (emitResult) => {
|
|
173
|
+
if (flags.json) ui.output(formatEmitJson(emitResult));
|
|
174
|
+
else {
|
|
175
|
+
const output = formatEmitOutput(emitResult, flags);
|
|
176
|
+
if (output) ui.log(output);
|
|
177
|
+
if (!flags.quiet) ui.success(formatSuccessMessage(flags));
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
process.exit(exitCode);
|
|
181
|
+
});
|
|
182
|
+
return command;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
//#endregion
|
|
186
|
+
export { createContractEmitCommand as t };
|
|
187
|
+
//# sourceMappingURL=contract-emit-CVv7dbQ9.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract-emit-CVv7dbQ9.mjs","names":["lines: string[]","exhaustive: never","config: Awaited<ReturnType<typeof loadConfig>>","errorUnexpected"],"sources":["../src/utils/formatters/emit.ts","../src/commands/contract-emit.ts"],"sourcesContent":["import { ifDefined } from '@prisma-next/utils/defined';\nimport { relative } from 'pathe';\n\nimport type { GlobalFlags } from '../global-flags';\nimport { isVerbose } from './helpers';\n\n// EmitContractResult type for CLI output formatting (includes file paths)\nexport interface EmitContractResult {\n readonly storageHash: string;\n readonly executionHash?: string;\n readonly profileHash: string;\n readonly outDir: string;\n readonly files: {\n readonly json: string;\n readonly dts: string;\n };\n readonly timings: {\n readonly total: number;\n };\n}\n\n/**\n * Formats human-readable output for contract emit.\n */\nexport function formatEmitOutput(result: EmitContractResult, flags: GlobalFlags): string {\n if (flags.quiet) {\n return '';\n }\n\n const lines: string[] = [];\n\n // Convert absolute paths to relative paths from cwd\n const jsonPath = relative(process.cwd(), result.files.json);\n const dtsPath = relative(process.cwd(), result.files.dts);\n\n lines.push(`✔ Emitted contract.json → ${jsonPath}`);\n lines.push(`✔ Emitted contract.d.ts → ${dtsPath}`);\n lines.push(` storageHash: ${result.storageHash}`);\n if (result.executionHash) {\n lines.push(` executionHash: ${result.executionHash}`);\n }\n if (result.profileHash) {\n lines.push(` profileHash: ${result.profileHash}`);\n }\n if (isVerbose(flags, 1)) {\n lines.push(` Total time: ${result.timings.total}ms`);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Formats JSON output for contract emit.\n */\nexport function formatEmitJson(result: EmitContractResult): string {\n const output = {\n ok: true,\n storageHash: result.storageHash,\n ...ifDefined('executionHash', result.executionHash),\n ...(result.profileHash ? { profileHash: result.profileHash } : {}),\n outDir: result.outDir,\n files: result.files,\n timings: result.timings,\n };\n\n return JSON.stringify(output, null, 2);\n}\n","import { mkdirSync, writeFileSync } from 'node:fs';\nimport { errorContractConfigMissing } from '@prisma-next/core-control-plane/errors';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { dirname, isAbsolute, join, relative, resolve } from 'pathe';\nimport { loadConfig } from '../config-loader';\nimport { createControlClient } from '../control-api/client';\nimport type { EmitFailure } from '../control-api/types';\nimport {\n CliStructuredError,\n errorContractValidationFailed,\n errorRuntime,\n errorUnexpected,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n setCommandDescriptions,\n setCommandExamples,\n} from '../utils/command-helpers';\nimport {\n type EmitContractResult,\n formatEmitJson,\n formatEmitOutput,\n} from '../utils/formatters/emit';\nimport { formatStyledHeader, formatSuccessMessage } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlags } from '../utils/global-flags';\nimport { createProgressAdapter } from '../utils/progress-adapter';\nimport { handleResult } from '../utils/result-handler';\nimport { TerminalUI } from '../utils/terminal-ui';\n\ninterface ContractEmitOptions extends CommonCommandOptions {\n readonly config?: string;\n}\n\nfunction mapDiagnosticsToIssues(\n failure: EmitFailure,\n): ReadonlyArray<{ kind: string; message: string }> {\n const diagnostics = failure.diagnostics?.diagnostics ?? [];\n return diagnostics.map((diagnostic) => {\n const location =\n diagnostic.sourceId && diagnostic.span\n ? ` (${diagnostic.sourceId}:${diagnostic.span.start.line}:${diagnostic.span.start.column})`\n : diagnostic.sourceId\n ? ` (${diagnostic.sourceId})`\n : '';\n return {\n kind: diagnostic.code,\n message: `${diagnostic.message}${location}`,\n };\n });\n}\n\n/**\n * Maps an EmitFailure to a CliStructuredError for consistent error handling.\n */\nfunction mapEmitFailure(\n failure: EmitFailure,\n context?: { readonly configPath?: string },\n): CliStructuredError {\n if (failure.code === 'CONTRACT_SOURCE_INVALID') {\n const issues = mapDiagnosticsToIssues(failure);\n return errorRuntime(failure.summary, {\n why: failure.why ?? 'Contract source provider failed',\n fix: 'Check your contract source provider in prisma-next.config.ts and ensure it returns Result<ContractIR, Diagnostics>',\n ...(issues.length > 0 ? { meta: { issues } } : {}),\n });\n }\n\n if (failure.code === 'CONTRACT_VALIDATION_FAILED') {\n return errorContractValidationFailed(\n failure.why ?? 'Contract validation failed while emitting',\n context?.configPath ? { where: { path: context.configPath } } : undefined,\n );\n }\n\n if (failure.code === 'EMIT_FAILED') {\n return errorRuntime(failure.summary, {\n why: failure.why ?? 'Failed to emit contract',\n fix: 'Check your contract configuration and ensure the source is valid',\n });\n }\n\n // Exhaustive check - TypeScript will error if a new code is added but not handled\n const exhaustive: never = failure.code;\n throw new Error(`Unhandled EmitFailure code: ${exhaustive}`);\n}\n\n/**\n * Executes the contract emit command and returns a structured Result.\n */\nasync function executeContractEmitCommand(\n options: ContractEmitOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n startTime: number,\n): Promise<Result<EmitContractResult, CliStructuredError>> {\n // Load config\n let config: Awaited<ReturnType<typeof loadConfig>>;\n try {\n config = await loadConfig(options.config);\n } catch (error) {\n // Convert thrown CliStructuredError to Result\n if (error instanceof CliStructuredError) {\n return notOk(error);\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: 'Failed to load config',\n }),\n );\n }\n\n const configPath = options.config\n ? relative(process.cwd(), resolve(options.config))\n : 'prisma-next.config.ts';\n\n // Resolve contract from config\n if (!config.contract) {\n return notOk(\n errorContractConfigMissing({\n why: 'Config.contract is required for emit. Define it in your config: contract: { source: ..., output: ... }',\n }),\n );\n }\n\n // Contract config is already normalized by defineConfig() with defaults applied\n const contractConfig = config.contract;\n\n // Resolve artifact paths from config (already normalized by defineConfig() with defaults)\n if (!contractConfig.output) {\n return notOk(\n errorContractConfigMissing({\n why: 'Contract config must have output path. This should not happen if defineConfig() was used.',\n }),\n );\n }\n if (!contractConfig.output.endsWith('.json')) {\n return notOk(\n errorContractConfigMissing({\n why: 'Contract config output path must end with .json (e.g., \"src/prisma/contract.json\")',\n }),\n );\n }\n const configDir = options.config ? dirname(resolve(options.config)) : process.cwd();\n const outputJsonPath = isAbsolute(contractConfig.output)\n ? contractConfig.output\n : join(configDir, contractConfig.output);\n // Colocate .d.ts with .json (contract.json → contract.d.ts)\n const outputDtsPath = `${outputJsonPath.slice(0, -5)}.d.ts`;\n\n // Output header to stderr (decoration)\n if (!flags.json && !flags.quiet) {\n const contractPath = relative(process.cwd(), outputJsonPath);\n const typesPath = relative(process.cwd(), outputDtsPath);\n const header = formatStyledHeader({\n command: 'contract emit',\n description: 'Emit your contract artifacts',\n url: 'https://pris.ly/contract-emit',\n details: [\n { label: 'config', value: configPath },\n { label: 'contract', value: contractPath },\n { label: 'types', value: typesPath },\n ],\n flags,\n });\n ui.stderr(header);\n }\n\n // Create control client (no driver needed for emit)\n const client = createControlClient({\n family: config.family,\n target: config.target,\n adapter: config.adapter,\n extensionPacks: config.extensionPacks ?? [],\n });\n\n // Create progress adapter\n const onProgress = createProgressAdapter({ ui, flags });\n\n try {\n // Call emit with progress callback\n const result = await client.emit({\n contractConfig: {\n sourceProvider: contractConfig.source,\n output: outputJsonPath,\n },\n onProgress,\n });\n\n // Handle failures by mapping to CLI structured error\n if (!result.ok) {\n return notOk(mapEmitFailure(result.failure, { configPath }));\n }\n\n // Create directories if needed\n mkdirSync(dirname(outputJsonPath), { recursive: true });\n mkdirSync(dirname(outputDtsPath), { recursive: true });\n\n // Write the results to files\n writeFileSync(outputJsonPath, result.value.contractJson, 'utf-8');\n writeFileSync(outputDtsPath, result.value.contractDts, 'utf-8');\n\n // Convert success result to CLI output format\n const emitResult: EmitContractResult = {\n storageHash: result.value.storageHash,\n ...(result.value.executionHash ? { executionHash: result.value.executionHash } : {}),\n profileHash: result.value.profileHash,\n outDir: dirname(outputJsonPath),\n files: {\n json: outputJsonPath,\n dts: outputDtsPath,\n },\n timings: { total: Date.now() - startTime },\n };\n\n return ok(emitResult);\n } catch (error) {\n // Use static type guard to work across module boundaries\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n\n // Wrap unexpected errors\n return notOk(\n errorUnexpected('Unexpected error during contract emit', {\n why: error instanceof Error ? error.message : String(error),\n }),\n );\n } finally {\n await client.close();\n }\n}\n\nexport function createContractEmitCommand(): Command {\n const command = new Command('emit');\n setCommandDescriptions(\n command,\n 'Emit your contract artifacts',\n 'Reads your contract source (TypeScript or Prisma schema) and emits contract.json and\\n' +\n 'contract.d.ts. The contract.json contains the canonical contract structure, and\\n' +\n 'contract.d.ts provides TypeScript types for type-safe query building.',\n );\n setCommandExamples(command, [\n 'prisma-next contract emit',\n 'prisma-next contract emit --config ./custom-config.ts',\n ]);\n addGlobalOptions(command)\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (options: ContractEmitOptions) => {\n const flags = parseGlobalFlags(options);\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\n const startTime = Date.now();\n\n const result = await executeContractEmitCommand(options, flags, ui, startTime);\n\n // Handle result - formats output and returns exit code\n const exitCode = handleResult(result, flags, ui, (emitResult) => {\n if (flags.json) {\n ui.output(formatEmitJson(emitResult));\n } else {\n const output = formatEmitOutput(emitResult, flags);\n if (output) {\n ui.log(output);\n }\n if (!flags.quiet) {\n ui.success(formatSuccessMessage(flags));\n }\n }\n });\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { f as setCommandDescriptions, g as parseGlobalFlags, i as addGlobalOptions, p as setCommandExamples, r as handleResult, t as TerminalUI } from "./terminal-ui-DAcMBRKf.mjs";
|
|
2
|
+
import { t as inspectLiveSchema } from "./inspect-live-schema-BQe5i4YE.mjs";
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { ok } from "@prisma-next/utils/result";
|
|
6
|
+
import { dirname, relative, resolve } from "pathe";
|
|
7
|
+
import { printPsl } from "@prisma-next/psl-printer";
|
|
8
|
+
import { createPostgresDefaultMapping, createPostgresTypeMap, extractEnumInfo, parseRawDefault } from "@prisma-next/psl-printer/postgres";
|
|
9
|
+
|
|
10
|
+
//#region src/commands/contract-infer-paths.ts
|
|
11
|
+
/**
|
|
12
|
+
* Resolves the output path for the inferred PSL contract.
|
|
13
|
+
*
|
|
14
|
+
* Priority:
|
|
15
|
+
* 1. --output <path> flag (resolved relative to cwd)
|
|
16
|
+
* 2. contract.prisma next to config.contract.output
|
|
17
|
+
* 3. Canonical default: contract.prisma in the config directory
|
|
18
|
+
*/
|
|
19
|
+
function resolveContractInferOutputPath(options, contractOutput) {
|
|
20
|
+
const configDir = options.config ? dirname(resolve(process.cwd(), options.config)) : process.cwd();
|
|
21
|
+
if (options.output) return resolve(process.cwd(), options.output);
|
|
22
|
+
if (contractOutput) return resolve(dirname(resolve(configDir, contractOutput)), "contract.prisma");
|
|
23
|
+
return resolve(configDir, "contract.prisma");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/commands/contract-infer.ts
|
|
28
|
+
async function executeContractInferCommand(options, ui, startTime) {
|
|
29
|
+
const flags = parseGlobalFlags(options);
|
|
30
|
+
const inspectResult = await inspectLiveSchema(options, flags, ui, startTime, {
|
|
31
|
+
commandName: "contract infer",
|
|
32
|
+
description: "Infer a PSL contract from the live database schema",
|
|
33
|
+
url: "https://pris.ly/contract-infer"
|
|
34
|
+
});
|
|
35
|
+
if (!inspectResult.ok) return inspectResult;
|
|
36
|
+
const { config, schema, target, meta } = inspectResult.value;
|
|
37
|
+
const outputPath = resolveContractInferOutputPath(options, config.contract?.output);
|
|
38
|
+
const enumInfo = extractEnumInfo(schema.annotations);
|
|
39
|
+
const pslContent = printPsl(schema, {
|
|
40
|
+
defaultMapping: createPostgresDefaultMapping(),
|
|
41
|
+
typeMap: createPostgresTypeMap(enumInfo.typeNames),
|
|
42
|
+
enumInfo,
|
|
43
|
+
parseRawDefault
|
|
44
|
+
});
|
|
45
|
+
if (existsSync(outputPath) && !flags.json && !flags.quiet) ui.stderr(`\u26A0 Overwriting existing file: ${relative(process.cwd(), outputPath)}`);
|
|
46
|
+
mkdirSync(dirname(outputPath), { recursive: true });
|
|
47
|
+
writeFileSync(outputPath, pslContent, "utf-8");
|
|
48
|
+
const pslPath = relative(process.cwd(), outputPath);
|
|
49
|
+
if (!flags.json && !flags.quiet) ui.stderr(`\u2714 Contract written to ${pslPath}`);
|
|
50
|
+
return ok({
|
|
51
|
+
ok: true,
|
|
52
|
+
summary: "Contract inferred successfully",
|
|
53
|
+
target,
|
|
54
|
+
psl: { path: pslPath },
|
|
55
|
+
meta,
|
|
56
|
+
timings: { total: Date.now() - startTime }
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
function createContractInferCommand() {
|
|
60
|
+
const command = new Command("infer");
|
|
61
|
+
setCommandDescriptions(command, "Infer a PSL contract from the live database schema", "Reads the live database schema and writes an inferred PSL contract to disk.\nThis command stops at `contract.prisma`; follow it with `contract emit` and\n`db sign` as separate steps.");
|
|
62
|
+
setCommandExamples(command, [
|
|
63
|
+
"prisma-next contract infer --db $DATABASE_URL",
|
|
64
|
+
"prisma-next contract infer --db $DATABASE_URL --output ./prisma/contract.prisma",
|
|
65
|
+
"prisma-next contract infer --db $DATABASE_URL --json"
|
|
66
|
+
]);
|
|
67
|
+
addGlobalOptions(command).option("--db <url>", "Database connection string").option("--config <path>", "Path to prisma-next.config.ts").option("--output <path>", "Write the inferred PSL contract to the specified path").action(async (options) => {
|
|
68
|
+
const flags = parseGlobalFlags(options);
|
|
69
|
+
const ui = new TerminalUI({
|
|
70
|
+
color: flags.color,
|
|
71
|
+
interactive: flags.interactive
|
|
72
|
+
});
|
|
73
|
+
const exitCode = handleResult(await executeContractInferCommand(options, ui, Date.now()), flags, ui, (value) => {
|
|
74
|
+
if (flags.json) ui.output(JSON.stringify(value, null, 2));
|
|
75
|
+
});
|
|
76
|
+
process.exit(exitCode);
|
|
77
|
+
});
|
|
78
|
+
return command;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
//#endregion
|
|
82
|
+
export { createContractInferCommand as t };
|
|
83
|
+
//# sourceMappingURL=contract-infer-Bvw8u8Eu.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract-infer-Bvw8u8Eu.mjs","names":[],"sources":["../src/commands/contract-infer-paths.ts","../src/commands/contract-infer.ts"],"sourcesContent":["import { dirname, resolve } from 'pathe';\n\ninterface ContractInferPathOptions {\n readonly output?: string;\n readonly config?: string;\n}\n\n/**\n * Resolves the output path for the inferred PSL contract.\n *\n * Priority:\n * 1. --output <path> flag (resolved relative to cwd)\n * 2. contract.prisma next to config.contract.output\n * 3. Canonical default: contract.prisma in the config directory\n */\nexport function resolveContractInferOutputPath(\n options: ContractInferPathOptions,\n contractOutput: string | undefined,\n): string {\n const configDir = options.config\n ? dirname(resolve(process.cwd(), options.config))\n : process.cwd();\n\n if (options.output) {\n return resolve(process.cwd(), options.output);\n }\n if (contractOutput) {\n const contractPath = resolve(configDir, contractOutput);\n return resolve(dirname(contractPath), 'contract.prisma');\n }\n return resolve(configDir, 'contract.prisma');\n}\n","import { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { printPsl } from '@prisma-next/psl-printer';\nimport {\n createPostgresDefaultMapping,\n createPostgresTypeMap,\n extractEnumInfo,\n parseRawDefault,\n} from '@prisma-next/psl-printer/postgres';\nimport { ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { dirname, relative } from 'pathe';\nimport type { CliStructuredError } from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n setCommandDescriptions,\n setCommandExamples,\n} from '../utils/command-helpers';\nimport { parseGlobalFlags } from '../utils/global-flags';\nimport { handleResult } from '../utils/result-handler';\nimport { TerminalUI } from '../utils/terminal-ui';\nimport { resolveContractInferOutputPath } from './contract-infer-paths';\nimport {\n type InspectLiveSchemaOptions,\n type InspectLiveSchemaResult,\n inspectLiveSchema,\n} from './inspect-live-schema';\n\ninterface ContractInferOptions extends InspectLiveSchemaOptions {\n readonly output?: string;\n}\n\ninterface ContractInferSuccessResult {\n readonly ok: true;\n readonly summary: string;\n readonly target: InspectLiveSchemaResult['target'];\n readonly psl: {\n readonly path: string;\n };\n readonly meta: InspectLiveSchemaResult['meta'];\n readonly timings: {\n readonly total: number;\n };\n}\n\nasync function executeContractInferCommand(\n options: ContractInferOptions,\n ui: TerminalUI,\n startTime: number,\n): Promise<Result<ContractInferSuccessResult, CliStructuredError>> {\n const flags = parseGlobalFlags(options);\n const inspectResult = await inspectLiveSchema(options, flags, ui, startTime, {\n commandName: 'contract infer',\n description: 'Infer a PSL contract from the live database schema',\n url: 'https://pris.ly/contract-infer',\n });\n\n if (!inspectResult.ok) {\n return inspectResult;\n }\n\n const { config, schema, target, meta } = inspectResult.value;\n const outputPath = resolveContractInferOutputPath(options, config.contract?.output);\n const enumInfo = extractEnumInfo(schema.annotations);\n const pslContent = printPsl(schema, {\n defaultMapping: createPostgresDefaultMapping(),\n typeMap: createPostgresTypeMap(enumInfo.typeNames),\n enumInfo,\n parseRawDefault,\n });\n\n if (existsSync(outputPath) && !flags.json && !flags.quiet) {\n ui.stderr(`\\u26A0 Overwriting existing file: ${relative(process.cwd(), outputPath)}`);\n }\n\n mkdirSync(dirname(outputPath), { recursive: true });\n writeFileSync(outputPath, pslContent, 'utf-8');\n\n const pslPath = relative(process.cwd(), outputPath);\n if (!flags.json && !flags.quiet) {\n ui.stderr(`\\u2714 Contract written to ${pslPath}`);\n }\n\n return ok({\n ok: true,\n summary: 'Contract inferred successfully',\n target,\n psl: {\n path: pslPath,\n },\n meta,\n timings: {\n total: Date.now() - startTime,\n },\n });\n}\n\nexport function createContractInferCommand(): Command {\n const command = new Command('infer');\n setCommandDescriptions(\n command,\n 'Infer a PSL contract from the live database schema',\n 'Reads the live database schema and writes an inferred PSL contract to disk.\\n' +\n 'This command stops at `contract.prisma`; follow it with `contract emit` and\\n' +\n '`db sign` as separate steps.',\n );\n setCommandExamples(command, [\n 'prisma-next contract infer --db $DATABASE_URL',\n 'prisma-next contract infer --db $DATABASE_URL --output ./prisma/contract.prisma',\n 'prisma-next contract infer --db $DATABASE_URL --json',\n ]);\n addGlobalOptions(command)\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--output <path>', 'Write the inferred PSL contract to the specified path')\n .action(async (options: ContractInferOptions) => {\n const flags = parseGlobalFlags(options);\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\n const startTime = Date.now();\n\n const result = await executeContractInferCommand(options, ui, startTime);\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value, null, 2));\n }\n });\n\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAeA,SAAgB,+BACd,SACA,gBACQ;CACR,MAAM,YAAY,QAAQ,SACtB,QAAQ,QAAQ,QAAQ,KAAK,EAAE,QAAQ,OAAO,CAAC,GAC/C,QAAQ,KAAK;AAEjB,KAAI,QAAQ,OACV,QAAO,QAAQ,QAAQ,KAAK,EAAE,QAAQ,OAAO;AAE/C,KAAI,eAEF,QAAO,QAAQ,QADM,QAAQ,WAAW,eAAe,CACnB,EAAE,kBAAkB;AAE1D,QAAO,QAAQ,WAAW,kBAAkB;;;;;ACc9C,eAAe,4BACb,SACA,IACA,WACiE;CACjE,MAAM,QAAQ,iBAAiB,QAAQ;CACvC,MAAM,gBAAgB,MAAM,kBAAkB,SAAS,OAAO,IAAI,WAAW;EAC3E,aAAa;EACb,aAAa;EACb,KAAK;EACN,CAAC;AAEF,KAAI,CAAC,cAAc,GACjB,QAAO;CAGT,MAAM,EAAE,QAAQ,QAAQ,QAAQ,SAAS,cAAc;CACvD,MAAM,aAAa,+BAA+B,SAAS,OAAO,UAAU,OAAO;CACnF,MAAM,WAAW,gBAAgB,OAAO,YAAY;CACpD,MAAM,aAAa,SAAS,QAAQ;EAClC,gBAAgB,8BAA8B;EAC9C,SAAS,sBAAsB,SAAS,UAAU;EAClD;EACA;EACD,CAAC;AAEF,KAAI,WAAW,WAAW,IAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,MAClD,IAAG,OAAO,qCAAqC,SAAS,QAAQ,KAAK,EAAE,WAAW,GAAG;AAGvF,WAAU,QAAQ,WAAW,EAAE,EAAE,WAAW,MAAM,CAAC;AACnD,eAAc,YAAY,YAAY,QAAQ;CAE9C,MAAM,UAAU,SAAS,QAAQ,KAAK,EAAE,WAAW;AACnD,KAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,MACxB,IAAG,OAAO,8BAA8B,UAAU;AAGpD,QAAO,GAAG;EACR,IAAI;EACJ,SAAS;EACT;EACA,KAAK,EACH,MAAM,SACP;EACD;EACA,SAAS,EACP,OAAO,KAAK,KAAK,GAAG,WACrB;EACF,CAAC;;AAGJ,SAAgB,6BAAsC;CACpD,MAAM,UAAU,IAAI,QAAQ,QAAQ;AACpC,wBACE,SACA,sDACA,yLAGD;AACD,oBAAmB,SAAS;EAC1B;EACA;EACA;EACD,CAAC;AACF,kBAAiB,QAAQ,CACtB,OAAO,cAAc,6BAA6B,CAClD,OAAO,mBAAmB,gCAAgC,CAC1D,OAAO,mBAAmB,wDAAwD,CAClF,OAAO,OAAO,YAAkC;EAC/C,MAAM,QAAQ,iBAAiB,QAAQ;EACvC,MAAM,KAAK,IAAI,WAAW;GAAE,OAAO,MAAM;GAAO,aAAa,MAAM;GAAa,CAAC;EAIjF,MAAM,WAAW,aADF,MAAM,4BAA4B,SAAS,IAFxC,KAAK,KAAK,CAE4C,EAClC,OAAO,KAAK,UAAU;AAC1D,OAAI,MAAM,KACR,IAAG,OAAO,KAAK,UAAU,OAAO,MAAM,EAAE,CAAC;IAE3C;AAEF,UAAQ,KAAK,SAAS;GACtB;AAEJ,QAAO"}
|