@prisma/orm-toolchain 8.0.0-rc.1-dev.35 → 8.0.0-rc.1-dev.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/bin__prisma-next.mjs +5 -5
  2. package/dist/bin__prisma-next.mjs.map +1 -1
  3. package/dist/{cli-errors-f5PRtVdm-C6xVKeQn.d.mts → cli-errors-WMw54cyq-DC2OYnd7.d.mts} +5 -3
  4. package/dist/{cli-errors-f5PRtVdm-C6xVKeQn.d.mts.map → cli-errors-WMw54cyq-DC2OYnd7.d.mts.map} +1 -1
  5. package/dist/cli.mjs +472 -20
  6. package/dist/cli.mjs.map +1 -1
  7. package/dist/cli__commands__contract-emit.mjs +1 -1
  8. package/dist/cli__commands__migrate.d.mts +2 -2
  9. package/dist/cli__commands__migration-graph.d.mts +1 -1
  10. package/dist/cli__commands__migration-list.d.mts +1 -1
  11. package/dist/cli__commands__migration-log.d.mts +1 -1
  12. package/dist/cli__commands__migration-plan.d.mts +1 -1
  13. package/dist/cli__commands__migration-status.d.mts +1 -1
  14. package/dist/cli__control-api.d.mts +3 -3
  15. package/dist/cli__control-api.mjs +2 -2
  16. package/dist/cli__control-api__testing.d.mts +1 -1
  17. package/dist/contract-emit-BHZYuA91-wlnU7OrE.mjs +2 -0
  18. package/dist/{contract-emit-BlvUNMHM-BEioUVR5.mjs → contract-emit-Cpj5Qz7z-BXt3HGPC.mjs} +3 -3
  19. package/dist/{contract-emit-BlvUNMHM-BEioUVR5.mjs.map → contract-emit-Cpj5Qz7z-BXt3HGPC.mjs.map} +1 -1
  20. package/dist/{contract-emit-CrYO0A8x-60BOqXFr.mjs → contract-emit-Dp1pe06_-Cdpvh5DH.mjs} +3 -3
  21. package/dist/{contract-emit-CrYO0A8x-60BOqXFr.mjs.map → contract-emit-Dp1pe06_-Cdpvh5DH.mjs.map} +1 -1
  22. package/dist/{format-D5x0jz7q-xalz6Fkn.mjs → format-DceifGAK-BJhTdkcO.mjs} +8 -5
  23. package/dist/format-DceifGAK-BJhTdkcO.mjs.map +1 -0
  24. package/dist/{init-CWI_P7Cj-BXq9iChN.mjs → init-DMiJjbrC-C7-PvDyK.mjs} +3 -3
  25. package/dist/{init-CWI_P7Cj-BXq9iChN.mjs.map → init-DMiJjbrC-C7-PvDyK.mjs.map} +1 -1
  26. package/dist/{migrate-show-DutwCc2F-BhGfH7D-.d.mts → migrate-show-DRfCIamX-BK6CN3RI.d.mts} +3 -3
  27. package/dist/{migrate-show-DutwCc2F-BhGfH7D-.d.mts.map → migrate-show-DRfCIamX-BK6CN3RI.d.mts.map} +1 -1
  28. package/dist/{migration-plan-4cnnP6yM-DXzRfi_A.d.mts → migration-plan-DPp3Orhx-6edvA2e2.d.mts} +3 -3
  29. package/dist/{migration-plan-4cnnP6yM-DXzRfi_A.d.mts.map → migration-plan-DPp3Orhx-6edvA2e2.d.mts.map} +1 -1
  30. package/dist/vite-plugin-contract-emit.mjs +1 -1
  31. package/package.json +12 -12
  32. package/dist/contract-emit-Csa6R0gt-DvxFlS0O.mjs +0 -2
  33. package/dist/format-D5x0jz7q-xalz6Fkn.mjs.map +0 -1
package/dist/cli.mjs CHANGED
@@ -1,11 +1,12 @@
1
1
  import { i as loadConfig } from "./exports-BZLNbtkY.mjs";
2
- import { F as requireLiveDatabase, I as runCommandAction, N as errorUnexpected, a as errorConfigValidation$1, b as errorNoMigrations, c as errorDatabaseConnectionRequired, d as errorFileNotFound, h as errorLegendHumanOnly, j as errorTargetMigrationNotSupported, s as errorContractValidationFailed, t as CliStructuredError$1$1, u as errorDriverRequired, v as errorMigrationPackageNotFound } from "./cli-errors-C6_pH59O-CzD4SYcJ.mjs";
2
+ import { F as requireLiveDatabase, I as runCommandAction, N as errorUnexpected, O as errorRuntime$1, a as errorConfigValidation$1, b as errorNoMigrations, c as errorDatabaseConnectionRequired, d as errorFileNotFound, h as errorLegendHumanOnly, j as errorTargetMigrationNotSupported, s as errorContractValidationFailed, t as CliStructuredError$1$1, u as errorDriverRequired, v as errorMigrationPackageNotFound } from "./cli-errors-C6_pH59O-CzD4SYcJ.mjs";
3
3
  import { r as getEmittedArtifactPaths } from "./exports-BCLg4CiV-05kuwcb0.mjs";
4
+ import { n as executeContractEmit } from "./contract-emit-Dp1pe06_-Cdpvh5DH.mjs";
4
5
  import { h as renderPreviewStatement, m as previewBlockHeader } from "./terminal-ui-Cqz4LVL7-B0mcVdLy.mjs";
5
6
  import { c as spaceMigrationDirectory } from "./verify-contract-spaces-DhJTb0zM-_oh6W6lp.mjs";
6
7
  import { S as targetSupportsMigrations, f as maskConnectionUrl, n as closeQuietly, v as sanitizeErrorMessage } from "./command-helpers-kD9CO1hd-BPhnkBin.mjs";
7
- import { t as createContractEmitCommand } from "./contract-emit-BlvUNMHM-BEioUVR5.mjs";
8
- import { t as createFormatCommand } from "./format-D5x0jz7q-xalz6Fkn.mjs";
8
+ import { t as createContractEmitCommand } from "./contract-emit-Cpj5Qz7z-BXt3HGPC.mjs";
9
+ import { n as executeFormat, t as createFormatCommand } from "./format-DceifGAK-BJhTdkcO.mjs";
9
10
  import { a as loadContractSpaceAggregateForCli, r as buildReadAggregate, s as refuseContractSpaceIntegrity, u as toDeclaredExtensionsFromRaw } from "./contract-space-aggregate-loader-BpdB-mHG-BiU0IUeb.mjs";
10
11
  import { t as createControlClient } from "./client-BqhVohc5-DFRVWFps.mjs";
11
12
  import { a as readContractIR, o as resolveRefAdvancementFields, t as advanceRefSafely } from "./ref-advancement-DaZBzm7m-WoqnFAyr.mjs";
@@ -22,25 +23,27 @@ import { n as looksLikePath, r as resolveAppTargetPath, t as findPackageByDirPat
22
23
  import { t as buildMigrationSpaceGraphEntries } from "./migration-graph-DmdVVJoZ-DDBKjUMz.mjs";
23
24
  import { n as renderMigrationGraphDot, r as renderMigrationGraphSections, t as buildMigrationGraphTreeSections } from "./migration-graph-sections-BWcFCOL6-_G0Wb4QR.mjs";
24
25
  import { a as sortLedgerEntries, i as serializeLedgerEntriesForJson, n as formatLedgerAppliedAt, o as styleHashTransition, t as MIGRATION_LOG_EMPTY_MESSAGE } from "./migration-log-table-DRiOnvzf-zTQBThqe.mjs";
26
+ import { n as executeRefListCommand, r as executeRefSetCommand, t as executeRefDeleteCommand } from "./ref-CVD6j3jA-BAgpZLNM.mjs";
25
27
  import { CliStructuredError } from "@prisma/orm-framework/errors/control";
26
28
  import { ifDefined } from "@prisma/orm-framework/utils/defined";
27
- import { join, normalize, relative, resolve } from "pathe";
29
+ import { basename, dirname, join, normalize, relative, resolve } from "pathe";
28
30
  import { existsSync, unlinkSync, writeFileSync } from "node:fs";
29
31
  import { DOCS_BASE, isStructuredError } from "@prisma/orm-framework/utils/structured-error";
30
32
  import { blindCast, castAs } from "@prisma/orm-framework/utils/casts";
31
33
  import { InternalError } from "@prisma/orm-framework/utils/internal-error";
32
- import { readFile } from "node:fs/promises";
34
+ import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
33
35
  import { APP_SPACE_ID, createControlStack } from "@prisma/orm-framework/components/control";
34
36
  import { collectConfigIssues } from "@prisma/orm-framework/config/config-validation";
35
37
  import { tmpdir } from "node:os";
38
+ import { printPsl } from "@prisma/orm-framework/psl-printer";
36
39
  import { defineCommand, defineCommandFamily, defineConfigSection, flag, positional } from "@prisma/cli-engine";
37
40
  import { CliStructuredError as CliStructuredError$1, notOk, ok } from "@prisma/cli-engine/protocol";
38
41
  import { pathToFileURL } from "node:url";
39
42
  import { build } from "esbuild";
40
- //#region ../../../1-framework/3-tooling/cli/dist/load-config-BQgwPvgu.mjs
43
+ //#region ../../../1-framework/3-tooling/cli/dist/load-config-Db2bTG_C.mjs
41
44
  const MISSING_CONFIG_ACTION = {
42
45
  kind: "run-command",
43
- label: "Create a configuration file",
46
+ label: "Create a config file",
44
47
  command: "prisma-next init"
45
48
  };
46
49
  function editConfigAction(field) {
@@ -260,16 +263,6 @@ function defineOrmCommand(def) {
260
263
  }
261
264
  });
262
265
  }
263
- /**
264
- * The database connection override, declared from here by every command that
265
- * accepts one so its brief and placeholder cannot drift apart. Resolution
266
- * order is the flag, then `config.db.connection`, then
267
- * `CONFIG.DB_CONNECTION_REQUIRED`.
268
- */
269
- const dbFlag = flag.string({
270
- brief: "Database connection string",
271
- placeholder: "url"
272
- });
273
266
  const OUTCOMES = {
274
267
  ok: "ok",
275
268
  skipped: "skipped",
@@ -302,6 +295,267 @@ function controlProgressReporter(report) {
302
295
  });
303
296
  };
304
297
  }
298
+ function hashRows(document) {
299
+ return {
300
+ kind: "fields",
301
+ rows: [
302
+ {
303
+ label: "storageHash",
304
+ value: [{
305
+ text: document.storageHash,
306
+ tone: "identifier"
307
+ }]
308
+ },
309
+ ...document.executionHash === void 0 ? [] : [{
310
+ label: "executionHash",
311
+ value: [{
312
+ text: document.executionHash,
313
+ tone: "identifier"
314
+ }]
315
+ }],
316
+ {
317
+ label: "profileHash",
318
+ value: [{
319
+ text: document.profileHash,
320
+ tone: "identifier"
321
+ }]
322
+ }
323
+ ]
324
+ };
325
+ }
326
+ function emitPresentations(inputs) {
327
+ const { document, cwd } = inputs;
328
+ return {
329
+ human: () => [
330
+ {
331
+ kind: "fields",
332
+ rail: true,
333
+ rows: [{
334
+ label: "contract",
335
+ value: relative(cwd, document.files.json)
336
+ }, {
337
+ label: "types",
338
+ value: relative(cwd, document.files.dts)
339
+ }]
340
+ },
341
+ {
342
+ kind: "summary",
343
+ status: "ok",
344
+ text: "Emitted contract.json and contract.d.ts"
345
+ },
346
+ hashRows(document)
347
+ ],
348
+ stdout: () => [document.files.json, document.files.dts],
349
+ json: () => document
350
+ };
351
+ }
352
+ function createContractEmitCommand$1({ executeContractEmit }) {
353
+ return defineOrmCommand({
354
+ help: {
355
+ summary: "Emit your contract artifacts",
356
+ description: "Reads your contract source (TypeScript or Prisma schema) and emits\ncontract.json and contract.d.ts. The contract.json contains the canonical\ncontract structure, and contract.d.ts provides TypeScript types for\ntype-safe query building. Offline — does not consult the database.",
357
+ examples: [
358
+ "contract emit",
359
+ "contract emit --output-path ./generated",
360
+ "contract emit --json"
361
+ ]
362
+ },
363
+ args: { flags: { outputPath: flag.string({
364
+ brief: "Directory to write contract.json and contract.d.ts into",
365
+ placeholder: "dir"
366
+ }) } },
367
+ needs: { config: ormConfigSection },
368
+ handler: async (args, ctx) => {
369
+ const startedAt = Date.now();
370
+ const outputPath = args.flags.outputPath === void 0 ? void 0 : resolve(ctx.cwd, args.flags.outputPath);
371
+ const result = await executeContractEmit({
372
+ config: ctx.config,
373
+ cwd: ctx.cwd,
374
+ onProgress: controlProgressReporter(ctx.report),
375
+ signal: ctx.signal,
376
+ ...ifDefined("outputPath", outputPath)
377
+ });
378
+ if (result.validationWarning !== void 0) ctx.report({
379
+ kind: "message",
380
+ severity: "warn",
381
+ text: result.validationWarning
382
+ });
383
+ const document = {
384
+ ok: true,
385
+ storageHash: result.storageHash,
386
+ ...ifDefined("executionHash", result.executionHash),
387
+ profileHash: result.profileHash,
388
+ outDir: dirname(result.files.json),
389
+ files: result.files,
390
+ timings: { total: Date.now() - startedAt }
391
+ };
392
+ ctx.report({
393
+ kind: "message",
394
+ severity: "verbose",
395
+ text: `Total time: ${document.timings.total}ms`
396
+ });
397
+ return ok(ctx.present({ data: document }, emitPresentations({
398
+ document,
399
+ cwd: ctx.cwd
400
+ })));
401
+ }
402
+ });
403
+ }
404
+ const contractEmitCommand = createContractEmitCommand$1({ executeContractEmit });
405
+ /**
406
+ * Writes a generated file the way `contract emit` publishes its pair: the
407
+ * bytes land in a temporary file beside the target and are renamed over it, so
408
+ * a run interrupted mid-write leaves the previous file intact rather than a
409
+ * truncated one.
410
+ */
411
+ async function publishTextArtifact(inputs) {
412
+ const directory = dirname(inputs.path);
413
+ const tempPath = join(directory, `.${basename(inputs.path)}.${process.pid}.${inputs.publicationToken}.next.tmp`);
414
+ await mkdir(directory, { recursive: true });
415
+ try {
416
+ await writeFile(tempPath, inputs.content, "utf-8");
417
+ await rename(tempPath, inputs.path);
418
+ } finally {
419
+ await rm(tempPath, { force: true });
420
+ }
421
+ }
422
+ /**
423
+ * The database connection override, declared from here by every command that
424
+ * accepts one so its brief and placeholder cannot drift apart. Resolution
425
+ * order is the flag, then `config.db.connection`, then
426
+ * `CONFIG.DB_CONNECTION_REQUIRED`.
427
+ */
428
+ const dbFlag = flag.string({
429
+ brief: "Database connection string",
430
+ placeholder: "url"
431
+ });
432
+ /** The file `contract infer` writes when nothing names another. */
433
+ const INFERRED_CONTRACT_FILENAME = "contract.prisma";
434
+ /**
435
+ * Where `contract infer` writes the PSL it inferred: `--output`, else
436
+ * `contract.prisma` beside the emitted contract, else `contract.prisma` in the
437
+ * invocation directory.
438
+ */
439
+ function inferredContractPathFor(inputs) {
440
+ if (inputs.output !== void 0) return resolve(inputs.cwd, inputs.output);
441
+ const contractOutput = inputs.config.contract?.output;
442
+ if (contractOutput !== void 0) return join(dirname(resolve(inputs.cwd, contractOutput)), INFERRED_CONTRACT_FILENAME);
443
+ return join(inputs.cwd, INFERRED_CONTRACT_FILENAME);
444
+ }
445
+ function inferPresentations(inputs) {
446
+ const { document, database } = inputs;
447
+ return {
448
+ human: () => [...database === void 0 ? [] : [{
449
+ kind: "fields",
450
+ rail: true,
451
+ rows: [{
452
+ label: "database",
453
+ value: database
454
+ }]
455
+ }], {
456
+ kind: "summary",
457
+ status: "ok",
458
+ text: [{ text: "Contract written to " }, {
459
+ text: document.psl.path,
460
+ tone: "identifier"
461
+ }]
462
+ }],
463
+ json: () => document
464
+ };
465
+ }
466
+ function createContractInferCommand({ createControlClient, printPsl }) {
467
+ return defineOrmCommand({
468
+ help: {
469
+ summary: "Infer a PSL contract from the live database schema",
470
+ description: "Reads the live database schema and writes an inferred PSL contract to\ndisk. This command stops at contract.prisma; follow it with\n`contract emit` and `db sign` as separate steps. An existing file at the\noutput path is overwritten, with a warning.",
471
+ examples: [
472
+ "contract infer --db $DATABASE_URL",
473
+ "contract infer --db $DATABASE_URL --output ./src/prisma/contract.prisma",
474
+ "contract infer --json"
475
+ ]
476
+ },
477
+ args: { flags: {
478
+ db: dbFlag,
479
+ output: flag.string({
480
+ brief: "Write the inferred PSL contract to the specified path",
481
+ placeholder: "path"
482
+ })
483
+ } },
484
+ needs: { config: ormConfigSection },
485
+ handler: async (args, ctx) => {
486
+ const startedAt = Date.now();
487
+ const dbConnection = args.flags.db ?? ctx.config.db?.connection;
488
+ if (dbConnection === void 0) return notOk(normalizeError(errorDatabaseConnectionRequired({
489
+ why: "Database connection is required for contract infer (set db.connection in prisma-next.config.ts, or pass --db <url>)",
490
+ commandName: "contract infer",
491
+ missingFlags: ["--db"]
492
+ })));
493
+ if (ctx.config.driver === void 0) return notOk(normalizeError(errorDriverRequired({ why: "Config.driver is required for contract infer" })));
494
+ const client = createControlClient({
495
+ family: ctx.config.family,
496
+ target: ctx.config.target,
497
+ adapter: ctx.config.adapter,
498
+ driver: ctx.config.driver,
499
+ extensions: ctx.config.extensions ?? []
500
+ });
501
+ let pslContent;
502
+ try {
503
+ const schema = await client.introspect({
504
+ connection: dbConnection,
505
+ onProgress: controlProgressReporter(ctx.report)
506
+ });
507
+ const pslContractAst = client.inferPslContract(schema);
508
+ if (pslContractAst === void 0) return notOk(normalizeError(errorRuntime$1("CONTRACT.INFER_UNSUPPORTED", "contract infer is not supported for this family", {
509
+ why: "The configured family does not implement the PslContractInferCapable capability, so an inferred PSL contract cannot be produced from the live database schema.",
510
+ fix: "Use a family that supports contract inference (e.g. SQL/Postgres)."
511
+ })));
512
+ pslContent = printPsl(pslContractAst, { pslBlockDescriptors: client.getPslBlockDescriptors() });
513
+ } catch (error) {
514
+ if (CliStructuredError$1$1.is(error)) return notOk(normalizeError(error));
515
+ const safeMessage = sanitizeErrorMessage(error instanceof Error ? error.message : String(error), typeof dbConnection === "string" ? dbConnection : void 0);
516
+ return notOk(normalizeError(errorUnexpected(safeMessage, { why: `Unexpected error during contract infer: ${safeMessage}` })));
517
+ } finally {
518
+ await closeQuietly(client);
519
+ }
520
+ const outputPath = inferredContractPathFor({
521
+ config: ctx.config,
522
+ cwd: ctx.cwd,
523
+ output: args.flags.output
524
+ });
525
+ const displayPath = relative(ctx.cwd, outputPath);
526
+ if (existsSync(outputPath)) ctx.report({
527
+ kind: "message",
528
+ severity: "warn",
529
+ text: `Overwriting existing file: ${displayPath}`
530
+ });
531
+ await publishTextArtifact({
532
+ path: outputPath,
533
+ content: pslContent,
534
+ publicationToken: String(process.hrtime.bigint())
535
+ });
536
+ const database = typeof dbConnection === "string" ? maskConnectionUrl(dbConnection) : void 0;
537
+ const document = {
538
+ ok: true,
539
+ summary: "Contract inferred successfully",
540
+ target: {
541
+ familyId: ctx.config.family.familyId,
542
+ id: ctx.config.target.targetId
543
+ },
544
+ psl: { path: displayPath },
545
+ meta: { ...ifDefined("dbUrl", database) },
546
+ timings: { total: Date.now() - startedAt }
547
+ };
548
+ return ok(ctx.present({ data: document }, inferPresentations({
549
+ document,
550
+ database
551
+ })));
552
+ }
553
+ });
554
+ }
555
+ const contractInferCommand = createContractInferCommand({
556
+ createControlClient,
557
+ printPsl
558
+ });
305
559
  function operationNode(operation) {
306
560
  return operation.operationClass === "destructive" ? {
307
561
  label: operation.label,
@@ -903,6 +1157,44 @@ function createDbSchemaCommand(createClient) {
903
1157
  });
904
1158
  }
905
1159
  const dbSchemaCommand = createDbSchemaCommand(createControlClient);
1160
+ const NOTHING_TO_FORMAT = "Nothing to format (contract source is not PSL).";
1161
+ function formatPresentations(document, cwd) {
1162
+ const path = document.path;
1163
+ return {
1164
+ human: () => document.formatted && path !== void 0 ? [{
1165
+ kind: "summary",
1166
+ status: "ok",
1167
+ text: [{ text: "Formatted " }, {
1168
+ text: relative(cwd, path),
1169
+ tone: "identifier"
1170
+ }]
1171
+ }] : [{
1172
+ kind: "summary",
1173
+ status: "info",
1174
+ text: NOTHING_TO_FORMAT
1175
+ }],
1176
+ json: () => document
1177
+ };
1178
+ }
1179
+ function createFormatCommand$1(execute = executeFormat) {
1180
+ return defineOrmCommand({
1181
+ help: {
1182
+ summary: "Format your PSL contract source",
1183
+ description: "Formats the Prisma schema (PSL) contract source declared in your config\n(contract.source.inputs[0]) in place. Only runs when contract.source.format\nis 'psl'; a TypeScript or unset source is left untouched. Indent and newline\nare read from the optional formatter config section, defaulting to two\nspaces and the system newline.",
1184
+ examples: ["format", "format --json"]
1185
+ },
1186
+ needs: { config: ormConfigSection },
1187
+ handler: async (_args, ctx) => {
1188
+ const result = await execute({
1189
+ config: ctx.config,
1190
+ cwd: ctx.cwd
1191
+ });
1192
+ if (!result.ok) return notOk(normalizeError(result.failure));
1193
+ return ok(ctx.present({ data: result.value }, formatPresentations(result.value, ctx.cwd)));
1194
+ }
1195
+ });
1196
+ }
1197
+ const formatCommand = createFormatCommand$1();
906
1198
  const STATUS_ACTION = runCommandAction("Check every space against the database", "prisma-next migration status");
907
1199
  /**
908
1200
  * The route the migration will take. The graph is a drawing — the engine cannot
@@ -1337,7 +1629,7 @@ const migrationGraphCommand = defineOrmCommand({
1337
1629
  })));
1338
1630
  }
1339
1631
  });
1340
- function listPresentations(inputs) {
1632
+ function listPresentations$1(inputs) {
1341
1633
  const legend = inputs.legend;
1342
1634
  return {
1343
1635
  human: () => [
@@ -1410,7 +1702,7 @@ const migrationListCommand = defineOrmCommand({
1410
1702
  styler,
1411
1703
  palette: TONE_MIGRATION_GRAPH_PALETTE
1412
1704
  }) : void 0;
1413
- return ok(ctx.present({ data: listed.value }, listPresentations({
1705
+ return ok(ctx.present({ data: listed.value }, listPresentations$1({
1414
1706
  list: listed.value,
1415
1707
  tree,
1416
1708
  migrationsDir: displayPath(migrationsDir, ctx.cwd),
@@ -1761,6 +2053,160 @@ const migrationShowCommand = defineOrmCommand({
1761
2053
  })));
1762
2054
  }
1763
2055
  });
2056
+ function deletePresentations(document) {
2057
+ return {
2058
+ human: () => [{
2059
+ kind: "summary",
2060
+ status: "ok",
2061
+ text: [
2062
+ { text: "Deleted ref \"" },
2063
+ {
2064
+ text: document.ref,
2065
+ tone: "ref"
2066
+ },
2067
+ { text: "\"" }
2068
+ ]
2069
+ }],
2070
+ json: () => document
2071
+ };
2072
+ }
2073
+ function createRefDeleteCommand(execute = executeRefDeleteCommand) {
2074
+ return defineOrmCommand({
2075
+ help: {
2076
+ summary: "Delete a ref",
2077
+ description: "Removes migrations/app/refs/<name>.json. The contract the ref pointed at\nis untouched: a ref is a pointer, and its target survives the deletion.",
2078
+ examples: ["ref delete staging", "ref delete staging --json"]
2079
+ },
2080
+ args: { positionals: { name: positional.string({
2081
+ brief: "Ref name to delete",
2082
+ placeholder: "name"
2083
+ }) } },
2084
+ needs: { config: ormConfigSection },
2085
+ handler: async (args, ctx) => {
2086
+ const result = await execute(args.positionals.name, {
2087
+ config: ctx.config,
2088
+ cwd: ctx.cwd
2089
+ });
2090
+ if (!result.ok) return notOk(normalizeError(result.failure));
2091
+ return ok(ctx.present({ data: result.value }, deletePresentations(result.value)));
2092
+ }
2093
+ });
2094
+ }
2095
+ const refDeleteCommand = createRefDeleteCommand();
2096
+ const HEADING_REF = "Ref";
2097
+ const HEADING_CONTRACT = "Contract";
2098
+ const HEADING_INVARIANTS = "Invariants";
2099
+ const EMPTY_MESSAGE = "No refs defined";
2100
+ /**
2101
+ * The refs as a grid the engine sizes. The invariants heading appears only
2102
+ * when a ref carries any, as the commander shell appended them only then.
2103
+ */
2104
+ function refsGrid(refs) {
2105
+ const entries = Object.entries(refs);
2106
+ const showInvariants = entries.some(([, entry]) => entry.invariants.length > 0);
2107
+ return {
2108
+ kind: "table",
2109
+ columns: showInvariants ? [
2110
+ HEADING_REF,
2111
+ HEADING_CONTRACT,
2112
+ HEADING_INVARIANTS
2113
+ ] : [HEADING_REF, HEADING_CONTRACT],
2114
+ rows: entries.map(([name, entry]) => {
2115
+ const cells = [[{
2116
+ text: name,
2117
+ tone: "ref"
2118
+ }], [{
2119
+ text: entry.hash,
2120
+ tone: "identifier"
2121
+ }]];
2122
+ if (showInvariants) cells.push(entry.invariants.join(", "));
2123
+ return cells;
2124
+ })
2125
+ };
2126
+ }
2127
+ function listPresentations(document) {
2128
+ return {
2129
+ human: () => Object.keys(document.refs).length === 0 ? [{
2130
+ kind: "summary",
2131
+ status: "info",
2132
+ text: EMPTY_MESSAGE
2133
+ }] : [refsGrid(document.refs)],
2134
+ json: () => document
2135
+ };
2136
+ }
2137
+ function createRefListCommand(execute = executeRefListCommand) {
2138
+ return defineOrmCommand({
2139
+ help: {
2140
+ summary: "List every named ref",
2141
+ description: "Reads migrations/app/refs/ and reports each ref with the contract hash it\npoints at and the invariants recorded against it. Offline — does not\nconsult the database.",
2142
+ examples: ["ref list", "ref list --json"]
2143
+ },
2144
+ needs: { config: ormConfigSection },
2145
+ handler: async (_args, ctx) => {
2146
+ const result = await execute({
2147
+ config: ctx.config,
2148
+ cwd: ctx.cwd
2149
+ });
2150
+ if (!result.ok) return notOk(normalizeError(result.failure));
2151
+ return ok(ctx.present({ data: result.value }, listPresentations(result.value)));
2152
+ }
2153
+ });
2154
+ }
2155
+ const refListCommand = createRefListCommand();
2156
+ function setPresentations(document) {
2157
+ return {
2158
+ human: () => [{
2159
+ kind: "summary",
2160
+ status: "ok",
2161
+ text: [
2162
+ { text: "Set ref \"" },
2163
+ {
2164
+ text: document.ref,
2165
+ tone: "ref"
2166
+ },
2167
+ { text: "\" → " },
2168
+ {
2169
+ text: document.hash,
2170
+ tone: "identifier"
2171
+ }
2172
+ ]
2173
+ }],
2174
+ json: () => document
2175
+ };
2176
+ }
2177
+ function createRefSetCommand(execute = executeRefSetCommand) {
2178
+ return defineOrmCommand({
2179
+ help: {
2180
+ summary: "Point a ref at a contract",
2181
+ description: "Writes migrations/app/refs/<name>.json so a logical environment name\nresolves to a contract hash. The contract is given as a hash or prefix,\nanother ref name, a migration directory name, or <dir>^ for that\nmigration's source contract. Offline — the contract must already be a\nnode of the on-disk migration graph, with its snapshot present.",
2182
+ examples: [
2183
+ "ref set staging 4cb4256",
2184
+ "ref set production 20260101T1000_add_user",
2185
+ "ref set staging production --json"
2186
+ ]
2187
+ },
2188
+ args: { positionals: {
2189
+ name: positional.string({
2190
+ brief: "Ref name (e.g. staging, production)",
2191
+ placeholder: "name"
2192
+ }),
2193
+ contract: positional.string({
2194
+ brief: "Contract reference: hash, prefix, ref name, migration dir name, or <dir>^",
2195
+ placeholder: "contract"
2196
+ })
2197
+ } },
2198
+ needs: { config: ormConfigSection },
2199
+ handler: async (args, ctx) => {
2200
+ const result = await execute(args.positionals.name, args.positionals.contract, {
2201
+ config: ctx.config,
2202
+ cwd: ctx.cwd
2203
+ });
2204
+ if (!result.ok) return notOk(normalizeError(result.failure));
2205
+ return ok(ctx.present({ data: result.value }, setPresentations(result.value)));
2206
+ }
2207
+ });
2208
+ }
2209
+ const refSetCommand = createRefSetCommand();
1764
2210
  /**
1765
2211
  * The engine derives each diagnostic's docs link from this base plus the
1766
2212
  * dotted code.
@@ -1774,13 +2220,19 @@ const DOCS_BASE_URL = `${DOCS_BASE}/`;
1774
2220
  const ormCommandFamily = defineCommandFamily({
1775
2221
  configSection: ormConfigSection,
1776
2222
  commands: {
2223
+ "contract emit": contractEmitCommand,
2224
+ "contract infer": contractInferCommand,
1777
2225
  "db init": dbInitCommand,
1778
2226
  "db schema": dbSchemaCommand,
2227
+ format: formatCommand,
1779
2228
  migrate: migrateCommand,
1780
2229
  "migration graph": migrationGraphCommand,
1781
2230
  "migration list": migrationListCommand,
1782
2231
  "migration log": migrationLogCommand,
1783
- "migration show": migrationShowCommand
2232
+ "migration show": migrationShowCommand,
2233
+ "ref delete": refDeleteCommand,
2234
+ "ref list": refListCommand,
2235
+ "ref set": refSetCommand
1784
2236
  },
1785
2237
  docsBaseUrl: DOCS_BASE_URL,
1786
2238
  redirects: [{