@prisma/composer-prisma-cloud 0.9.0 → 0.10.0-dev.2

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.
@@ -23667,10 +23667,7 @@ function _defu(baseObject, defaults, namespace = ".", merger) {
23667
23667
  function createDefu(merger) {
23668
23668
  return (...arguments_) => arguments_.reduce((p, c) => _defu(p, c, "", merger), {});
23669
23669
  }
23670
- var defu;
23671
- var init_defu = __esmMin((() => {
23672
- defu = createDefu();
23673
- }));
23670
+ const defu = createDefu();
23674
23671
  /**
23675
23672
  * Cloud provider instance metadata service FQDNs. These resolve to link-local
23676
23673
  * IPs (usually `169.254.169.254`) inside their respective clouds and are
@@ -23914,7 +23911,6 @@ function isLoopbackHost(host) {
23914
23911
  }
23915
23912
  init_env();
23916
23913
  init_error();
23917
- init_defu();
23918
23914
  async function runPluginInit(context) {
23919
23915
  let options = context.options;
23920
23916
  const plugins = options.plugins || [];
@@ -30586,7 +30582,6 @@ const changeEmail = createAuthEndpoint("/change-email", {
30586
30582
  });
30587
30583
  init_env();
30588
30584
  init_error();
30589
- init_defu();
30590
30585
  init_instrumentation();
30591
30586
  const defuReplaceArrays = createDefu((obj, key, value) => {
30592
30587
  if (Array.isArray(obj[key]) && Array.isArray(value)) {
@@ -32348,7 +32343,7 @@ function rowChanged(baseRow, cloneRow) {
32348
32343
  return JSON.stringify(baseRow) !== JSON.stringify(cloneRow);
32349
32344
  }
32350
32345
  var memoryAdapter;
32351
- var init_dist$3 = __esmMin((() => {
32346
+ var init_dist$2 = __esmMin((() => {
32352
32347
  init_adapter();
32353
32348
  init_env();
32354
32349
  memoryAdapter = (db, config) => {
@@ -32609,7 +32604,7 @@ async function getBaseAdapter(options, handleDirectDatabase) {
32609
32604
  acc[key] = [];
32610
32605
  return acc;
32611
32606
  }, {});
32612
- const { memoryAdapter } = await Promise.resolve().then(() => (init_dist$3(), dist_exports));
32607
+ const { memoryAdapter } = await Promise.resolve().then(() => (init_dist$2(), dist_exports));
32613
32608
  adapter = memoryAdapter(memoryDB)(options);
32614
32609
  } else if (typeof options.database === "function") adapter = options.database(options);
32615
32610
  else adapter = await handleDirectDatabase(options);
@@ -49496,7 +49491,7 @@ var init_handle_empty_in_lists = __esmMin((() => {}));
49496
49491
  var init_safe_null_comparison_plugin = __esmMin((() => {}));
49497
49492
  var init_constraint_node = __esmMin((() => {}));
49498
49493
  var init_simple_reference_expression_node = __esmMin((() => {}));
49499
- var init_dist$2 = __esmMin((() => {
49494
+ var init_dist$1 = __esmMin((() => {
49500
49495
  init_kysely();
49501
49496
  init_query_creator();
49502
49497
  init_query_finalizer();
@@ -49713,7 +49708,7 @@ var BunSqliteQueryCompiler;
49713
49708
  var BunSqliteDialect;
49714
49709
  var init_bun_sqlite_dialect_DTyyejk1 = __esmMin((() => {
49715
49710
  init_kysely_migration_tables_B2_rTeXm();
49716
- init_dist$2();
49711
+ init_dist$1();
49717
49712
  BunSqliteAdapter = class {
49718
49713
  get supportsCreateIfNotExists() {
49719
49714
  return true;
@@ -49882,7 +49877,7 @@ var NodeSqliteQueryCompiler;
49882
49877
  var NodeSqliteDialect;
49883
49878
  var init_node_sqlite_dialect = __esmMin((() => {
49884
49879
  init_kysely_migration_tables_B2_rTeXm();
49885
- init_dist$2();
49880
+ init_dist$1();
49886
49881
  NodeSqliteAdapter = class {
49887
49882
  get supportsCreateIfNotExists() {
49888
49883
  return true;
@@ -50050,7 +50045,7 @@ var D1SqliteQueryCompiler;
50050
50045
  var D1SqliteDialect;
50051
50046
  var init_d1_sqlite_dialect_CDCl_qH4 = __esmMin((() => {
50052
50047
  init_kysely_migration_tables_B2_rTeXm();
50053
- init_dist$2();
50048
+ init_dist$1();
50054
50049
  D1SqliteAdapter = class extends SqliteAdapter {};
50055
50050
  D1SqliteDriver = class {
50056
50051
  #config;
@@ -50223,8 +50218,8 @@ function insensitiveNe(columnRef, value) {
50223
50218
  }
50224
50219
  var createKyselyAdapter;
50225
50220
  var kyselyAdapter;
50226
- var init_dist$1 = __esmMin((() => {
50227
- init_dist$2();
50221
+ var init_dist = __esmMin((() => {
50222
+ init_dist$1();
50228
50223
  init_adapter();
50229
50224
  init_env();
50230
50225
  init_string();
@@ -50740,7 +50735,7 @@ var kysely_adapter_exports = /* @__PURE__ */ __exportAll({
50740
50735
  kyselyAdapter: () => kyselyAdapter
50741
50736
  });
50742
50737
  var init_kysely_adapter = __esmMin((() => {
50743
- init_dist$1();
50738
+ init_dist();
50744
50739
  }));
50745
50740
  init_error();
50746
50741
  async function getAdapter(options) {
@@ -50793,9 +50788,9 @@ function getSchema(config) {
50793
50788
  }
50794
50789
  init_get_tables();
50795
50790
  init_env();
50796
- init_dist$1();
50791
+ init_dist();
50797
50792
  init_adapter();
50798
- init_dist$2();
50793
+ init_dist$1();
50799
50794
  const map = {
50800
50795
  postgres: {
50801
50796
  string: [
@@ -51643,7 +51638,6 @@ init_get_tables();
51643
51638
  init_env();
51644
51639
  init_error();
51645
51640
  init_id();
51646
- init_defu();
51647
51641
  /**
51648
51642
  * Estimates the entropy of a string in bits.
51649
51643
  * This is a simple approximation that helps detect low-entropy secrets.
@@ -51854,7 +51848,7 @@ Most of the features of Better Auth will not work correctly.`);
51854
51848
  return ctx;
51855
51849
  }
51856
51850
  init_error();
51857
- init_dist$1();
51851
+ init_dist();
51858
51852
  const init = async (options) => {
51859
51853
  const adapter = await getAdapter(options);
51860
51854
  const getDatabaseType = (database) => getKyselyDatabaseType(database) || "unknown";
@@ -59502,8 +59496,12 @@ function ifDefined(key, value) {
59502
59496
  return value !== void 0 ? blindCast({ [key]: value }) : {};
59503
59497
  }
59504
59498
  const STRUCTURED_CODE_RE = /^[A-Z][A-Z0-9]*\.[A-Z][A-Z0-9_]*$/;
59499
+ /** Whether a bare string is a published `NAMESPACE.SUBCODE` code. */
59500
+ function isStructuredErrorCode(code) {
59501
+ return STRUCTURED_CODE_RE.test(code);
59502
+ }
59505
59503
  function isStructuredError(e) {
59506
- return typeof e === "object" && e !== null && "code" in e && typeof e.code === "string" && STRUCTURED_CODE_RE.test(e.code) && "message" in e && typeof e.message === "string";
59504
+ return typeof e === "object" && e !== null && "code" in e && typeof e.code === "string" && isStructuredErrorCode(e.code) && "message" in e && typeof e.message === "string";
59507
59505
  }
59508
59506
  function structuredError(code, message, options) {
59509
59507
  const error = options?.cause !== void 0 ? new Error(message, { cause: options.cause }) : new Error(message);
@@ -59515,6 +59513,7 @@ function structuredError(code, message, options) {
59515
59513
  code,
59516
59514
  ...ifDefined("why", options?.why),
59517
59515
  ...ifDefined("fix", options?.fix),
59516
+ ...ifDefined("nextActions", options?.nextActions),
59518
59517
  ...ifDefined("where", options?.where),
59519
59518
  ...ifDefined("severity", options?.severity),
59520
59519
  ...ifDefined("meta", options?.meta),
@@ -59540,7 +59539,7 @@ var CliStructuredError = class extends Error {
59540
59539
  code;
59541
59540
  severity;
59542
59541
  constructor(code, summary, options) {
59543
- super(summary);
59542
+ super(summary, options?.cause !== void 0 ? { cause: options.cause } : void 0);
59544
59543
  this.name = "CliStructuredError";
59545
59544
  this.code = code;
59546
59545
  this.severity = options?.severity ?? "error";
@@ -59552,6 +59551,7 @@ var CliStructuredError = class extends Error {
59552
59551
  Object.assign(this, {
59553
59552
  ...ifDefined("why", options?.why),
59554
59553
  ...ifDefined("fix", fix),
59554
+ ...ifDefined("nextActions", options?.nextActions),
59555
59555
  ...ifDefined("where", where),
59556
59556
  ...ifDefined("meta", options?.meta),
59557
59557
  ...ifDefined("docsUrl", options?.docsUrl)
@@ -59559,6 +59559,9 @@ var CliStructuredError = class extends Error {
59559
59559
  }
59560
59560
  /**
59561
59561
  * Converts this error to a CLI error envelope for output formatting.
59562
+ *
59563
+ * This is the boundary that emits the envelope, so it is where a missing
59564
+ * `nextActions` becomes `[]`.
59562
59565
  */
59563
59566
  toEnvelope() {
59564
59567
  return {
@@ -59568,6 +59571,7 @@ var CliStructuredError = class extends Error {
59568
59571
  summary: this.message,
59569
59572
  ...ifDefined("why", this.why),
59570
59573
  ...ifDefined("fix", this.fix),
59574
+ nextActions: this.nextActions ?? [],
59571
59575
  ...ifDefined("where", this.where),
59572
59576
  ...ifDefined("meta", this.meta),
59573
59577
  ...ifDefined("docsUrl", this.docsUrl)
@@ -59589,8 +59593,12 @@ var CliStructuredError = class extends Error {
59589
59593
  function errorConfigValidation(field, options) {
59590
59594
  return new CliStructuredError("CONFIG.VALIDATION_FAILED", "Config validation error", {
59591
59595
  why: options?.why ?? `Config must have a "${field}" field`,
59592
- fix: "Check your prisma-next.config.ts and ensure all required fields are provided",
59593
- docsUrl: docsUrlFor("CONFIG.VALIDATION_FAILED")
59596
+ fix: "Check your prisma.config.ts and ensure all required fields are provided",
59597
+ docsUrl: docsUrlFor("CONFIG.VALIDATION_FAILED"),
59598
+ meta: {
59599
+ field,
59600
+ ...options?.section !== void 0 ? { section: options.section } : {}
59601
+ }
59594
59602
  });
59595
59603
  }
59596
59604
  function postgresError(code, message, options) {
@@ -59601,7 +59609,7 @@ function postgresError(code, message, options) {
59601
59609
  * — named by `operation` (e.g. `createTable`, `dropColumn`, `dataTransform`) —
59602
59610
  * was invoked, but the migration was constructed without a `ControlStack`.
59603
59611
  * Concrete authoring usage always goes through the migration CLI entrypoint,
59604
- * which assembles a stack from the loaded `prisma-next.config.ts`; reaching this
59612
+ * which assembles a stack from the loaded `prisma.config.ts`; reaching this
59605
59613
  * error means a test fixture or ad-hoc consumer instantiated `PostgresMigration`
59606
59614
  * with the no-arg form (legal for `operations` / `describe` introspection only).
59607
59615
  *
@@ -59621,7 +59629,7 @@ function postgresError(code, message, options) {
59621
59629
  function errorPostgresMigrationStackMissing(operation) {
59622
59630
  return new CliStructuredError("MIGRATION.POSTGRES_CONTROL_STACK_MISSING", `PostgresMigration.${operation} requires a control adapter`, {
59623
59631
  why: `PostgresMigration.${operation} was invoked on an instance constructed without a ControlStack, so the stored controlAdapter is undefined and the operation cannot lower its plan.`,
59624
- fix: "Construct the migration via the migration CLI entrypoint (which assembles a ControlStack from the loaded prisma-next.config.ts), or pass a ControlStack containing a Postgres adapter to the migration constructor in test fixtures.",
59632
+ fix: "Construct the migration via the migration CLI entrypoint (which assembles a ControlStack from the loaded prisma.config.ts), or pass a ControlStack containing a Postgres adapter to the migration constructor in test fixtures.",
59625
59633
  meta: { operation }
59626
59634
  });
59627
59635
  }
@@ -59984,6 +59992,22 @@ function normalizeSchemaNativeType(nativeType) {
59984
59992
  if (trimmed.includes(" without time zone")) return trimmed.replace(" without time zone", "");
59985
59993
  return trimmed;
59986
59994
  }
59995
+ /**
59996
+ * A bug in Prisma Next, not a user error. Never catch this except at the
59997
+ * outermost boundary for crash reporting — an InternalError means an invariant
59998
+ * broke and the process cannot reliably continue. User-facing failures use
59999
+ * `structuredError` with a dotted code instead.
60000
+ */
60001
+ var InternalError = class extends Error {
60002
+ isPrismaInternalError = true;
60003
+ constructor(message, options) {
60004
+ super(message, options?.cause !== void 0 ? { cause: options.cause } : void 0);
60005
+ this.name = "InternalError";
60006
+ }
60007
+ };
60008
+ function assertNever(value, message) {
60009
+ throw new InternalError(message ?? `Unreachable: unexpected value ${String(value)}`);
60010
+ }
59987
60011
  function isJsonArray(value) {
59988
60012
  return Array.isArray(value);
59989
60013
  }
@@ -60002,170 +60026,6 @@ function frozenCodecRef(codec) {
60002
60026
  ...ifDefined("many", codec.many)
60003
60027
  });
60004
60028
  }
60005
- function asNamespaceId(value) {
60006
- return blindCast(value);
60007
- }
60008
- /**
60009
- * Resolves the effective control policy for a storage-plane node.
60010
- *
60011
- * Precedence: node-level value → contract default → `'managed'`.
60012
- *
60013
- * Both parameters are optional raw values so this function stays node-type-agnostic
60014
- * and can be called by any consumer (verifier, planner, etc.) without importing IR classes.
60015
- */
60016
- function effectiveControlPolicy(nodeControl, defaultControlPolicy) {
60017
- return nodeControl ?? defaultControlPolicy ?? "managed";
60018
- }
60019
- const CrossReferenceSchema = /* @__PURE__ */ blindCast(/* @__PURE__ */ type({
60020
- "+": "reject",
60021
- namespace: "string",
60022
- model: "string",
60023
- "space?": "string"
60024
- }));
60025
- /**
60026
- * Runtime predicate for `ColumnDefaultLiteralInputValue`. Authoring layers
60027
- * resolve template values from caller-supplied args (typed `unknown` at the
60028
- * boundary) and need to validate before constructing a `ColumnDefault`.
60029
- * Accepts JSON primitives, plain arrays/objects of JSON values, and `Date`
60030
- * instances. Rejects functions, class instances (other than `Date`),
60031
- * `undefined`, `bigint`, `symbol`, and arrays/objects containing those.
60032
- */
60033
- function isColumnDefaultLiteralInputValue(value) {
60034
- if (value === null) return true;
60035
- const t = typeof value;
60036
- if (t === "string" || t === "number" || t === "boolean") return true;
60037
- if (value instanceof Date) return true;
60038
- if (Array.isArray(value)) return value.every(isColumnDefaultLiteralInputValue);
60039
- if (t === "object" && Object.getPrototypeOf(value) === Object.prototype) return Object.values(value).every(isColumnDefaultLiteralInputValue);
60040
- return false;
60041
- }
60042
- function isColumnDefault(value) {
60043
- if (typeof value !== "object" || value === null) return false;
60044
- const kind = value.kind;
60045
- if (kind === "literal") return "value" in value;
60046
- if (kind === "function") return typeof value.expression === "string";
60047
- return false;
60048
- }
60049
- var DdlColumnDefault = class {
60050
- freeze() {
60051
- Object.freeze(this);
60052
- }
60053
- };
60054
- var LiteralColumnDefault = class extends DdlColumnDefault {
60055
- kind = "literal";
60056
- value;
60057
- constructor(value) {
60058
- super();
60059
- if (!isColumnDefaultLiteralInputValue(value)) throw structuredError("CONTRACT.DEFAULT_INVALID", "Invalid column default literal value");
60060
- this.value = value;
60061
- this.freeze();
60062
- }
60063
- accept(visitor, ctx) {
60064
- return visitor.literal(this, ctx);
60065
- }
60066
- };
60067
- var FunctionColumnDefault = class extends DdlColumnDefault {
60068
- kind = "function";
60069
- expression;
60070
- constructor(expression) {
60071
- super();
60072
- this.expression = expression;
60073
- this.freeze();
60074
- }
60075
- accept(visitor, ctx) {
60076
- return visitor.function(this, ctx);
60077
- }
60078
- };
60079
- var DdlColumn = class {
60080
- name;
60081
- type;
60082
- notNull;
60083
- primaryKey;
60084
- default;
60085
- /** Codec identity for this column. When present, the DDL walker resolves the codec via `codecLookup.get(codecRef.codecId)` and calls `codec.encode(default.value, {})` to obtain the wire value before inlining the literal default into the DDL string. When absent, literal defaults follow RawSqlLiteral wire-scalar semantics (string / number / boolean / bigint / null / Uint8Array / Date inlined directly). */
60086
- codecRef;
60087
- constructor(options) {
60088
- this.name = options.name;
60089
- this.type = options.type;
60090
- this.notNull = options.notNull;
60091
- this.primaryKey = options.primaryKey;
60092
- this.default = options.default;
60093
- this.codecRef = options.codecRef;
60094
- Object.freeze(this);
60095
- }
60096
- };
60097
- var DdlNode = class {
60098
- /**
60099
- * Structural brand: every DDL node answers `true`. Lets {@link isDdlNode}
60100
- * recognise any `DdlNode` subclass — including target-contributed kinds —
60101
- * without a central kind registry that subclasses would have to register
60102
- * into.
60103
- */
60104
- isDdlNode() {
60105
- return true;
60106
- }
60107
- freeze() {
60108
- Object.freeze(this);
60109
- }
60110
- collectParamRefs() {
60111
- return [];
60112
- }
60113
- };
60114
- function isDdlNode(value) {
60115
- return typeof value === "object" && value !== null && "isDdlNode" in value && typeof value.isDdlNode === "function";
60116
- }
60117
- /**
60118
- * A composite (or single-column) PRIMARY KEY constraint on a `CreateTable`
60119
- * node. When `name` is set, the adapter renders `CONSTRAINT <name> PRIMARY KEY
60120
- * (…)`; otherwise it renders an anonymous `PRIMARY KEY (…)`.
60121
- *
60122
- * Frozen on construction — immutable after creation.
60123
- */
60124
- var PrimaryKeyConstraint = class {
60125
- kind = "primary-key";
60126
- columns;
60127
- name;
60128
- constructor(options) {
60129
- this.columns = Object.freeze([...options.columns]);
60130
- this.name = options.name;
60131
- Object.freeze(this);
60132
- }
60133
- };
60134
- /**
60135
- * A table-level CHECK constraint carrying a raw SQL predicate expression. Used
60136
- * for checks that are not enum value-set restrictions — e.g. the element-non-null
60137
- * constraint on a scalar-array column (`array_position(col, NULL) IS NULL`).
60138
- * The `expression` is emitted verbatim, so callers must supply safe,
60139
- * pre-validated SQL.
60140
- *
60141
- * Frozen on construction — immutable after creation.
60142
- */
60143
- var CheckExpressionConstraint = class {
60144
- kind = "check-expression";
60145
- name;
60146
- expression;
60147
- constructor(options) {
60148
- this.name = options.name;
60149
- this.expression = options.expression;
60150
- Object.freeze(this);
60151
- }
60152
- };
60153
- /**
60154
- * A bug in Prisma Next, not a user error. Never catch this except at the
60155
- * outermost boundary for crash reporting — an InternalError means an invariant
60156
- * broke and the process cannot reliably continue. User-facing failures use
60157
- * `structuredError` with a dotted code instead.
60158
- */
60159
- var InternalError = class extends Error {
60160
- isPrismaInternalError = true;
60161
- constructor(message, options) {
60162
- super(message, options?.cause !== void 0 ? { cause: options.cause } : void 0);
60163
- this.name = "InternalError";
60164
- }
60165
- };
60166
- function assertNever(value, message) {
60167
- throw new InternalError(message ?? `Unreachable: unexpected value ${String(value)}`);
60168
- }
60169
60029
  const toAnyExpressionVisitor = {
60170
60030
  columnRef: (expr) => expr,
60171
60031
  identifierRef: (expr) => expr,
@@ -60378,7 +60238,7 @@ var FunctionSource = class FunctionSource extends FromSource {
60378
60238
  ordinality;
60379
60239
  constructor(fn, args, alias, ordinality = false) {
60380
60240
  super();
60381
- if (alias?.columnAliases?.length === 0) throw structuredError("SQL.AST_INVALID", "FunctionSource column aliases must not be empty", { meta: {
60241
+ if (alias?.columnAliases?.length === 0) throw structuredError("RUNTIME.AST_INVALID", "FunctionSource column aliases must not be empty", { meta: {
60382
60242
  kind: "function-source",
60383
60243
  field: "columnAliases"
60384
60244
  } });
@@ -60676,7 +60536,7 @@ var CaseExpr = class CaseExpr extends Expression {
60676
60536
  elseExpr;
60677
60537
  constructor(branches, elseExpr) {
60678
60538
  super();
60679
- if (branches.length === 0) throw structuredError("SQL.AST_INVALID", "CaseExpr requires at least one branch", { meta: {
60539
+ if (branches.length === 0) throw structuredError("RUNTIME.AST_INVALID", "CaseExpr requires at least one branch", { meta: {
60680
60540
  kind: "case",
60681
60541
  field: "branches"
60682
60542
  } });
@@ -61329,6 +61189,154 @@ var UpdateAst = class UpdateAst extends QueryAst {
61329
61189
  return this;
61330
61190
  }
61331
61191
  };
61192
+ function asNamespaceId(value) {
61193
+ return blindCast(value);
61194
+ }
61195
+ /**
61196
+ * Resolves the effective control policy for a storage-plane node.
61197
+ *
61198
+ * Precedence: node-level value → contract default → `'managed'`.
61199
+ *
61200
+ * Both parameters are optional raw values so this function stays node-type-agnostic
61201
+ * and can be called by any consumer (verifier, planner, etc.) without importing IR classes.
61202
+ */
61203
+ function effectiveControlPolicy(nodeControl, defaultControlPolicy) {
61204
+ return nodeControl ?? defaultControlPolicy ?? "managed";
61205
+ }
61206
+ const CrossReferenceSchema = /* @__PURE__ */ blindCast(/* @__PURE__ */ type({
61207
+ "+": "reject",
61208
+ namespace: "string",
61209
+ model: "string",
61210
+ "space?": "string"
61211
+ }));
61212
+ /**
61213
+ * Runtime predicate for `ColumnDefaultLiteralInputValue`. Authoring layers
61214
+ * resolve template values from caller-supplied args (typed `unknown` at the
61215
+ * boundary) and need to validate before constructing a `ColumnDefault`.
61216
+ * Accepts JSON primitives, plain arrays/objects of JSON values, and `Date`
61217
+ * instances. Rejects functions, class instances (other than `Date`),
61218
+ * `undefined`, `bigint`, `symbol`, and arrays/objects containing those.
61219
+ */
61220
+ function isColumnDefaultLiteralInputValue(value) {
61221
+ if (value === null) return true;
61222
+ const t = typeof value;
61223
+ if (t === "string" || t === "number" || t === "boolean") return true;
61224
+ if (value instanceof Date) return true;
61225
+ if (Array.isArray(value)) return value.every(isColumnDefaultLiteralInputValue);
61226
+ if (t === "object" && Object.getPrototypeOf(value) === Object.prototype) return Object.values(value).every(isColumnDefaultLiteralInputValue);
61227
+ return false;
61228
+ }
61229
+ function isColumnDefault(value) {
61230
+ if (typeof value !== "object" || value === null) return false;
61231
+ const kind = value.kind;
61232
+ if (kind === "literal") return "value" in value;
61233
+ if (kind === "function") return typeof value.expression === "string";
61234
+ return false;
61235
+ }
61236
+ var DdlColumnDefault = class {
61237
+ freeze() {
61238
+ Object.freeze(this);
61239
+ }
61240
+ };
61241
+ var LiteralColumnDefault = class extends DdlColumnDefault {
61242
+ kind = "literal";
61243
+ value;
61244
+ constructor(value) {
61245
+ super();
61246
+ if (!isColumnDefaultLiteralInputValue(value)) throw structuredError("CONTRACT.DEFAULT_INVALID", "Invalid column default literal value");
61247
+ this.value = value;
61248
+ this.freeze();
61249
+ }
61250
+ accept(visitor, ctx) {
61251
+ return visitor.literal(this, ctx);
61252
+ }
61253
+ };
61254
+ var FunctionColumnDefault = class extends DdlColumnDefault {
61255
+ kind = "function";
61256
+ expression;
61257
+ constructor(expression) {
61258
+ super();
61259
+ this.expression = expression;
61260
+ this.freeze();
61261
+ }
61262
+ accept(visitor, ctx) {
61263
+ return visitor.function(this, ctx);
61264
+ }
61265
+ };
61266
+ var DdlColumn = class {
61267
+ name;
61268
+ type;
61269
+ notNull;
61270
+ primaryKey;
61271
+ default;
61272
+ /** Codec identity for this column. When present, the DDL walker resolves the codec via `codecLookup.get(codecRef.codecId)` and runs the literal default through both declared conversions in order — `codec.encode(codec.decodeJson(default.value), {})` — to obtain the wire value it inlines into the DDL string. The read-back is what makes the pair sound: a contract stores a literal default in the codec's canonical JSON, which is not always the application value `encode` takes (`pg/int8@1` stores decimal text for a `bigint`). A `Date` is the one authored value JSON has no notation for, so it arrives as itself and skips `decodeJson`. When absent, literal defaults follow RawSqlLiteral wire-scalar semantics (string / number / boolean / bigint / null / Uint8Array / Date inlined directly). */
61273
+ codecRef;
61274
+ constructor(options) {
61275
+ this.name = options.name;
61276
+ this.type = options.type;
61277
+ this.notNull = options.notNull;
61278
+ this.primaryKey = options.primaryKey;
61279
+ this.default = options.default;
61280
+ this.codecRef = options.codecRef;
61281
+ Object.freeze(this);
61282
+ }
61283
+ };
61284
+ var DdlNode = class {
61285
+ /**
61286
+ * Structural brand: every DDL node answers `true`. Lets {@link isDdlNode}
61287
+ * recognise any `DdlNode` subclass — including target-contributed kinds —
61288
+ * without a central kind registry that subclasses would have to register
61289
+ * into.
61290
+ */
61291
+ isDdlNode() {
61292
+ return true;
61293
+ }
61294
+ freeze() {
61295
+ Object.freeze(this);
61296
+ }
61297
+ collectParamRefs() {
61298
+ return [];
61299
+ }
61300
+ };
61301
+ function isDdlNode(value) {
61302
+ return typeof value === "object" && value !== null && "isDdlNode" in value && typeof value.isDdlNode === "function";
61303
+ }
61304
+ /**
61305
+ * A composite (or single-column) PRIMARY KEY constraint on a `CreateTable`
61306
+ * node. When `name` is set, the adapter renders `CONSTRAINT <name> PRIMARY KEY
61307
+ * (…)`; otherwise it renders an anonymous `PRIMARY KEY (…)`.
61308
+ *
61309
+ * Frozen on construction — immutable after creation.
61310
+ */
61311
+ var PrimaryKeyConstraint = class {
61312
+ kind = "primary-key";
61313
+ columns;
61314
+ name;
61315
+ constructor(options) {
61316
+ this.columns = Object.freeze([...options.columns]);
61317
+ this.name = options.name;
61318
+ Object.freeze(this);
61319
+ }
61320
+ };
61321
+ /**
61322
+ * A table-level CHECK constraint carrying a raw SQL predicate expression. Used
61323
+ * for checks that are not enum value-set restrictions — e.g. the element-non-null
61324
+ * constraint on a scalar-array column (`array_position(col, NULL) IS NULL`).
61325
+ * The `expression` is emitted verbatim, so callers must supply safe,
61326
+ * pre-validated SQL.
61327
+ *
61328
+ * Frozen on construction — immutable after creation.
61329
+ */
61330
+ var CheckExpressionConstraint = class {
61331
+ kind = "check-expression";
61332
+ name;
61333
+ expression;
61334
+ constructor(options) {
61335
+ this.name = options.name;
61336
+ this.expression = options.expression;
61337
+ Object.freeze(this);
61338
+ }
61339
+ };
61332
61340
  /**
61333
61341
  * Walks an AST's parameter references in first-encounter order and dedupes
61334
61342
  * by ParamRef identity. The single canonical helper used by every consumer
@@ -62026,10 +62034,12 @@ const PG_INT_CODEC_ID = "pg/int@1";
62026
62034
  const PG_INT2_CODEC_ID = "pg/int2@1";
62027
62035
  const PG_INT4_CODEC_ID = "pg/int4@1";
62028
62036
  const PG_INT8_CODEC_ID = "pg/int8@1";
62037
+ const PG_INT8_NUMBER_CODEC_ID = "pg/int8number@1";
62029
62038
  const PG_FLOAT_CODEC_ID = "pg/float@1";
62030
62039
  const PG_FLOAT4_CODEC_ID = "pg/float4@1";
62031
62040
  const PG_FLOAT8_CODEC_ID = "pg/float8@1";
62032
62041
  const PG_NUMERIC_CODEC_ID = "pg/numeric@1";
62042
+ const PG_UNBOUNDED_INT_CODEC_ID = "pg/unboundedint@1";
62033
62043
  const PG_BOOL_CODEC_ID = "pg/bool@1";
62034
62044
  const PG_BIT_CODEC_ID = "pg/bit@1";
62035
62045
  const PG_VARBIT_CODEC_ID = "pg/varbit@1";
@@ -62152,16 +62162,19 @@ function buildPostgresCodecDescriptorRegistry(descriptors) {
62152
62162
  for (const descriptor of descriptors) {
62153
62163
  if (!isPostgresCodecDescriptor(descriptor)) {
62154
62164
  const codecId = candidateCodecId(descriptor);
62155
- throw structuredError("POSTGRES.CODEC_DESCRIPTOR_INVALID", `Codec descriptor '${codecId}' is not a valid PostgreSQL codec descriptor.`, {
62165
+ throw structuredError("RUNTIME.CODEC_DESCRIPTOR_INVALID", `Codec descriptor '${codecId}' is not a valid PostgreSQL codec descriptor.`, {
62156
62166
  why: "PostgreSQL codec registries require the postgres-codec discriminant and complete target descriptor methods.",
62157
62167
  fix: "Extend PostgresCodecDescriptor or adapt a generic descriptor with postgresCodec().",
62158
62168
  meta: { codecId }
62159
62169
  });
62160
62170
  }
62161
- if (byId.has(descriptor.codecId)) throw structuredError("POSTGRES.CODEC_DESCRIPTOR_DUPLICATE", `Duplicate PostgreSQL codec descriptor id '${descriptor.codecId}'.`, {
62171
+ if (byId.has(descriptor.codecId)) throw structuredError("RUNTIME.DUPLICATE_CODEC", `Duplicate PostgreSQL codec descriptor id '${descriptor.codecId}'.`, {
62162
62172
  why: "Each codecId must resolve to exactly one PostgreSQL descriptor during registry composition.",
62163
62173
  fix: "Remove the duplicate target, adapter, or extension contribution.",
62164
- meta: { codecId: descriptor.codecId }
62174
+ meta: {
62175
+ codecId: descriptor.codecId,
62176
+ target: "postgres"
62177
+ }
62165
62178
  });
62166
62179
  byId.set(descriptor.codecId, descriptor);
62167
62180
  }
@@ -62461,6 +62474,40 @@ function normalizeSqlBody(sql) {
62461
62474
  }
62462
62475
  /**
62463
62476
  * Returns the first 8 lowercase hex characters of the SHA-256 digest over the
62477
+ * canonical content tuple for a check constraint:
62478
+ *
62479
+ * [normalizeSqlBody(expression)]
62480
+ *
62481
+ * The predicate is the whole of a check's content — the constraint name,
62482
+ * schema, and table are orthogonal to its equivalence. The one-element tuple
62483
+ * keeps the encoding in the same shape as the index and RLS tuples so a member
62484
+ * can be added later without re-reading which encoding a kind uses.
62485
+ *
62486
+ * The tuple order and encoding are a stability commitment: any change
62487
+ * re-suffixes every wire name.
62488
+ */
62489
+ function computeCheckContentHash(expression) {
62490
+ const tuple = JSON.stringify([normalizeSqlBody(expression)]);
62491
+ return createHash("sha256").update(tuple).digest("hex").slice(0, 8);
62492
+ }
62493
+ /** The trailing segment a check's wire-name prefix carries, per kind. */
62494
+ const CHECK_KIND_SUFFIX = {
62495
+ membership: "check",
62496
+ elementNotNull: "elem_not_null"
62497
+ };
62498
+ /**
62499
+ * Composes the wire-name prefix of a derived CHECK constraint:
62500
+ * `${table}_${column}_${kindSuffix}`, capped at the wire-name byte budget.
62501
+ * Shared by contract authoring (naming emitted checks) and `contract infer`
62502
+ * (recomputing the name a derived check would carry), so truncated and
62503
+ * multibyte prefixes match by construction.
62504
+ */
62505
+ function composeCheckWirePrefix(tableName, columnName, kind) {
62506
+ return truncateToWireNamePrefixBytes(`${tableName}_${columnName}_${CHECK_KIND_SUFFIX[kind]}`);
62507
+ }
62508
+ Object.keys(CHECK_KIND_SUFFIX).filter((kind) => kind in CHECK_KIND_SUFFIX);
62509
+ /**
62510
+ * Returns the first 8 lowercase hex characters of the SHA-256 digest over the
62464
62511
  * canonical content tuple for an index:
62465
62512
  *
62466
62513
  * [normalizeSqlBody(expression), normalizeSqlBody(where), columns, unique, type, sortedOptions]
@@ -62501,17 +62548,40 @@ function computeIndexContentHash(parts) {
62501
62548
  ]);
62502
62549
  return createHash("sha256").update(tuple).digest("hex").slice(0, 8);
62503
62550
  }
62551
+ const utf8 = new TextEncoder();
62552
+ /** UTF-8 byte length — the unit Postgres measures identifiers in. */
62553
+ function byteLength(value) {
62554
+ return utf8.encode(value).length;
62555
+ }
62504
62556
  /**
62505
- * Rejects a wire-name prefix over {@link WIRE_NAME_PREFIX_MAX_LENGTH}.
62557
+ * Rejects a wire-name prefix over {@link WIRE_NAME_PREFIX_MAX_BYTES}.
62506
62558
  * `subject` opens the error message (e.g. `defineContract: policy prefix`).
62507
62559
  */
62508
62560
  function assertWireNamePrefixLength(prefix, subject) {
62509
- if (prefix.length > 54) throw structuredError("CONTRACT.WIRE_NAME_PREFIX_TOO_LONG", `${subject} "${prefix}" exceeds the 54-character maximum (Postgres identifiers cap at 63 characters and the wire name appends a 9-character hash suffix).`, { meta: {
62561
+ if (byteLength(prefix) > 54) throw structuredError("CONTRACT.WIRE_NAME_PREFIX_TOO_LONG", `${subject} "${prefix}" exceeds the 54-byte maximum (Postgres identifiers cap at 63 bytes and the wire name appends a 9-byte hash suffix).`, { meta: {
62510
62562
  prefix,
62511
- maxLength: 54
62563
+ maxBytes: 54
62512
62564
  } });
62513
62565
  }
62514
62566
  /**
62567
+ * Shortens a DERIVED wire-name prefix to {@link WIRE_NAME_PREFIX_MAX_BYTES},
62568
+ * cutting on a code-point boundary so a multibyte character is never split.
62569
+ * Only derived prefixes truncate — an authored one throws
62570
+ * ({@link assertWireNamePrefixLength}), because its author can shorten it.
62571
+ */
62572
+ function truncateToWireNamePrefixBytes(prefix) {
62573
+ if (byteLength(prefix) <= 54) return prefix;
62574
+ let out = "";
62575
+ let bytes = 0;
62576
+ for (const character of prefix) {
62577
+ const size = byteLength(character);
62578
+ if (bytes + size > 54) break;
62579
+ out += character;
62580
+ bytes += size;
62581
+ }
62582
+ return out;
62583
+ }
62584
+ /**
62515
62585
  * SQL family IR node base. Carries the family-level `kind` discriminator
62516
62586
  * `'sql'` and inherits the framework's `freezeNode` affordance.
62517
62587
  *
@@ -62556,6 +62626,41 @@ var SqlNode = class extends IRNodeBase {
62556
62626
  }
62557
62627
  };
62558
62628
  /**
62629
+ * SQL Contract IR node for a table-level check constraint, name-identified:
62630
+ * `name` is the full physical name; a present `prefix` marks the constraint as
62631
+ * wire-named (`name` is `formatWireName(prefix, <8hex>)` over the expression's
62632
+ * content hash), an absent `prefix` marks it exact (the name is adopted
62633
+ * verbatim). This is the convention indexes and RLS policies already use — see
62634
+ * ADR 234, "Content-addressed wire names for Postgres-normalized objects".
62635
+ *
62636
+ * The predicate is opaque: one SQL string, never parsed and never rendered
62637
+ * from structured parts. A database reprints predicates in its own normalized
62638
+ * form, so a wire-named check is compared by name — the hash already commits
62639
+ * to the expression the contract declared.
62640
+ */
62641
+ var CheckConstraint = class CheckConstraint extends SqlNode {
62642
+ name;
62643
+ expression;
62644
+ constructor(input) {
62645
+ super();
62646
+ const name = nameOf(input.naming);
62647
+ if (name.length === 0) throw new ContractValidationError("CheckConstraint: every check constraint carries a full physical name.", "storage");
62648
+ this.name = name;
62649
+ if (input.naming.kind === "wire") this.prefix = input.naming.prefix;
62650
+ this.expression = input.expression;
62651
+ freezeNode(this);
62652
+ }
62653
+ /**
62654
+ * Normalizes either shape into an instance: an existing `CheckConstraint`
62655
+ * passes through, canonical input is constructed. Callers that accept
62656
+ * "instance or input" go through this, so the constructor keeps one
62657
+ * canonical shape instead of widening to a union.
62658
+ */
62659
+ static from(value) {
62660
+ return value instanceof CheckConstraint ? value : new CheckConstraint(value);
62661
+ }
62662
+ };
62663
+ /**
62559
62664
  * SQL Contract IR node for a table-level secondary index, name-identified:
62560
62665
  * `name` is the full physical name; a present `prefix` marks the index as
62561
62666
  * wire-named (`name` is `formatWireName(prefix, <8hex>)`), an absent `prefix`
@@ -62573,7 +62678,7 @@ var SqlNode = class extends IRNodeBase {
62573
62678
  * alias one (e.g.
62574
62679
  * `import { Index as SqlIndexNode } from '@internal/sql-contract/types'`).
62575
62680
  */
62576
- var Index = class extends SqlNode {
62681
+ var Index = class Index extends SqlNode {
62577
62682
  name;
62578
62683
  unique;
62579
62684
  constructor(input) {
@@ -62591,31 +62696,8 @@ var Index = class extends SqlNode {
62591
62696
  if (input.options !== void 0) this.options = input.options;
62592
62697
  freezeNode(this);
62593
62698
  }
62594
- };
62595
- /**
62596
- * SQL Contract IR node for a table-level check constraint that restricts
62597
- * a column to the permitted values of a value-set.
62598
- *
62599
- * The constraint is **structured** (names a column and a value-set
62600
- * reference), not a raw SQL expression. Each target renders its own DDL
62601
- * from the structured form, keeping the contract target-agnostic.
62602
- *
62603
- * Construction is idempotent: passing an existing `CheckConstraint`
62604
- * instance as input produces a new instance with identical fields.
62605
- * The constructor does not use `instanceof` for input discrimination —
62606
- * it reads plain named properties, which is sufficient since
62607
- * `CheckConstraintInput` is a structural type.
62608
- */
62609
- var CheckConstraint = class extends SqlNode {
62610
- name;
62611
- column;
62612
- valueSet;
62613
- constructor(input) {
62614
- super();
62615
- this.name = input.name;
62616
- this.column = input.column;
62617
- this.valueSet = input.valueSet;
62618
- freezeNode(this);
62699
+ static from(value) {
62700
+ return value instanceof Index ? value : new Index(value);
62619
62701
  }
62620
62702
  };
62621
62703
  /**
@@ -62634,7 +62716,7 @@ var CheckConstraint = class extends SqlNode {
62634
62716
  * Use `UNBOUND_NAMESPACE_ID` from `@internal/framework-components/ir`
62635
62717
  * as the sentinel `namespaceId` for single-namespace (unbound) references.
62636
62718
  */
62637
- var ForeignKeyReference = class extends SqlNode {
62719
+ var ForeignKeyReference = class ForeignKeyReference extends SqlNode {
62638
62720
  namespaceId;
62639
62721
  tableName;
62640
62722
  columns;
@@ -62646,6 +62728,9 @@ var ForeignKeyReference = class extends SqlNode {
62646
62728
  if (input.spaceId !== void 0) this.spaceId = input.spaceId;
62647
62729
  freezeNode(this);
62648
62730
  }
62731
+ static from(value) {
62732
+ return value instanceof ForeignKeyReference ? value : new ForeignKeyReference(value);
62733
+ }
62649
62734
  };
62650
62735
  /**
62651
62736
  * SQL Contract IR node for a table-level foreign-key declaration — the
@@ -62667,23 +62752,26 @@ var ForeignKeyReference = class extends SqlNode {
62667
62752
  * regardless of whether the input was a JSON literal or an already-constructed
62668
62753
  * class instance.
62669
62754
  */
62670
- var ForeignKey = class extends SqlNode {
62755
+ var ForeignKey = class ForeignKey extends SqlNode {
62671
62756
  source;
62672
62757
  target;
62673
62758
  constructor(input) {
62674
62759
  super();
62675
- this.source = input.source instanceof ForeignKeyReference ? input.source : new ForeignKeyReference(input.source);
62676
- this.target = input.target instanceof ForeignKeyReference ? input.target : new ForeignKeyReference(input.target);
62760
+ this.source = ForeignKeyReference.from(input.source);
62761
+ this.target = ForeignKeyReference.from(input.target);
62677
62762
  if (input.name !== void 0) this.name = input.name;
62678
62763
  if (input.onDelete !== void 0) this.onDelete = input.onDelete;
62679
62764
  if (input.onUpdate !== void 0) this.onUpdate = input.onUpdate;
62680
62765
  freezeNode(this);
62681
62766
  }
62767
+ static from(value) {
62768
+ return value instanceof ForeignKey ? value : new ForeignKey(value);
62769
+ }
62682
62770
  };
62683
62771
  /**
62684
62772
  * SQL Contract IR node for a table's primary-key constraint.
62685
62773
  */
62686
- var PrimaryKey$1 = class extends SqlNode {
62774
+ var PrimaryKey$1 = class PrimaryKey extends SqlNode {
62687
62775
  columns;
62688
62776
  constructor(input) {
62689
62777
  super();
@@ -62691,6 +62779,9 @@ var PrimaryKey$1 = class extends SqlNode {
62691
62779
  if (input.name !== void 0) this.name = input.name;
62692
62780
  freezeNode(this);
62693
62781
  }
62782
+ static from(value) {
62783
+ return value instanceof PrimaryKey ? value : new PrimaryKey(value);
62784
+ }
62694
62785
  };
62695
62786
  /**
62696
62787
  * SQL Contract IR node for a single column entry in `StorageTable.columns`.
@@ -62705,7 +62796,7 @@ var PrimaryKey$1 = class extends SqlNode {
62705
62796
  * in the parent `StorageTable.columns: Record<string, StorageColumn>`
62706
62797
  * map, so a `name` field would be redundant with the key.
62707
62798
  */
62708
- var StorageColumn = class extends SqlNode {
62799
+ var StorageColumn = class StorageColumn extends SqlNode {
62709
62800
  nativeType;
62710
62801
  codecId;
62711
62802
  nullable;
@@ -62715,6 +62806,7 @@ var StorageColumn = class extends SqlNode {
62715
62806
  this.codecId = input.codecId;
62716
62807
  this.nullable = input.nullable;
62717
62808
  if (input.many !== void 0) this.many = input.many;
62809
+ if (input.noCheck !== void 0) this.noCheck = input.noCheck;
62718
62810
  if (input.typeParams !== void 0) this.typeParams = input.typeParams;
62719
62811
  if (input.typeRef !== void 0) this.typeRef = input.typeRef;
62720
62812
  if (input.default !== void 0) this.default = input.default;
@@ -62722,11 +62814,14 @@ var StorageColumn = class extends SqlNode {
62722
62814
  if (input.valueSet !== void 0) this.valueSet = input.valueSet;
62723
62815
  freezeNode(this);
62724
62816
  }
62817
+ static from(value) {
62818
+ return value instanceof StorageColumn ? value : new StorageColumn(value);
62819
+ }
62725
62820
  };
62726
62821
  /**
62727
62822
  * SQL Contract IR node for a table-level unique constraint.
62728
62823
  */
62729
- var UniqueConstraint = class extends SqlNode {
62824
+ var UniqueConstraint = class UniqueConstraint extends SqlNode {
62730
62825
  columns;
62731
62826
  constructor(input) {
62732
62827
  super();
@@ -62734,6 +62829,9 @@ var UniqueConstraint = class extends SqlNode {
62734
62829
  if (input.name !== void 0) this.name = input.name;
62735
62830
  freezeNode(this);
62736
62831
  }
62832
+ static from(value) {
62833
+ return value instanceof UniqueConstraint ? value : new UniqueConstraint(value);
62834
+ }
62737
62835
  };
62738
62836
  /**
62739
62837
  * SQL Contract IR node for a single table entry in a namespace's
@@ -62754,13 +62852,13 @@ var StorageTable = class StorageTable extends SqlNode {
62754
62852
  foreignKeys;
62755
62853
  constructor(input) {
62756
62854
  super();
62757
- this.columns = Object.freeze(Object.fromEntries(Object.entries(input.columns).map(([name, col]) => [name, col instanceof StorageColumn ? col : new StorageColumn(col)])));
62758
- if (input.primaryKey !== void 0) this.primaryKey = input.primaryKey instanceof PrimaryKey$1 ? input.primaryKey : new PrimaryKey$1(input.primaryKey);
62759
- this.uniques = Object.freeze(input.uniques.map((u) => u instanceof UniqueConstraint ? u : new UniqueConstraint(u)));
62760
- this.indexes = Object.freeze(input.indexes.map((i) => i instanceof Index ? i : new Index(i)));
62761
- this.foreignKeys = Object.freeze(input.foreignKeys.map((fk) => fk instanceof ForeignKey ? fk : new ForeignKey(fk)));
62855
+ this.columns = Object.freeze(Object.fromEntries(Object.entries(input.columns).map(([name, col]) => [name, StorageColumn.from(col)])));
62856
+ if (input.primaryKey !== void 0) this.primaryKey = PrimaryKey$1.from(input.primaryKey);
62857
+ this.uniques = Object.freeze(input.uniques.map(UniqueConstraint.from));
62858
+ this.indexes = Object.freeze(input.indexes.map(Index.from));
62859
+ this.foreignKeys = Object.freeze(input.foreignKeys.map(ForeignKey.from));
62762
62860
  if (input.control !== void 0) this.control = input.control;
62763
- if (input.checks !== void 0 && input.checks.length > 0) this.checks = Object.freeze(input.checks.map((cc) => new CheckConstraint(cc)));
62861
+ if (input.checks !== void 0 && input.checks.length > 0) this.checks = Object.freeze(input.checks.map(CheckConstraint.from));
62764
62862
  freezeNode(this);
62765
62863
  }
62766
62864
  /**
@@ -62806,6 +62904,16 @@ var StorageValueSet = class extends SqlNode {
62806
62904
  }
62807
62905
  };
62808
62906
  /**
62907
+ * Hydrates one stored check constraint into constructor input. `parseNaming`
62908
+ * is what rejects a hand-edited file whose `prefix` and `name` disagree.
62909
+ */
62910
+ function checkConstraintInputFromSerialized(flat) {
62911
+ return {
62912
+ naming: parseNaming(flat.name, flat.prefix),
62913
+ expression: flat.expression
62914
+ };
62915
+ }
62916
+ /**
62809
62917
  * Hydrates one stored index into constructor input. The parameter is typed
62810
62918
  * but the values are whatever the file held, so each field the union depends
62811
62919
  * on is checked here rather than downstream — by the time `Index` sees the
@@ -62978,22 +63086,119 @@ const pgNumericDecode = (wire) => {
62978
63086
  return wire;
62979
63087
  };
62980
63088
  const DECIMAL_INTEGER = /^-?\d+$/;
62981
- /** Reads an `int8` wire or JSON value as a `bigint`, rejecting anything `BigInt()` would misread. */
62982
- const pgInt8Decode = (wire) => {
63089
+ /**
63090
+ * Requires an application value to be of the JS type the codec reads.
63091
+ *
63092
+ * A range check reads a value of the wrong type as a value out of range, and
63093
+ * reports a number plainly inside the range as outside it — so the type is
63094
+ * established first and answered for on its own terms, naming what a caller
63095
+ * has to change.
63096
+ */
63097
+ const requireJsType = (codecId, expected, value) => {
63098
+ if (typeof value === expected) return;
63099
+ throw postgresError("RUNTIME.ENCODE_FAILED", `${codecId} value must be a ${expected}, got ${typeof value} ${String(value)}`, { meta: {
63100
+ codecId,
63101
+ received: typeof value
63102
+ } });
63103
+ };
63104
+ /** Writes a `bigint` application value as the decimal text the wire form of the exact integer codecs carries. */
63105
+ const pgBigintEncode = (codecId, value) => {
63106
+ requireJsType(codecId, "bigint", value);
63107
+ return value.toString();
63108
+ };
63109
+ /**
63110
+ * Writes an application value as the decimal text these codecs carry as their
63111
+ * canonical JSON.
63112
+ *
63113
+ * A schema-written literal default (`BigInt @default(0)`) arrives here as a
63114
+ * `number`, since a number literal is the only integer a schema language
63115
+ * writes, and one that is a safe integer names its value exactly. Past that
63116
+ * range the literal was rounded before any of this ran, so the value written is
63117
+ * not the value meant — which this refuses rather than minting an exact-looking
63118
+ * total from it. A non-integral number is refused on the same terms.
63119
+ */
63120
+ const pgBigintEncodeJson = (codecId, value) => {
63121
+ if (typeof value !== "number") return pgBigintEncode(codecId, value);
63122
+ if (!Number.isSafeInteger(value)) throw postgresError("RUNTIME.ENCODE_FAILED", `${codecId} number literal must be an integer within the safe integer range, got ${String(value)}`, { meta: {
63123
+ codecId,
63124
+ received: String(value)
63125
+ } });
63126
+ return BigInt(value).toString();
63127
+ };
63128
+ /**
63129
+ * Reads a wire or JSON value as a `bigint`, rejecting anything `BigInt()` would
63130
+ * misread. A number-typed wire value must also be a safe integer: past
63131
+ * ±(2^53 − 1) the driver's `number` has already rounded, so stringifying it
63132
+ * would mint a spuriously-exact `bigint` that need not equal the stored value.
63133
+ */
63134
+ const decimalIntegerDecode = (codecId, wire) => {
62983
63135
  if (typeof wire === "bigint") return wire;
62984
63136
  const text = String(wire);
62985
- if (!DECIMAL_INTEGER.test(text)) throw postgresError("RUNTIME.DECODE_FAILED", "pg/int8@1 value must be a decimal integer", { meta: {
62986
- codecId: "pg/int8@1",
63137
+ if (!DECIMAL_INTEGER.test(text)) throw postgresError("RUNTIME.DECODE_FAILED", `${codecId} value must be a decimal integer`, { meta: {
63138
+ codecId,
63139
+ received: text
63140
+ } });
63141
+ if (typeof wire === "number" && !Number.isSafeInteger(wire)) throw postgresError("RUNTIME.DECODE_FAILED", `${codecId} wire number must be an integer within the safe integer range, got ${text}`, { meta: {
63142
+ codecId,
62987
63143
  received: text
62988
63144
  } });
62989
63145
  return BigInt(text);
62990
63146
  };
63147
+ /** Reads an `int8` wire or JSON value as a `bigint`, rejecting anything `BigInt()` would misread. */
63148
+ const pgInt8Decode = (wire) => decimalIntegerDecode("pg/int8@1", wire);
62991
63149
  /**
62992
- * Renders an `int8` default as a `bigint` literal. The canonical JSON is decimal
62993
- * text but the application type is `bigint`, so a plain string literal would not
63150
+ * Reads an unconstrained-`numeric` wire or JSON value as a `bigint`, rejecting
63151
+ * non-integral values including `NaN` and the infinities, which are `numeric`
63152
+ * values but not integers.
63153
+ */
63154
+ const pgUnboundedIntDecode = (wire) => decimalIntegerDecode("pg/unboundedint@1", wire);
63155
+ const MIN_SAFE_INTEGER_BIGINT = BigInt(Number.MIN_SAFE_INTEGER);
63156
+ const MAX_SAFE_INTEGER_BIGINT = BigInt(Number.MAX_SAFE_INTEGER);
63157
+ /**
63158
+ * Requires an integer within ±(2^53 − 1), the range a JS `number` holds
63159
+ * exactly. The guard throws rather than rounding: past the boundary a `number`
63160
+ * silently loses digits, which is the failure mode this codec exists to refuse.
63161
+ */
63162
+ const pgInt8NumberGuard = (code, value) => {
63163
+ if (!Number.isSafeInteger(value)) throw postgresError(code, `pg/int8number@1 value must be an integer within the safe integer range, got ${String(value)}`, { meta: {
63164
+ codecId: "pg/int8number@1",
63165
+ received: String(value)
63166
+ } });
63167
+ return value;
63168
+ };
63169
+ const pgInt8NumberEncodeJson = (value) => {
63170
+ requireJsType("pg/int8number@1", "number", value);
63171
+ return pgInt8NumberGuard("RUNTIME.ENCODE_FAILED", value);
63172
+ };
63173
+ const pgInt8NumberEncode = (value) => String(pgInt8NumberEncodeJson(value));
63174
+ /**
63175
+ * Reads an `int8` wire value as a `number`, throwing outside ±(2^53 − 1) and on
63176
+ * non-integral input. Decimal text goes through `BigInt` before the range check
63177
+ * so an out-of-range value is compared exactly rather than after rounding.
63178
+ */
63179
+ const pgInt8NumberDecode = (wire) => {
63180
+ if (typeof wire === "number") return pgInt8NumberGuard("RUNTIME.DECODE_FAILED", wire);
63181
+ const value = decimalIntegerDecode("pg/int8number@1", wire);
63182
+ if (value < MIN_SAFE_INTEGER_BIGINT || value > MAX_SAFE_INTEGER_BIGINT) throw postgresError("RUNTIME.DECODE_FAILED", `pg/int8number@1 value must be an integer within the safe integer range, got ${value}`, { meta: {
63183
+ codecId: "pg/int8number@1",
63184
+ received: value.toString()
63185
+ } });
63186
+ return Number(value);
63187
+ };
63188
+ const pgInt8NumberDecodeJson = (json) => {
63189
+ if (typeof json !== "number") throw postgresError("RUNTIME.DECODE_FAILED", "pg/int8number@1 database JSON value must be a number", { meta: {
63190
+ codecId: "pg/int8number@1",
63191
+ received: typeof json
63192
+ } });
63193
+ return pgInt8NumberGuard("RUNTIME.DECODE_FAILED", json);
63194
+ };
63195
+ /**
63196
+ * Renders a decimal-text default as a `bigint` literal, for the codecs whose
63197
+ * canonical JSON is decimal text while the application type is `bigint`
63198
+ * (`pg/int8@1`, `pg/unboundedint@1`) — a plain string literal would not
62994
63199
  * typecheck against the emitted column type.
62995
63200
  */
62996
- const pgInt8RenderValueLiteral = (value) => typeof value === "string" && DECIMAL_INTEGER.test(value) ? `${value}n` : void 0;
63201
+ const decimalTextBigintLiteral = (value) => typeof value === "string" && DECIMAL_INTEGER.test(value) ? `${value}n` : void 0;
62997
63202
  const pgNumericRenderOutputType = (typeParams) => {
62998
63203
  const precision = typeParams.precision;
62999
63204
  if (precision === void 0) return void 0;
@@ -63653,13 +63858,13 @@ const pgInt2Descriptor = new PgInt2Descriptor();
63653
63858
  */
63654
63859
  var PgInt8Codec = class extends CodecImpl {
63655
63860
  async encode(value, _ctx) {
63656
- return value.toString();
63861
+ return pgBigintEncode(PG_INT8_CODEC_ID, value);
63657
63862
  }
63658
63863
  async decode(wire, _ctx) {
63659
63864
  return pgInt8Decode(wire);
63660
63865
  }
63661
63866
  encodeJson(value) {
63662
- return value.toString();
63867
+ return pgBigintEncodeJson(PG_INT8_CODEC_ID, value);
63663
63868
  }
63664
63869
  decodeJson(json) {
63665
63870
  if (typeof json !== "string") throw postgresError("RUNTIME.DECODE_FAILED", "pg/int8@1 database JSON value must be a decimal string", { meta: {
@@ -63685,13 +63890,59 @@ var PgInt8Descriptor = class extends PostgresCodecDescriptor {
63685
63890
  targetTypes = ["int8"];
63686
63891
  paramsSchema = voidParamsSchema;
63687
63892
  renderValueLiteral(value) {
63688
- return pgInt8RenderValueLiteral(value);
63893
+ return decimalTextBigintLiteral(value);
63689
63894
  }
63690
63895
  factory() {
63691
63896
  return () => new PgInt8Codec(this);
63692
63897
  }
63693
63898
  };
63694
63899
  const pgInt8Descriptor = new PgInt8Descriptor();
63900
+ /**
63901
+ * A Postgres `int8` decoded as a JS `number`, for columns whose values stay
63902
+ * within the safe integer range ±(2^53 − 1). Both directions guard rather than
63903
+ * round: decode (wire and JSON) and encode throw a structured error on
63904
+ * out-of-range or non-integral input. The canonical JSON is a JSON number —
63905
+ * the deliberate exception to the decimal-text rule for 64-bit integers, and
63906
+ * the codec's purpose. The descriptor claims no target type, so `int8` in type
63907
+ * position stays `pg/int8@1`.
63908
+ */
63909
+ var PgInt8NumberCodec = class extends CodecImpl {
63910
+ async encode(value, _ctx) {
63911
+ return pgInt8NumberEncode(value);
63912
+ }
63913
+ async decode(wire, _ctx) {
63914
+ return pgInt8NumberDecode(wire);
63915
+ }
63916
+ encodeJson(value) {
63917
+ return pgInt8NumberEncodeJson(value);
63918
+ }
63919
+ decodeJson(json) {
63920
+ return pgInt8NumberDecodeJson(json);
63921
+ }
63922
+ };
63923
+ var PgInt8NumberDescriptor = class extends PostgresCodecDescriptor {
63924
+ nativeType() {
63925
+ return PG_INT8_NATIVE_TYPE;
63926
+ }
63927
+ jsonProjection(expression) {
63928
+ return expression;
63929
+ }
63930
+ codecId = PG_INT8_NUMBER_CODEC_ID;
63931
+ traits = [
63932
+ "equality",
63933
+ "order",
63934
+ "numeric"
63935
+ ];
63936
+ targetTypes = [];
63937
+ paramsSchema = voidParamsSchema;
63938
+ renderValueLiteral(value) {
63939
+ return renderTsLiteral(value);
63940
+ }
63941
+ factory() {
63942
+ return () => new PgInt8NumberCodec(this);
63943
+ }
63944
+ };
63945
+ const pgInt8NumberDescriptor = new PgInt8NumberDescriptor();
63695
63946
  var PgFloat4Codec = class extends CodecImpl {
63696
63947
  async encode(value, _ctx) {
63697
63948
  return value;
@@ -63845,6 +64096,53 @@ var PgNumericDescriptor = class extends PostgresCodecDescriptor {
63845
64096
  };
63846
64097
  const pgNumericDescriptor = new PgNumericDescriptor();
63847
64098
  /**
64099
+ * A genuinely unbounded integer over unconstrained Postgres `numeric` storage.
64100
+ * Application values are `bigint` and the canonical JSON is decimal text, like
64101
+ * `pg/int8@1`; decode rejects non-integral values. The descriptor claims no
64102
+ * target type, so `numeric` and `decimal` in type position stay `pg/numeric@1`.
64103
+ */
64104
+ var PgUnboundedIntCodec = class extends CodecImpl {
64105
+ async encode(value, _ctx) {
64106
+ return pgBigintEncode(PG_UNBOUNDED_INT_CODEC_ID, value);
64107
+ }
64108
+ async decode(wire, _ctx) {
64109
+ return pgUnboundedIntDecode(wire);
64110
+ }
64111
+ encodeJson(value) {
64112
+ return pgBigintEncodeJson(PG_UNBOUNDED_INT_CODEC_ID, value);
64113
+ }
64114
+ decodeJson(json) {
64115
+ if (typeof json !== "string") throw postgresError("RUNTIME.DECODE_FAILED", "pg/unboundedint@1 database JSON value must be a decimal string", { meta: {
64116
+ codecId: PG_UNBOUNDED_INT_CODEC_ID,
64117
+ received: typeof json
64118
+ } });
64119
+ return pgUnboundedIntDecode(json);
64120
+ }
64121
+ };
64122
+ var PgUnboundedIntDescriptor = class extends PostgresCodecDescriptor {
64123
+ nativeType() {
64124
+ return PG_NUMERIC_NATIVE_TYPE;
64125
+ }
64126
+ jsonProjection(expression) {
64127
+ return decimalTextJsonProjection(expression);
64128
+ }
64129
+ codecId = PG_UNBOUNDED_INT_CODEC_ID;
64130
+ traits = [
64131
+ "equality",
64132
+ "order",
64133
+ "numeric"
64134
+ ];
64135
+ targetTypes = [];
64136
+ paramsSchema = voidParamsSchema;
64137
+ renderValueLiteral(value) {
64138
+ return decimalTextBigintLiteral(value);
64139
+ }
64140
+ factory() {
64141
+ return () => new PgUnboundedIntCodec(this);
64142
+ }
64143
+ };
64144
+ const pgUnboundedIntDescriptor = new PgUnboundedIntDescriptor();
64145
+ /**
63848
64146
  * A Postgres `date` has no time-of-day or timezone component. This codec
63849
64147
  * canonicalizes its JS-level value as a `Date` at UTC midnight, so its
63850
64148
  * round-trip is independent of the process's local timezone — see
@@ -64381,9 +64679,11 @@ const codecDescriptors = definePostgresCodecs([
64381
64679
  pgInt4Descriptor,
64382
64680
  pgInt2Descriptor,
64383
64681
  pgInt8Descriptor,
64682
+ pgInt8NumberDescriptor,
64384
64683
  pgFloat4Descriptor,
64385
64684
  pgFloat8Descriptor,
64386
64685
  pgNumericDescriptor,
64686
+ pgUnboundedIntDescriptor,
64387
64687
  pgDateDescriptor,
64388
64688
  pgTimestampDescriptor,
64389
64689
  pgTimestamptzDescriptor,
@@ -64577,14 +64877,6 @@ const ColumnDefaultFunctionSchema = type.declare().type({
64577
64877
  kind: functionKindSchema,
64578
64878
  expression: "string"
64579
64879
  });
64580
- const ColumnDefaultSchema = ColumnDefaultLiteralSchema.or(ColumnDefaultFunctionSchema);
64581
- const StorageValueSetRefSchema = type({
64582
- plane: "'storage'",
64583
- namespaceId: "string",
64584
- entityKind: "'valueSet'",
64585
- entityName: "string",
64586
- "spaceId?": "string"
64587
- });
64588
64880
  const StorageColumnSchema = type({
64589
64881
  "+": "reject",
64590
64882
  nativeType: "string",
@@ -64593,11 +64885,26 @@ const StorageColumnSchema = type({
64593
64885
  "many?": "boolean",
64594
64886
  "typeParams?": "Record<string, unknown>",
64595
64887
  "typeRef?": "string",
64596
- "default?": ColumnDefaultSchema,
64888
+ "default?": ColumnDefaultLiteralSchema.or(ColumnDefaultFunctionSchema),
64597
64889
  "control?": ControlPolicySchema$1,
64598
- "valueSet?": StorageValueSetRefSchema
64890
+ "valueSet?": type({
64891
+ plane: "'storage'",
64892
+ namespaceId: "string",
64893
+ entityKind: "'valueSet'",
64894
+ entityName: "string",
64895
+ "spaceId?": "string"
64896
+ }),
64897
+ "noCheck?": "(\"membership\" | \"elementNotNull\")[]"
64599
64898
  }).narrow((col, ctx) => {
64600
64899
  if (col.typeParams !== void 0 && col.typeRef !== void 0) return ctx.mustBe("a column with either typeParams or typeRef, not both");
64900
+ if (col.noCheck !== void 0) {
64901
+ if (col.noCheck.length === 0) return ctx.mustBe("a column whose noCheck array is non-empty (omit the key when enforced)");
64902
+ for (let i = 1; i < col.noCheck.length; i += 1) {
64903
+ const previous = col.noCheck[i - 1];
64904
+ const current = col.noCheck[i];
64905
+ if (previous !== void 0 && current !== void 0 && previous >= current) return ctx.mustBe("a column whose noCheck kinds are unique and sorted ascending lexicographically");
64906
+ }
64907
+ }
64601
64908
  return true;
64602
64909
  });
64603
64910
  /**
@@ -64651,8 +64958,8 @@ const ForeignKeySchema = type.declare().type({
64651
64958
  const CheckConstraintSchema = type({
64652
64959
  "+": "reject",
64653
64960
  name: "string",
64654
- column: "string",
64655
- valueSet: StorageValueSetRefSchema
64961
+ "prefix?": "string",
64962
+ expression: "string"
64656
64963
  });
64657
64964
  const tableEntityKind = {
64658
64965
  kind: "table",
@@ -64668,7 +64975,8 @@ const tableEntityKind = {
64668
64975
  }),
64669
64976
  construct: (input) => new StorageTable({
64670
64977
  ...input,
64671
- indexes: input.indexes.map((i) => i instanceof Index ? i : indexInputFromSerialized(i))
64978
+ indexes: input.indexes.map((i) => i instanceof Index ? i : indexInputFromSerialized(i)),
64979
+ ...ifDefined("checks", input.checks?.map((c) => c instanceof CheckConstraint ? c : checkConstraintInputFromSerialized(c)))
64672
64980
  })
64673
64981
  };
64674
64982
  const valueSetEntityKind = {
@@ -66682,6 +66990,7 @@ function isAggregateDescriptor(value) {
66682
66990
  if (!isObjectLike(value)) return false;
66683
66991
  if (!("operation" in value) || !isNonEmptyString(value.operation)) return false;
66684
66992
  if (!("nullable" in value) || typeof value.nullable !== "boolean") return false;
66993
+ if (value.nullable === false && (!("emptyResultJson" in value) || value.emptyResultJson === void 0)) return false;
66685
66994
  if (!("input" in value) || !isAggregateInputMatch(value.input)) return false;
66686
66995
  if (!("output" in value) || !isAggregateOutputCodec(value.output)) return false;
66687
66996
  return value.input.kind === "codec" || value.input.kind === "trait" || value.output.kind === "codec";
@@ -66930,7 +67239,7 @@ function collectAggregateDescriptors(descriptors) {
66930
67239
  for (const descriptor of descriptors) {
66931
67240
  const descriptorId = descriptor.id ?? "<unknown>";
66932
67241
  for (const contributed of descriptor.types?.aggregateDescriptors ?? []) {
66933
- if (!isAggregateDescriptor(contributed)) throw runtimeError("CONTRACT.AGGREGATE_DESCRIPTOR_INVALID", `Malformed aggregate descriptor contributed by "${descriptorId}". A descriptor declares a non-empty \`operation\`, an \`input\` match of kind \`none\`/\`any\`/\`codec\`/\`trait\`, an \`output\` of kind \`self\`/\`codec\`, and a boolean \`nullable\`; a \`self\` output needs an input to reuse.`, {
67242
+ if (!isAggregateDescriptor(contributed)) throw runtimeError("CONTRACT.AGGREGATE_DESCRIPTOR_INVALID", `Malformed aggregate descriptor contributed by "${descriptorId}". A descriptor declares a non-empty \`operation\`, an \`input\` match of kind \`none\`/\`any\`/\`codec\`/\`trait\`, an \`output\` of kind \`self\`/\`codec\`, and a boolean \`nullable\` — plus \`emptyResultJson\`, in the result codec's canonical JSON, where \`nullable\` is false; a \`self\` output needs an input to reuse.`, {
66934
67243
  contributedBy: descriptorId,
66935
67244
  descriptor: contributed
66936
67245
  });
@@ -67737,6 +68046,9 @@ var PrimaryKey = class PrimaryKey extends SqlSchemaIRNode {
67737
68046
  children() {
67738
68047
  return [];
67739
68048
  }
68049
+ static from(value) {
68050
+ return value instanceof PrimaryKey ? value : new PrimaryKey(value);
68051
+ }
67740
68052
  static is(node) {
67741
68053
  return node.nodeKind === RelationalSchemaNodeKind.primaryKey;
67742
68054
  }
@@ -67747,27 +68059,28 @@ var PrimaryKey = class PrimaryKey extends SqlSchemaIRNode {
67747
68059
  }
67748
68060
  };
67749
68061
  /**
67750
- * Schema IR node for a table-level check constraint that restricts a
67751
- * column to a set of permitted values (an enum-style `IN (...)` check).
67752
- *
67753
- * Carries the **resolved values** rather than a raw SQL predicate so
67754
- * callers can compare value-sets without parsing SQL.
68062
+ * Schema IR node for a table-level check constraint, carried as an opaque
68063
+ * predicate. The expression is never parsed a database reprints predicates
68064
+ * in its own normalized form, so any structured reading of it would drift.
67755
68065
  *
67756
- * Implements `DiffableNode` so a check constraint is directly a table's
67757
- * diff-tree child: `id` is the constraint name. `isEqualTo` compares
67758
- * `column` and the permitted-value set (order-insensitive — the database
67759
- * does not guarantee `IN (...)` ordering).
68066
+ * Implements `DiffableNode` so a check is directly a table's diff-tree child;
68067
+ * `id` is `check:<name>`. `isEqualTo` is mode-selected by the receiver's
68068
+ * `prefix` (the differ always calls `expected.isEqualTo(actual)`): a
68069
+ * wire-named receiver compares ids only — the wire name's hash already
68070
+ * commits to the predicate — while an exact-named receiver byte-compares the
68071
+ * expression, which is reliable precisely when both sides came from the same
68072
+ * reprint.
67760
68073
  */
67761
68074
  var SqlCheckConstraintIR = class SqlCheckConstraintIR extends SqlSchemaIRNode {
67762
68075
  nodeKind = RelationalSchemaNodeKind.check;
67763
68076
  name;
67764
- column;
67765
- permittedValues;
68077
+ expression;
67766
68078
  constructor(input) {
67767
68079
  super();
67768
- this.name = input.name;
67769
- this.column = input.column;
67770
- this.permittedValues = Object.freeze([...input.permittedValues]);
68080
+ this.name = nameOf(input.naming);
68081
+ if (input.naming.kind === "wire") this.prefix = input.naming.prefix;
68082
+ this.expression = input.expression;
68083
+ defineNonEnumerable(this, "dependsOn", input.dependsOn);
67771
68084
  freezeNode(this);
67772
68085
  }
67773
68086
  get id() {
@@ -67776,23 +68089,17 @@ var SqlCheckConstraintIR = class SqlCheckConstraintIR extends SqlSchemaIRNode {
67776
68089
  children() {
67777
68090
  return [];
67778
68091
  }
68092
+ static from(value) {
68093
+ return value instanceof SqlCheckConstraintIR ? value : new SqlCheckConstraintIR(value);
68094
+ }
67779
68095
  static is(node) {
67780
68096
  return node.nodeKind === RelationalSchemaNodeKind.check;
67781
68097
  }
67782
- /**
67783
- * Compares the permitted-value sets only (unordered), matching the
67784
- * relational walk's `verifyCheckConstraints`: two checks pairing by name
67785
- * compare their value sets — the `column` field is descriptive, not part
67786
- * of the comparison, so a name-paired check with equal values verifies
67787
- * regardless of which column carries it.
67788
- */
67789
68098
  isEqualTo(other) {
67790
68099
  const node = blindCast(other);
67791
68100
  assertNode(node, "SqlCheckConstraintIR", SqlCheckConstraintIR.is);
67792
- const thisValues = new Set(this.permittedValues);
67793
- const otherValues = new Set(node.permittedValues);
67794
- if (thisValues.size !== otherValues.size) return false;
67795
- return [...thisValues].every((v) => otherValues.has(v));
68101
+ if (this.prefix !== void 0) return this.id === node.id;
68102
+ return this.expression === node.expression;
67796
68103
  }
67797
68104
  };
67798
68105
  /**
@@ -68081,6 +68388,9 @@ var SqlIndexIR = class SqlIndexIR extends SqlSchemaIRNode {
68081
68388
  children() {
68082
68389
  return [];
68083
68390
  }
68391
+ static from(value) {
68392
+ return value instanceof SqlIndexIR ? value : new SqlIndexIR(value);
68393
+ }
68084
68394
  static is(node) {
68085
68395
  return node.nodeKind === RelationalSchemaNodeKind.index;
68086
68396
  }
@@ -68229,10 +68539,10 @@ var SqlTableIR = class extends SqlSchemaIRNode {
68229
68539
  this.columns = Object.freeze(Object.fromEntries(Object.entries(input.columns).map(([key, col]) => [key, col instanceof SqlColumnIR ? col : new SqlColumnIR(col)])));
68230
68540
  this.foreignKeys = Object.freeze(input.foreignKeys.map((fk) => fk instanceof SqlForeignKeyIR ? fk : new SqlForeignKeyIR(fk)));
68231
68541
  this.uniques = Object.freeze(input.uniques.map((u) => u instanceof SqlUniqueIR ? u : new SqlUniqueIR(u)));
68232
- this.indexes = Object.freeze(input.indexes.map((i) => i instanceof SqlIndexIR ? i : new SqlIndexIR(i)));
68233
- if (input.primaryKey !== void 0) this.primaryKey = input.primaryKey instanceof PrimaryKey ? input.primaryKey : new PrimaryKey(input.primaryKey);
68542
+ this.indexes = Object.freeze(input.indexes.map(SqlIndexIR.from));
68543
+ if (input.primaryKey !== void 0) this.primaryKey = PrimaryKey.from(input.primaryKey);
68234
68544
  if (input.annotations !== void 0) this.annotations = input.annotations;
68235
- if (input.checks !== void 0 && input.checks.length > 0) this.checks = Object.freeze(input.checks.map((c) => c instanceof SqlCheckConstraintIR ? c : new SqlCheckConstraintIR(c)));
68545
+ if (input.checks !== void 0 && input.checks.length > 0) this.checks = Object.freeze(input.checks.map(SqlCheckConstraintIR.from));
68236
68546
  freezeNode(this);
68237
68547
  }
68238
68548
  get id() {
@@ -68693,15 +69003,16 @@ var PostgresRoleSchemaNode = class PostgresRoleSchemaNode extends SqlSchemaIRNod
68693
69003
  * - `'decode'` — abort fired during `decodeRow` / `decodeField`.
68694
69004
  * - `'stream'` — abort fired between rows or before any codec call
68695
69005
  * (already-aborted at entry).
68696
- * - `'beforeExecute'` / `'afterExecute'` / `'onRow'` — abort fired
68697
- * on entry to or during the corresponding middleware phase
69006
+ * - `'beforeQuery'` / `'beforeExecute'` / `'afterQuery'` /
69007
+ * `'afterExecute'` / `'onRow'` — abort fired on entry to or during
69008
+ * the corresponding middleware phase
68698
69009
  * (cooperative cancellation per the param-transform seam).
68699
69010
  */
68700
69011
  const RUNTIME_ABORTED = "RUNTIME.ABORTED";
68701
69012
  /**
68702
69013
  * Construct a `RUNTIME.ABORTED` envelope. Phase distinguishes where the
68703
69014
  * abort was observed — codec call sites (`encode` / `decode` / `stream`)
68704
- * or middleware seams (`beforeExecute` / `afterExecute` / `onRow`), as
69015
+ * or operation-specific middleware seams, as
68705
69016
  * enumerated on {@link RuntimeAbortedPhase}. Cause carries
68706
69017
  * `signal.reason` verbatim from the platform — native abort produces a
68707
69018
  * `DOMException`, explicit `controller.abort(reason)` produces whatever
@@ -68866,8 +69177,8 @@ function renderLoweredSql(ast, contract, codecDescriptorRegistry) {
68866
69177
  case "delete":
68867
69178
  sql = renderDelete(node, contract, pim);
68868
69179
  break;
68869
- case "raw-sql":
68870
- sql = renderRawSql(node, contract, pim);
69180
+ case "raw-query":
69181
+ sql = renderParts(node.parts, contract, pim);
68871
69182
  break;
68872
69183
  // v8 ignore next 4
68873
69184
  default: assertNever(node, `Unsupported AST node kind: ${unreachableKind(node)}`);
@@ -68918,7 +69229,7 @@ function collectTableSources(ast) {
68918
69229
  /**
68919
69230
  * Ordered, codec-encoded values of the value-set a storage column restricts to, or `undefined` when the referenced column carries no value-set (the common, non-enum case). Resolves the column's storage coordinate from the SELECT's table sources, then the column's `valueSet` ref to the value-set's `values`.
68920
69231
  */
68921
- function allStrings$1(values) {
69232
+ function allStrings(values) {
68922
69233
  return values.every((value) => typeof value === "string");
68923
69234
  }
68924
69235
  function resolveEnumOrderValues(ref, sourcesByRef, contract) {
@@ -68956,11 +69267,11 @@ function resolveEnumOrderValuesForIdentifier(name, sourcesByRef, contract) {
68956
69267
  function renderOrderByExpr(expr, sourcesByRef, contract, pim) {
68957
69268
  if (expr.kind === "column-ref") {
68958
69269
  const orderValues = resolveEnumOrderValues(expr, sourcesByRef, contract);
68959
- if (orderValues !== void 0 && allStrings$1(orderValues)) return `array_position(ARRAY[${orderValues.map((value) => `'${escapeLiteral(value)}'`).join(", ")}]::text[], ${renderColumn(expr)})`;
69270
+ if (orderValues !== void 0 && allStrings(orderValues)) return `array_position(ARRAY[${orderValues.map((value) => `'${escapeLiteral(value)}'`).join(", ")}]::text[], ${renderColumn(expr)})`;
68960
69271
  }
68961
69272
  if (expr.kind === "identifier-ref") {
68962
69273
  const orderValues = resolveEnumOrderValuesForIdentifier(expr.name, sourcesByRef, contract);
68963
- if (orderValues !== void 0 && allStrings$1(orderValues)) return `array_position(ARRAY[${orderValues.map((value) => `'${escapeLiteral(value)}'`).join(", ")}]::text[], ${quoteIdentifier(expr.name)})`;
69274
+ if (orderValues !== void 0 && allStrings(orderValues)) return `array_position(ARRAY[${orderValues.map((value) => `'${escapeLiteral(value)}'`).join(", ")}]::text[], ${quoteIdentifier(expr.name)})`;
68964
69275
  }
68965
69276
  return renderExpr(expr, contract, pim);
68966
69277
  }
@@ -69332,19 +69643,11 @@ function renderUpdate(ast, contract, pim) {
69332
69643
  function renderDelete(ast, contract, pim) {
69333
69644
  return `DELETE FROM ${qualifyTableFromNamespaceCoordinate(ast.table, contract)}${ast.where ? ` WHERE ${renderWhere(ast.where, contract, pim)}` : ""}${ast.returning?.length ? ` RETURNING ${renderReturning(ast.returning, contract, pim)}` : ""}`;
69334
69645
  }
69335
- function renderRawSql(ast, contract, pim) {
69336
- const out = [];
69337
- for (let i = 0; i < ast.fragments.length; i++) {
69338
- out.push(ast.fragments[i] ?? "");
69339
- if (i < ast.args.length) {
69340
- const arg = ast.args[i];
69341
- if (arg !== void 0) out.push(renderExpr(arg, contract, pim));
69342
- }
69343
- }
69344
- return out.join("");
69646
+ function renderParts(parts, contract, pim) {
69647
+ return parts.map((part) => typeof part === "string" ? part : renderExpr(part, contract, pim)).join("");
69345
69648
  }
69346
69649
  function renderRawExpr(node, contract, pim) {
69347
- return node.parts.map((part) => typeof part === "string" ? part : renderExpr(part, contract, pim)).join("");
69650
+ return renderParts(node.parts, contract, pim);
69348
69651
  }
69349
69652
  /**
69350
69653
  * Maps each `ReferentialAction` value to the SQL keyword used in ON DELETE /
@@ -69364,8 +69667,15 @@ const REFERENTIAL_ACTION_SQL = {
69364
69667
  function errorMarkerRowCorrupt(options) {
69365
69668
  return new CliStructuredError("CONTRACT.MARKER_ROW_CORRUPT", "Marker row is corrupt or incompatible", {
69366
69669
  why: options.why,
69367
- fix: `The ${options.markerLocation} row for space "${options.space}" contains invalid data. Delete the row, then run \`prisma-next db sign --db <url>\` to write a fresh marker.`,
69368
- meta: { space: options.space }
69670
+ fix: `The ${options.markerLocation} row for space "${options.space}" contains invalid data. Delete the row, then run \`prisma db sign --db <url>\` to write a fresh marker.`,
69671
+ nextActions: [{
69672
+ kind: "run-command",
69673
+ label: "Write a fresh marker",
69674
+ command: "{bin} db sign --db <url>",
69675
+ reason: `Delete the invalid ${options.markerLocation} row for space "${options.space}" first — this command then writes a valid one.`
69676
+ }],
69677
+ meta: { space: options.space },
69678
+ ...ifDefined("cause", options.cause)
69369
69679
  });
69370
69680
  }
69371
69681
  /**
@@ -69375,7 +69685,8 @@ function errorMarkerReadFailed(options) {
69375
69685
  return new CliStructuredError("CONTRACT.MARKER_READ_FAILED", "Database error while reading contract marker", {
69376
69686
  why: options.why,
69377
69687
  fix: `Could not read marker at ${options.markerLocation} for space "${options.space}". Verify read permissions, connectivity, and locks, then retry.`,
69378
- meta: { space: options.space }
69688
+ meta: { space: options.space },
69689
+ ...ifDefined("cause", options.cause)
69379
69690
  });
69380
69691
  }
69381
69692
  function isMarkerRowParseError(err) {
@@ -69386,10 +69697,17 @@ function isLegacyMarkerShapeReadError(message) {
69386
69697
  return normalized.includes("column \"space\" does not exist") || normalized.includes("no such column: space");
69387
69698
  }
69388
69699
  function errorLegacyMarkerShape(options) {
69389
- return errorRunnerFailed(`Legacy marker-table shape detected on ${options.markerLocation} (no \`space\` column). Prisma Next is in pre-1.0; the previous transitional auto-migration to the per-space-row schema has been removed. Drop \`${options.markerLocation}\` and re-run \`prisma-next db init\` to reinitialise from a clean baseline.`, {
69700
+ return errorRunnerFailed(`Legacy marker-table shape detected on ${options.markerLocation} (no \`space\` column). Prisma Next is in pre-1.0; the previous transitional auto-migration to the per-space-row schema has been removed. Drop \`${options.markerLocation}\` and re-run \`prisma db init\` to reinitialise from a clean baseline.`, {
69390
69701
  why: options.why,
69391
- fix: "Legacy marker-table shape detected. Drop `prisma_contract.marker` (Postgres) or `_prisma_marker` (SQLite) and re-run `prisma-next db init` to recreate it with the current per-space schema.",
69392
- meta: { runnerErrorCode: "MIGRATION.LEGACY_MARKER_SHAPE" }
69702
+ fix: "Legacy marker-table shape detected. Drop `prisma_contract.marker` (Postgres) or `_prisma_marker` (SQLite) and re-run `prisma db init` to recreate it with the current per-space schema.",
69703
+ nextActions: [{
69704
+ kind: "run-command",
69705
+ label: "Reinitialise the marker table from a clean baseline",
69706
+ command: "{bin} db init",
69707
+ reason: `Drop \`${options.markerLocation}\` first — it has the legacy shape (no \`space\` column) and this command recreates it with the current per-space schema.`
69708
+ }],
69709
+ meta: { runnerErrorCode: "MIGRATION.LEGACY_MARKER_SHAPE" },
69710
+ ...ifDefined("cause", options.cause)
69393
69711
  });
69394
69712
  }
69395
69713
  function rethrowMarkerReadError(err, context) {
@@ -69397,17 +69715,20 @@ function rethrowMarkerReadError(err, context) {
69397
69715
  if (isMarkerRowParseError(err)) throw errorMarkerRowCorrupt({
69398
69716
  why: err.message,
69399
69717
  space: context.space,
69400
- markerLocation: context.markerLocation
69718
+ markerLocation: context.markerLocation,
69719
+ cause: err
69401
69720
  });
69402
69721
  const message = err instanceof Error ? err.message : String(err);
69403
69722
  if (isLegacyMarkerShapeReadError(message)) throw errorLegacyMarkerShape({
69404
69723
  why: message,
69405
- markerLocation: context.markerLocation
69724
+ markerLocation: context.markerLocation,
69725
+ cause: err
69406
69726
  });
69407
69727
  throw errorMarkerReadFailed({
69408
69728
  why: message,
69409
69729
  space: context.space,
69410
- markerLocation: context.markerLocation
69730
+ markerLocation: context.markerLocation,
69731
+ cause: err
69411
69732
  });
69412
69733
  }
69413
69734
  async function withMarkerReadErrorHandling(operation, context) {
@@ -69431,17 +69752,20 @@ function errorRunnerFailed(summary, options) {
69431
69752
  return new CliStructuredError("MIGRATION.RUNNER_FAILED", summary, {
69432
69753
  why: options?.why ?? "Migration runner failed",
69433
69754
  fix: options?.fix ?? "Inspect the reported conflict and reconcile schema drift",
69434
- ...options?.meta ? { meta: options.meta } : {}
69755
+ ...ifDefined("nextActions", options?.nextActions),
69756
+ ...options?.meta ? { meta: options.meta } : {},
69757
+ ...ifDefined("cause", options?.cause)
69435
69758
  });
69436
69759
  }
69437
69760
  /**
69438
- * Generic runtime error.
69761
+ * Generic runtime error carrying a caller-provided dotted code.
69439
69762
  */
69440
- function errorRuntime(summary, options) {
69441
- return new CliStructuredError("CONTRACT.VERIFY_FAILED", summary, {
69442
- ...options?.why ? { why: options.why } : { why: "Verification failed" },
69443
- ...options?.fix ? { fix: options.fix } : { fix: "Check contract and database state" },
69444
- ...options?.meta ? { meta: options.meta } : {}
69763
+ function errorRuntime(code, summary, options) {
69764
+ return new CliStructuredError(code, summary, {
69765
+ ...ifDefined("why", options?.why),
69766
+ ...ifDefined("fix", options?.fix),
69767
+ ...ifDefined("meta", options?.meta),
69768
+ ...ifDefined("cause", options?.cause)
69445
69769
  });
69446
69770
  }
69447
69771
  function sqlFamilyError(code, message, options) {
@@ -69495,7 +69819,16 @@ function parseContractMarkerRow(row) {
69495
69819
  const messages = result.map((p) => p.message).join("; ");
69496
69820
  throw sqlFamilyError("CONTRACT.MARKER_ROW_CORRUPT", `Invalid contract marker row: ${messages}`, {
69497
69821
  why: "The contract marker row read from the database does not match the expected marker shape.",
69498
- fix: "Re-sign the database with `prisma-next db sign`, or repair the marker table.",
69822
+ fix: "Re-sign the database with `prisma db sign`, or repair the marker table.",
69823
+ nextActions: [{
69824
+ kind: "run-command",
69825
+ label: "Re-sign the database",
69826
+ command: "{bin} db sign"
69827
+ }, {
69828
+ kind: "user-choice",
69829
+ label: "Repair the marker table by hand",
69830
+ reason: messages
69831
+ }],
69499
69832
  meta: { issues: messages }
69500
69833
  });
69501
69834
  }
@@ -70284,12 +70617,14 @@ var PostgresControlAdapter = class {
70284
70617
  const checkResult = await driver.query(`SELECT
70285
70618
  cl.relname AS table_name,
70286
70619
  c.conname AS constraint_name,
70287
- pg_get_constraintdef(c.oid) AS constraintdef
70620
+ pg_get_expr(c.conbin, c.conrelid) AS check_expression
70288
70621
  FROM pg_catalog.pg_constraint c
70289
70622
  JOIN pg_catalog.pg_class cl ON cl.oid = c.conrelid
70290
70623
  JOIN pg_catalog.pg_namespace ns ON ns.oid = cl.relnamespace
70291
70624
  WHERE ns.nspname = $1
70292
70625
  AND c.contype = 'c'
70626
+ AND c.conislocal
70627
+ AND c.conrelid <> 0
70293
70628
  ORDER BY cl.relname, c.conname`, [schema]);
70294
70629
  const columnsByTable = groupBy(columnsResult.rows, "table_name");
70295
70630
  const pksByTable = groupBy(pkResult.rows, "table_name");
@@ -70431,15 +70766,11 @@ var PostgresControlAdapter = class {
70431
70766
  columns: Object.freeze([...columnNames])
70432
70767
  };
70433
70768
  });
70434
- const checksForTable = [];
70435
- for (const checkRow of checksByTable.get(tableName) ?? []) {
70436
- const parsed = parseCheckConstraintDef(checkRow.constraintdef);
70437
- if (parsed) checksForTable.push({
70438
- name: checkRow.constraint_name,
70439
- column: parsed.column,
70440
- permittedValues: parsed.permittedValues
70441
- });
70442
- }
70769
+ const checksForTable = (checksByTable.get(tableName) ?? []).map((checkRow) => ({
70770
+ naming: namingOfLiveName(checkRow.constraint_name),
70771
+ expression: checkRow.check_expression,
70772
+ dependsOn: postgresColumnDependsOn(schema, tableName, Object.keys(columns))
70773
+ }));
70443
70774
  tableInputs[tableName] = {
70444
70775
  name: tableName,
70445
70776
  columns,
@@ -70730,75 +71061,6 @@ function groupBy(items, key) {
70730
71061
  }
70731
71062
  return map;
70732
71063
  }
70733
- /**
70734
- * Parses a Postgres check-constraint definition string (as returned by
70735
- * `pg_get_constraintdef`) into a column name and permitted values array.
70736
- *
70737
- * Handles two shapes that Postgres emits for enum-style checks:
70738
- *
70739
- * 1. `= ANY (ARRAY[...])` — Postgres rewrites `col IN ('a','b')` to this form:
70740
- * `CHECK ((col = ANY (ARRAY['a'::text, 'b'::text])))`
70741
- *
70742
- * 2. `IN (...)` — stays as-is when written directly:
70743
- * `CHECK ((col IN ('a', 'b')))`
70744
- *
70745
- * Column names may be plain identifiers (`status`) or double-quoted identifiers
70746
- * (`"my-col"`). Double-quoted identifiers with embedded `""` are un-escaped to a
70747
- * single `"`.
70748
- *
70749
- * String literal values may contain Postgres-style doubled single-quotes (`''`),
70750
- * which are un-escaped to a single `'` (e.g. `O''Brien` → `O'Brien`).
70751
- *
70752
- * Returns `{ column, permittedValues }` when the predicate matches one of
70753
- * the two recognised shapes. Returns `undefined` for anything else (e.g.
70754
- * a free-form SQL predicate that wasn't emitted by this slice).
70755
- */
70756
- function parseCheckConstraintDef(constraintdef) {
70757
- const afterCheck = constraintdef.replace(/^CHECK\s*\(/i, "").replace(/\)$/, "").trim();
70758
- const inner = afterCheck.startsWith("(") && afterCheck.endsWith(")") ? afterCheck.slice(1, -1).trim() : afterCheck;
70759
- const anyArrayMatch = inner.match(/^(?:"((?:[^"]|"")*)"|(\w+))\s*=\s*ANY\s*\(\s*ARRAY\s*\[(.+)\]\s*\)\s*$/i);
70760
- if (anyArrayMatch) {
70761
- const column = anyArrayMatch[1] !== void 0 ? anyArrayMatch[1].replace(/""/g, "\"") : anyArrayMatch[2];
70762
- const arrayBody = anyArrayMatch[3];
70763
- if (!column || !arrayBody) return void 0;
70764
- const permittedValues = extractArrayLiterals(arrayBody);
70765
- return permittedValues ? {
70766
- column,
70767
- permittedValues
70768
- } : void 0;
70769
- }
70770
- const inMatch = inner.match(/^(?:"((?:[^"]|"")*)"|(\w+))\s+IN\s*\((.+)\)\s*$/i);
70771
- if (inMatch) {
70772
- const column = inMatch[1] !== void 0 ? inMatch[1].replace(/""/g, "\"") : inMatch[2];
70773
- const listBody = inMatch[3];
70774
- if (!column || !listBody) return void 0;
70775
- const permittedValues = extractQuotedLiterals(listBody);
70776
- return permittedValues ? {
70777
- column,
70778
- permittedValues
70779
- } : void 0;
70780
- }
70781
- }
70782
- /**
70783
- * Extracts string literals from an `ARRAY[...]` body.
70784
- * Handles `'value'::type` casts by stripping the cast part.
70785
- * Postgres stores single quotes inside values as doubled single-quotes (`''`);
70786
- * each extracted value is un-escaped so `O''Brien` becomes `O'Brien`.
70787
- */
70788
- function extractArrayLiterals(arrayBody) {
70789
- const values = [...arrayBody.matchAll(/'((?:[^'\\]|\\.|'')*)'\s*(?:::[^\s,\]]+)?/g)].map((m) => (m[1] ?? "").replace(/''/g, "'"));
70790
- return values.length > 0 ? values : void 0;
70791
- }
70792
- /**
70793
- * Extracts string literals from an `IN (...)` list.
70794
- * Handles single-quoted literals with possible escaped quotes.
70795
- * Postgres stores single quotes inside values as doubled single-quotes (`''`);
70796
- * each extracted value is un-escaped so `O''Brien` becomes `O'Brien`.
70797
- */
70798
- function extractQuotedLiterals(listBody) {
70799
- const values = [...listBody.matchAll(/'((?:[^'\\]|\\.|'')*)'/g)].map((m) => (m[1] ?? "").replace(/''/g, "'"));
70800
- return values.length > 0 ? values : void 0;
70801
- }
70802
71064
  function pgIsTextLikeNativeType(nativeType) {
70803
71065
  return nativeType === "text" || nativeType === "varchar" || nativeType.startsWith("varchar(") || nativeType === "character varying" || nativeType.startsWith("character varying(") || nativeType === "char" || nativeType.startsWith("char(") || nativeType === "character" || nativeType.startsWith("character(");
70804
71066
  }
@@ -70837,14 +71099,28 @@ function pgInlineLiteral(wire, nativeType) {
70837
71099
  nativeType
70838
71100
  } });
70839
71101
  }
71102
+ const SERIAL_FAMILY_TYPES = /* @__PURE__ */ new Set([
71103
+ "serial",
71104
+ "serial4",
71105
+ "bigserial",
71106
+ "serial8",
71107
+ "smallserial",
71108
+ "serial2"
71109
+ ]);
70840
71110
  async function pgRenderDdlColumnDefault(def, nativeType, codecLookup, codecRef) {
70841
71111
  if (def.kind === "function") {
70842
- if (def.expression === "autoincrement()") return "";
71112
+ if (def.expression === "autoincrement()") {
71113
+ if (!SERIAL_FAMILY_TYPES.has(nativeType.toLowerCase())) throw postgresError("CONTRACT.DEFAULT_INVALID", `Column type "${nativeType}" has an autoincrement() default but is not a SERIAL-family pseudo-type. Autoincrement columns must declare their type as SERIAL (or SERIAL4), BIGSERIAL (or SERIAL8), or SMALLSERIAL (or SERIAL2) — e.g. col(name, "SERIAL", { default: fn("autoincrement()") }).`, { meta: { nativeType } });
71114
+ return "";
71115
+ }
70843
71116
  return `DEFAULT (${def.expression})`;
70844
71117
  }
70845
71118
  if (codecRef !== void 0) {
70846
71119
  const codec = codecLookup.get(codecRef.codecId);
70847
- if (codec !== void 0) return `DEFAULT ${pgInlineLiteral(await codec.encode(def.value, {}), nativeType)}`;
71120
+ if (codec !== void 0) {
71121
+ const value = def.value instanceof Date ? def.value : codec.decodeJson(def.value);
71122
+ return `DEFAULT ${pgInlineLiteral(await codec.encode(value, {}), nativeType)}`;
71123
+ }
70848
71124
  }
70849
71125
  return `DEFAULT ${pgInlineLiteral(def.value, nativeType)}`;
70850
71126
  }
@@ -71045,15 +71321,28 @@ const produces = (operation, input, codecId) => ({
71045
71321
  },
71046
71322
  nullable: true
71047
71323
  });
71048
- /** Integer codecs whose `sum` widens to `bigint` every built-in integer bar `int8`, whose sum goes to `numeric` instead. */
71324
+ /** The same, for an operation that builds its own expression. */
71325
+ const producesVia = (operation, input, codecId, lower) => ({
71326
+ ...produces(operation, input, codecId),
71327
+ lower
71328
+ });
71329
+ /** The SQL aggregate a lossless variant computes with. `sumBigInt` is a `sum` read exactly, `countBigInt` a `count`, `avgDecimal` an `avg`: the variants differ in how the result is read, never in what the database computes. */
71330
+ const computedWith = (fn) => ({ expr }) => new AggregateExpr(fn, expr);
71331
+ /** `avg` over an integer column, rounded once. PostgreSQL computes the exact `numeric` mean and the cast turns that one value into the `double precision` the result codec reads; casting the input instead would round every value before it was accumulated. */
71332
+ const avgCastToFloat8 = ({ expr }) => CastExpr.as(new AggregateExpr("avg", expr), "float8");
71333
+ /** Integer codecs whose `sum` widens to `bigint` — every built-in integer bar the 64-bit ones, whose sum goes to `numeric` instead. */
71049
71334
  const SUM_WIDENS_TO_INT8 = [
71050
71335
  PG_INT2_CODEC_ID,
71051
71336
  PG_INT4_CODEC_ID,
71052
71337
  PG_INT_CODEC_ID,
71053
71338
  SQL_INT_CODEC_ID
71054
71339
  ];
71055
- /** Every built-in integer codec: `avg` over any of them is `numeric`. */
71056
- const AVG_IS_NUMERIC = [...SUM_WIDENS_TO_INT8, PG_INT8_CODEC_ID];
71340
+ /** The 64-bit integer codecs: PostgreSQL computes their `sum` as a `numeric`, a total free to leave the range an `int8` holds. */
71341
+ const SUM_WIDENS_TO_NUMERIC = [PG_INT8_CODEC_ID, PG_INT8_NUMBER_CODEC_ID];
71342
+ /** The integer codecs a `sum` reads back as a `number`: every fixed-width one, whatever its own application type. */
71343
+ const FIXED_WIDTH_INTEGER_CODECS = [...SUM_WIDENS_TO_INT8, ...SUM_WIDENS_TO_NUMERIC];
71344
+ /** Every built-in integer codec, the unbounded one included: `avg` over any of them is a `numeric` mean. */
71345
+ const INTEGER_CODECS = [...FIXED_WIDTH_INTEGER_CODECS, PG_UNBOUNDED_INT_CODEC_ID];
71057
71346
  /** Codecs over `double precision`, whose `sum` and `avg` stay there. */
71058
71347
  const DOUBLE_PRECISION_CODECS = [
71059
71348
  PG_FLOAT8_CODEC_ID,
@@ -71091,20 +71380,36 @@ const postgresAggregateDescriptors = [
71091
71380
  {
71092
71381
  operation: "count",
71093
71382
  input: { kind: "any" },
71383
+ output: {
71384
+ kind: "codec",
71385
+ codecId: PG_INT8_NUMBER_CODEC_ID
71386
+ },
71387
+ nullable: false,
71388
+ emptyResultJson: 0
71389
+ },
71390
+ {
71391
+ operation: "countBigInt",
71392
+ input: { kind: "any" },
71094
71393
  output: {
71095
71394
  kind: "codec",
71096
71395
  codecId: PG_INT8_CODEC_ID
71097
71396
  },
71098
- nullable: false
71397
+ nullable: false,
71398
+ emptyResultJson: "0",
71399
+ lower: computedWith("count")
71099
71400
  },
71100
- ...SUM_WIDENS_TO_INT8.map((codecId) => produces("sum", overCodec(codecId), PG_INT8_CODEC_ID)),
71101
- produces("sum", overCodec(PG_INT8_CODEC_ID), PG_NUMERIC_CODEC_ID),
71401
+ ...FIXED_WIDTH_INTEGER_CODECS.map((codecId) => produces("sum", overCodec(codecId), PG_INT8_NUMBER_CODEC_ID)),
71402
+ ...SUM_WIDENS_TO_INT8.map((codecId) => producesVia("sumBigInt", overCodec(codecId), PG_INT8_CODEC_ID, computedWith("sum"))),
71403
+ ...SUM_WIDENS_TO_NUMERIC.map((codecId) => producesVia("sumBigInt", overCodec(codecId), PG_UNBOUNDED_INT_CODEC_ID, computedWith("sum"))),
71404
+ producesVia("sumBigInt", overCodec(PG_UNBOUNDED_INT_CODEC_ID), PG_UNBOUNDED_INT_CODEC_ID, computedWith("sum")),
71102
71405
  produces("sum", overCodec(PG_FLOAT4_CODEC_ID), PG_FLOAT4_CODEC_ID),
71103
71406
  ...DOUBLE_PRECISION_CODECS.map((codecId) => produces("sum", overCodec(codecId), PG_FLOAT8_CODEC_ID)),
71104
71407
  produces("sum", overCodec(PG_NUMERIC_CODEC_ID), PG_NUMERIC_CODEC_ID),
71408
+ produces("sum", overCodec(PG_UNBOUNDED_INT_CODEC_ID), PG_UNBOUNDED_INT_CODEC_ID),
71105
71409
  produces("sum", overCodec(PG_INTERVAL_CODEC_ID), PG_INTERVAL_CODEC_ID),
71106
71410
  produces("sum", overCodec(PG_TIME_CODEC_ID), PG_INTERVAL_CODEC_ID),
71107
- ...AVG_IS_NUMERIC.map((codecId) => produces("avg", overCodec(codecId), PG_NUMERIC_CODEC_ID)),
71411
+ ...INTEGER_CODECS.map((codecId) => producesVia("avg", overCodec(codecId), PG_FLOAT8_CODEC_ID, avgCastToFloat8)),
71412
+ ...[...INTEGER_CODECS, PG_NUMERIC_CODEC_ID].map((codecId) => producesVia("avgDecimal", overCodec(codecId), PG_NUMERIC_CODEC_ID, computedWith("avg"))),
71108
71413
  ...[PG_FLOAT4_CODEC_ID, ...DOUBLE_PRECISION_CODECS].map((codecId) => produces("avg", overCodec(codecId), PG_FLOAT8_CODEC_ID)),
71109
71414
  produces("avg", overCodec(PG_NUMERIC_CODEC_ID), PG_NUMERIC_CODEC_ID),
71110
71415
  produces("avg", overCodec(PG_INTERVAL_CODEC_ID), PG_INTERVAL_CODEC_ID),
@@ -71196,7 +71501,8 @@ const postgresAdapterDescriptorMeta = {
71196
71501
  returning: true,
71197
71502
  defaultInInsert: true,
71198
71503
  lateral: true,
71199
- scalarList: true
71504
+ scalarList: true,
71505
+ checkConstraint: true
71200
71506
  }
71201
71507
  },
71202
71508
  types: {
@@ -71513,9 +71819,9 @@ function classifyDiffEntityKind(issue, entityKindOf) {
71513
71819
  * issue reason. The vocabulary maps one-to-one: an undeclared live entity or
71514
71820
  * namespace is `extraTopLevelObject`, an undeclared live field
71515
71821
  * `extraNestedElement`, undeclared auxiliaries (constraints, indexes,
71516
- * defaults) and structural leaves (policies) `extraAuxiliary`; a value-set
71517
- * drift on a check node is `valueDrift`; every other paired divergence is
71518
- * `declaredIncompatible`; anything the database lacks is `declaredMissing`.
71822
+ * defaults) and structural leaves (policies) `extraAuxiliary`; every paired
71823
+ * divergence is `declaredIncompatible`; anything the database lacks is
71824
+ * `declaredMissing`.
71519
71825
  * `granularityOf` is the target's classifier, so target and extension node
71520
71826
  * kinds classify without the family importing them.
71521
71827
  */
@@ -71527,7 +71833,6 @@ function classifySqlDiffIssue(issue, granularityOf) {
71527
71833
  if (granularity === "field") return "extraNestedElement";
71528
71834
  return "extraAuxiliary";
71529
71835
  }
71530
- if (issueNode$1(issue)?.nodeKind === RelationalSchemaNodeKind.check) return "valueDrift";
71531
71836
  return "declaredIncompatible";
71532
71837
  }
71533
71838
  /**
@@ -71929,7 +72234,11 @@ const sortTargets = [{
71929
72234
  "table",
71930
72235
  "*"
71931
72236
  ],
71932
- arrayKeys: ["indexes", "uniques"]
72237
+ arrayKeys: [
72238
+ "checks",
72239
+ "indexes",
72240
+ "uniques"
72241
+ ]
71933
72242
  }];
71934
72243
  const matchesPreserveEmptyPattern = createPreserveEmptyPredicate(preserveEmptyPatterns);
71935
72244
  const shouldPreserveEmpty = (path) => isColumnDefaultValuePath(path) || matchesPreserveEmptyPattern(path);
@@ -72731,27 +73040,29 @@ function generateStorageNamespacesType(namespaces) {
72731
73040
  }
72732
73041
  const EXACT_NAME_BODY_PREAMBLE = "Drift detection compares the authored SQL text byte-for-byte against Postgres's reprinted form, which is only reliable when the text was captured by contract infer.";
72733
73042
  /**
72734
- * Per-subject remediation: an index moves to wire naming via `name:`;
72735
- * a policy has no such parameter — dropping `@@map` makes the block's head
72736
- * the wire prefix.
73043
+ * Per-subject remediation: an index or check moves to wire naming via
73044
+ * `name:`; a policy has no such parameter — dropping `@@map` makes the
73045
+ * block's head the wire prefix.
72737
73046
  */
72738
73047
  const EXACT_NAME_BODY_REMEDIATION = {
72739
73048
  index: "For hand-authored definitions, use name: and let Prisma Next manage the physical name; to migrate an adopted object to wire naming, replace map: with name: (keeping the body text unchanged) and apply the resulting rename migration.",
72740
- policy: "For hand-authored definitions, drop @@map and let the policy block's head name the policy; to migrate an adopted policy to wire naming, remove @@map (keeping the body text unchanged) and apply the resulting rename migration."
73049
+ policy: "For hand-authored definitions, drop @@map and let the policy block's head name the policy; to migrate an adopted policy to wire naming, remove @@map (keeping the body text unchanged) and apply the resulting rename migration.",
73050
+ check: "For hand-authored definitions, use name: and let Prisma Next manage the physical name; to migrate an adopted check to wire naming, replace map: with name: (keeping the body text unchanged) and apply the resulting rename migration."
72741
73051
  };
72742
- /** What the user actually wrote, per subject: index `map:`, policy `@@map`. */
73052
+ /** What the user actually wrote, per subject: index and check `map:`, policy `@@map`. */
72743
73053
  const EXACT_NAME_FEATURE = {
72744
73054
  index: "map:",
72745
- policy: "@@map"
73055
+ policy: "@@map",
73056
+ check: "map:"
72746
73057
  };
72747
73058
  const EXACT_NAME_BODY_WARNING_CODE = "PN_EXACT_NAME_BODY_COMPARISON";
72748
73059
  /**
72749
73060
  * Mints the exact-name body-comparison warning for a `map:`-named object
72750
73061
  * carrying a hand-authorable SQL body — fully formed, so the transport and
72751
- * the flush stay generic. `subject` is `index` here and `policy` where
72752
- * policies mint the same warning; the feature name and the remediation are
72753
- * subject-specific end to end, so a batched summary (grouped on
72754
- * code + summary) is true of every object it covers.
73062
+ * the flush stay generic. `subject` distinguishes the index, policy, and
73063
+ * check callers that mint this same warning; the feature name and the
73064
+ * remediation are subject-specific end to end, so a batched summary
73065
+ * (grouped on code + summary) is true of every object it covers.
72755
73066
  */
72756
73067
  function exactNameBodyWarning(subject, exactName) {
72757
73068
  const item = `${subject} "${exactName}"`;
@@ -73119,6 +73430,26 @@ function rejectDuplicateWireNamedIndexContent(indexes, coordinate, errors) {
73119
73430
  seenContent.add(content);
73120
73431
  }
73121
73432
  }
73433
+ /**
73434
+ * Two wire-named checks with the same predicate are one check written twice —
73435
+ * the content hash is their identity, so neither spelling can survive, and
73436
+ * whitespace variants of one predicate collapse onto the same hash. An
73437
+ * exact-named check is identified by its name instead, so content twins under
73438
+ * two names are legal (the legacy shape a database adopts from) and a repeated
73439
+ * name is rejected by the named-object check.
73440
+ */
73441
+ function rejectDuplicateWireNamedCheckContent(checks, coordinate, errors) {
73442
+ const seenContent = /* @__PURE__ */ new Set();
73443
+ for (const check of checks) {
73444
+ if (check.prefix === void 0) continue;
73445
+ const content = computeCheckContentHash(check.expression);
73446
+ if (seenContent.has(content)) {
73447
+ errors.push(`${coordinate}: duplicate check constraint definition (expression "${check.expression}")`);
73448
+ continue;
73449
+ }
73450
+ seenContent.add(content);
73451
+ }
73452
+ }
73122
73453
  function isContractFieldType(value) {
73123
73454
  if (!isPlainRecord(value)) return false;
73124
73455
  const kind = value["kind"];
@@ -73308,18 +73639,7 @@ function validateStorageSemantics(storage) {
73308
73639
  if (fk.onDelete === "setDefault" && !column.nullable && column.default === void 0) errors.push(`Namespace "${namespaceId}" table "${tableName}": onDelete setDefault on foreign key column "${colName}" which is NOT NULL and has no DEFAULT`);
73309
73640
  if (fk.onUpdate === "setDefault" && !column.nullable && column.default === void 0) errors.push(`Namespace "${namespaceId}" table "${tableName}": onUpdate setDefault on foreign key column "${colName}" which is NOT NULL and has no DEFAULT`);
73310
73641
  }
73311
- const seenCheckDefinitions = /* @__PURE__ */ new Set();
73312
- for (const check of table.checks ?? []) {
73313
- const signature = JSON.stringify({
73314
- column: check.column,
73315
- valueSet: check.valueSet
73316
- });
73317
- if (seenCheckDefinitions.has(signature)) {
73318
- errors.push(`Namespace "${namespaceId}" table "${tableName}": duplicate check constraint definition on column "${check.column}"`);
73319
- continue;
73320
- }
73321
- seenCheckDefinitions.add(signature);
73322
- }
73642
+ rejectDuplicateWireNamedCheckContent(table.checks ?? [], tableCoordinate, errors);
73323
73643
  }
73324
73644
  return errors;
73325
73645
  }
@@ -73369,7 +73689,6 @@ function validateSqlStorageConsistency(contract) {
73369
73689
  }
73370
73690
  for (const unique of table.uniques) for (const colName of unique.columns) if (!columnNames.has(colName)) throw new ContractValidationError(`Namespace "${namespaceId}" table "${tableName}" unique constraint references non-existent column "${colName}"`, "storage");
73371
73691
  for (const index of table.indexes) for (const colName of index.columns ?? []) if (!columnNames.has(colName)) throw new ContractValidationError(`Namespace "${namespaceId}" table "${tableName}" index references non-existent column "${colName}"`, "storage");
73372
- for (const check of table.checks ?? []) if (!columnNames.has(check.column)) throw new ContractValidationError(`Namespace "${namespaceId}" table "${tableName}" check constraint "${check.name}" references non-existent column "${check.column}"`, "storage");
73373
73692
  for (const [colName, column] of Object.entries(table.columns)) if (!column.nullable && column.default?.kind === "literal" && column.default.value === null) throw new ContractValidationError(`Namespace "${namespaceId}" table "${tableName}" column "${colName}" is NOT NULL but has a literal null default`, "storage");
73374
73693
  for (const fk of table.foreignKeys) {
73375
73694
  if (fk.source.namespaceId !== namespaceId || fk.source.tableName !== tableName) throw new ContractValidationError(`Namespace "${namespaceId}" table "${tableName}" contains foreignKey with mismatched source coordinates (${fk.source.namespaceId}.${fk.source.tableName})`, "storage");
@@ -74289,14 +74608,65 @@ const OK_VOID = ResultImpl.ok(void 0);
74289
74608
  function okVoid() {
74290
74609
  return OK_VOID;
74291
74610
  }
74611
+ const _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
74292
74612
  function normalizeWindowsPath(input = "") {
74293
74613
  if (!input) return input;
74294
74614
  return input.replace(/\\/g, "/").replace(_DRIVE_LETTER_START_RE, (r) => r.toUpperCase());
74295
74615
  }
74616
+ const _UNC_REGEX = /^[/\\]{2}/;
74617
+ const _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/;
74618
+ const _DRIVE_LETTER_RE = /^[A-Za-z]:$/;
74619
+ const _ROOT_FOLDER_RE = /^\/([A-Za-z]:)?$/;
74620
+ const normalize = function(path) {
74621
+ if (path.length === 0) return ".";
74622
+ path = normalizeWindowsPath(path);
74623
+ const isUNCPath = path.match(_UNC_REGEX);
74624
+ const isPathAbsolute = isAbsolute(path);
74625
+ const trailingSeparator = path[path.length - 1] === "/";
74626
+ path = normalizeString(path, !isPathAbsolute);
74627
+ if (path.length === 0) {
74628
+ if (isPathAbsolute) return "/";
74629
+ return trailingSeparator ? "./" : ".";
74630
+ }
74631
+ if (trailingSeparator) path += "/";
74632
+ if (_DRIVE_LETTER_RE.test(path)) path += "/";
74633
+ if (isUNCPath) {
74634
+ if (!isPathAbsolute) return `//./${path}`;
74635
+ return `//${path}`;
74636
+ }
74637
+ return isPathAbsolute && !isAbsolute(path) ? `/${path}` : path;
74638
+ };
74639
+ const join$1 = function(...segments) {
74640
+ let path = "";
74641
+ for (const seg of segments) {
74642
+ if (!seg) continue;
74643
+ if (path.length > 0) {
74644
+ const pathTrailing = path[path.length - 1] === "/";
74645
+ const segLeading = seg[0] === "/";
74646
+ if (pathTrailing && segLeading) path += seg.slice(1);
74647
+ else path += pathTrailing || segLeading ? seg : `/${seg}`;
74648
+ } else path += seg;
74649
+ }
74650
+ return normalize(path);
74651
+ };
74296
74652
  function cwd() {
74297
74653
  if (typeof process !== "undefined" && typeof process.cwd === "function") return process.cwd().replace(/\\/g, "/");
74298
74654
  return "/";
74299
74655
  }
74656
+ const resolve = function(...arguments_) {
74657
+ arguments_ = arguments_.map((argument) => normalizeWindowsPath(argument));
74658
+ let resolvedPath = "";
74659
+ let resolvedAbsolute = false;
74660
+ for (let index = arguments_.length - 1; index >= -1 && !resolvedAbsolute; index--) {
74661
+ const path = index >= 0 ? arguments_[index] : cwd();
74662
+ if (!path || path.length === 0) continue;
74663
+ resolvedPath = `${path}/${resolvedPath}`;
74664
+ resolvedAbsolute = isAbsolute(path);
74665
+ }
74666
+ resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute);
74667
+ if (resolvedAbsolute && !isAbsolute(resolvedPath)) return `/${resolvedPath}`;
74668
+ return resolvedPath.length > 0 ? resolvedPath : ".";
74669
+ };
74300
74670
  function normalizeString(path, allowAboveRoot) {
74301
74671
  let res = "";
74302
74672
  let lastSegmentLength = 0;
@@ -74347,107 +74717,38 @@ function normalizeString(path, allowAboveRoot) {
74347
74717
  }
74348
74718
  return res;
74349
74719
  }
74350
- var _DRIVE_LETTER_START_RE;
74351
- var _UNC_REGEX;
74352
- var _IS_ABSOLUTE_RE;
74353
- var _DRIVE_LETTER_RE;
74354
- var _ROOT_FOLDER_RE;
74355
- var normalize;
74356
- var join$1;
74357
- var resolve;
74358
- var isAbsolute;
74359
- var relative;
74360
- var dirname$1;
74361
- var basename;
74362
- var init_pathe_M_eThtNZ = __esmMin((() => {
74363
- _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
74364
- _UNC_REGEX = /^[/\\]{2}/;
74365
- _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/;
74366
- _DRIVE_LETTER_RE = /^[A-Za-z]:$/;
74367
- _ROOT_FOLDER_RE = /^\/([A-Za-z]:)?$/;
74368
- normalize = function(path) {
74369
- if (path.length === 0) return ".";
74370
- path = normalizeWindowsPath(path);
74371
- const isUNCPath = path.match(_UNC_REGEX);
74372
- const isPathAbsolute = isAbsolute(path);
74373
- const trailingSeparator = path[path.length - 1] === "/";
74374
- path = normalizeString(path, !isPathAbsolute);
74375
- if (path.length === 0) {
74376
- if (isPathAbsolute) return "/";
74377
- return trailingSeparator ? "./" : ".";
74378
- }
74379
- if (trailingSeparator) path += "/";
74380
- if (_DRIVE_LETTER_RE.test(path)) path += "/";
74381
- if (isUNCPath) {
74382
- if (!isPathAbsolute) return `//./${path}`;
74383
- return `//${path}`;
74384
- }
74385
- return isPathAbsolute && !isAbsolute(path) ? `/${path}` : path;
74386
- };
74387
- join$1 = function(...segments) {
74388
- let path = "";
74389
- for (const seg of segments) {
74390
- if (!seg) continue;
74391
- if (path.length > 0) {
74392
- const pathTrailing = path[path.length - 1] === "/";
74393
- const segLeading = seg[0] === "/";
74394
- if (pathTrailing && segLeading) path += seg.slice(1);
74395
- else path += pathTrailing || segLeading ? seg : `/${seg}`;
74396
- } else path += seg;
74397
- }
74398
- return normalize(path);
74399
- };
74400
- resolve = function(...arguments_) {
74401
- arguments_ = arguments_.map((argument) => normalizeWindowsPath(argument));
74402
- let resolvedPath = "";
74403
- let resolvedAbsolute = false;
74404
- for (let index = arguments_.length - 1; index >= -1 && !resolvedAbsolute; index--) {
74405
- const path = index >= 0 ? arguments_[index] : cwd();
74406
- if (!path || path.length === 0) continue;
74407
- resolvedPath = `${path}/${resolvedPath}`;
74408
- resolvedAbsolute = isAbsolute(path);
74409
- }
74410
- resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute);
74411
- if (resolvedAbsolute && !isAbsolute(resolvedPath)) return `/${resolvedPath}`;
74412
- return resolvedPath.length > 0 ? resolvedPath : ".";
74413
- };
74414
- isAbsolute = function(p) {
74415
- return _IS_ABSOLUTE_RE.test(p);
74416
- };
74417
- relative = function(from, to) {
74418
- const _from = resolve(from).replace(_ROOT_FOLDER_RE, "$1").split("/");
74419
- const _to = resolve(to).replace(_ROOT_FOLDER_RE, "$1").split("/");
74420
- if (_to[0][1] === ":" && _from[0][1] === ":" && _from[0] !== _to[0]) return _to.join("/");
74421
- const _fromCopy = [..._from];
74422
- for (const segment of _fromCopy) {
74423
- if (_to[0] !== segment) break;
74424
- _from.shift();
74425
- _to.shift();
74426
- }
74427
- return [..._from.map(() => ".."), ..._to].join("/");
74428
- };
74429
- dirname$1 = function(p) {
74430
- const segments = normalizeWindowsPath(p).replace(/\/$/, "").split("/").slice(0, -1);
74431
- if (segments.length === 1 && _DRIVE_LETTER_RE.test(segments[0])) segments[0] += "/";
74432
- return segments.join("/") || (isAbsolute(p) ? "/" : ".");
74433
- };
74434
- basename = function(p, extension) {
74435
- const segments = normalizeWindowsPath(p).split("/");
74436
- let lastSegment = "";
74437
- for (let i = segments.length - 1; i >= 0; i--) {
74438
- const val = segments[i];
74439
- if (val) {
74440
- lastSegment = val;
74441
- break;
74442
- }
74720
+ const isAbsolute = function(p) {
74721
+ return _IS_ABSOLUTE_RE.test(p);
74722
+ };
74723
+ const relative = function(from, to) {
74724
+ const _from = resolve(from).replace(_ROOT_FOLDER_RE, "$1").split("/");
74725
+ const _to = resolve(to).replace(_ROOT_FOLDER_RE, "$1").split("/");
74726
+ if (_to[0][1] === ":" && _from[0][1] === ":" && _from[0] !== _to[0]) return _to.join("/");
74727
+ const _fromCopy = [..._from];
74728
+ for (const segment of _fromCopy) {
74729
+ if (_to[0] !== segment) break;
74730
+ _from.shift();
74731
+ _to.shift();
74732
+ }
74733
+ return [..._from.map(() => ".."), ..._to].join("/");
74734
+ };
74735
+ const dirname$1 = function(p) {
74736
+ const segments = normalizeWindowsPath(p).replace(/\/$/, "").split("/").slice(0, -1);
74737
+ if (segments.length === 1 && _DRIVE_LETTER_RE.test(segments[0])) segments[0] += "/";
74738
+ return segments.join("/") || (isAbsolute(p) ? "/" : ".");
74739
+ };
74740
+ const basename = function(p, extension) {
74741
+ const segments = normalizeWindowsPath(p).split("/");
74742
+ let lastSegment = "";
74743
+ for (let i = segments.length - 1; i >= 0; i--) {
74744
+ const val = segments[i];
74745
+ if (val) {
74746
+ lastSegment = val;
74747
+ break;
74443
74748
  }
74444
- return extension && lastSegment.endsWith(extension) ? lastSegment.slice(0, -extension.length) : lastSegment;
74445
- };
74446
- }));
74447
- var init_dist = __esmMin((() => {
74448
- init_pathe_M_eThtNZ();
74449
- }));
74450
- init_dist();
74749
+ }
74750
+ return extension && lastSegment.endsWith(extension) ? lastSegment.slice(0, -extension.length) : lastSegment;
74751
+ };
74451
74752
  /**
74452
74753
  * Build the canonical "re-emit this package" remediation hint.
74453
74754
  *
@@ -74476,40 +74777,30 @@ function reemitHint(dir, fallback) {
74476
74777
  * - category: Always 'MIGRATION'
74477
74778
  * - why: Explains the cause in plain language
74478
74779
  * - fix: Actionable remediation step
74479
- * - details: Machine-readable structured data for agents
74780
+ * - meta: Machine-readable structured data for agents
74480
74781
  */
74481
- var MigrationToolsError = class extends Error {
74482
- code;
74483
- category = "MIGRATION";
74484
- why;
74485
- fix;
74486
- details;
74782
+ var MigrationToolsError = class extends CliStructuredError {
74783
+ category;
74487
74784
  constructor(code, summary, options) {
74488
- super(summary);
74489
- this.name = "MigrationToolsError";
74490
- this.code = code;
74491
- this.why = options.why;
74492
- this.fix = options.fix;
74493
- this.details = options.details;
74785
+ super(code, summary, options);
74786
+ this.category = "MIGRATION";
74494
74787
  }
74495
74788
  static is(error) {
74496
- if (!(error instanceof Error)) return false;
74497
- const candidate = error;
74498
- return candidate.name === "MigrationToolsError" && typeof candidate.code === "string";
74789
+ return CliStructuredError.is(error) && "category" in error && error.category === "MIGRATION" && error.code.startsWith("MIGRATION.");
74499
74790
  }
74500
74791
  };
74501
74792
  function errorDirectoryExists(dir) {
74502
74793
  return new MigrationToolsError("MIGRATION.DIR_EXISTS", "Migration directory already exists", {
74503
74794
  why: `The directory "${dir}" already exists. Each migration must have a unique directory.`,
74504
74795
  fix: "Use --name to pick a different name, or delete the existing directory and re-run.",
74505
- details: { dir }
74796
+ meta: { dir }
74506
74797
  });
74507
74798
  }
74508
74799
  function errorMissingFile(file, dir) {
74509
74800
  return new MigrationToolsError("MIGRATION.FILE_MISSING", `Missing ${file}`, {
74510
74801
  why: `Expected "${file}" in "${dir}" but the file does not exist.`,
74511
74802
  fix: reemitHint(dir, "or delete the directory if the migration is unwanted and the source TypeScript is gone."),
74512
- details: {
74803
+ meta: {
74513
74804
  file,
74514
74805
  dir
74515
74806
  }
@@ -74519,7 +74810,7 @@ function errorInvalidJson(filePath, parseError) {
74519
74810
  return new MigrationToolsError("MIGRATION.INVALID_JSON", "Invalid JSON in migration file", {
74520
74811
  why: `Failed to parse "${filePath}": ${parseError}`,
74521
74812
  fix: reemitHint(dirname$1(filePath), "or restore the directory from version control."),
74522
- details: {
74813
+ meta: {
74523
74814
  filePath,
74524
74815
  parseError
74525
74816
  }
@@ -74529,7 +74820,7 @@ function errorInvalidManifest(filePath, reason) {
74529
74820
  return new MigrationToolsError("MIGRATION.INVALID_MANIFEST", "Invalid migration manifest", {
74530
74821
  why: `Migration manifest at "${filePath}" is invalid: ${reason}`,
74531
74822
  fix: reemitHint(dirname$1(filePath), "or restore the directory from version control."),
74532
- details: {
74823
+ meta: {
74533
74824
  filePath,
74534
74825
  reason
74535
74826
  }
@@ -74539,21 +74830,21 @@ function errorDescribeMissingEndContract() {
74539
74830
  return new MigrationToolsError("MIGRATION.DESCRIBE_INVALID", "Migration.describe(): provide endContractJson or override describe() — a migration needs a destination contract hash.", {
74540
74831
  why: "Migration.describe() was called on a migration that carries no endContractJson and does not override describe(), so no destination contract hash can be derived.",
74541
74832
  fix: "Set endContractJson on the migration, or override describe() to return the { from, to } metadata explicitly.",
74542
- details: { reason: "missing-end-contract" }
74833
+ meta: { reason: "missing-end-contract" }
74543
74834
  });
74544
74835
  }
74545
74836
  function errorSpaceHeadRefMissing(spaceId) {
74546
74837
  return new MigrationToolsError("MIGRATION.CHECK_HEAD_REF_MISSING", `Contract space "${spaceId}" has no head ref; its contract cannot be resolved from the snapshot store without one.`, {
74547
74838
  why: `Contract space "${spaceId}" declares no refs/head.json, so there is no hash to resolve its contract against the snapshot store.`,
74548
74839
  fix: "Re-emit the contract-space migrations and head-ref artifacts (the extension's contract-space build), or restore refs/head.json from version control.",
74549
- details: { spaceId }
74840
+ meta: { spaceId }
74550
74841
  });
74551
74842
  }
74552
74843
  function errorInvalidSpaceId(spaceId) {
74553
74844
  return new MigrationToolsError("MIGRATION.INVALID_SPACE_ID", "Invalid contract space identifier", {
74554
74845
  why: `The space id "${spaceId}" does not match the required pattern /^[a-z][a-z0-9_-]{0,63}$/. Space ids are used as filesystem directory names under \`migrations/\`, so the pattern is conservative on purpose.`,
74555
74846
  fix: "Pick a lowercase identifier that begins with a letter and contains only lowercase letters, digits, hyphens, or underscores; max 64 characters total.",
74556
- details: { spaceId }
74847
+ meta: { spaceId }
74557
74848
  });
74558
74849
  }
74559
74850
  function errorDescriptorHeadHashMismatch(args) {
@@ -74561,7 +74852,7 @@ function errorDescriptorHeadHashMismatch(args) {
74561
74852
  return new MigrationToolsError("MIGRATION.DESCRIPTOR_HEAD_HASH_MISMATCH", "Extension descriptor's headRef.hash does not match its contractJson", {
74562
74853
  why: `Extension "${extensionId}" publishes a \`contractSpace\` whose \`headRef.hash\` (${headRefHash}) does not match the canonical hash recomputed from \`contractSpace.contractJson\` (${recomputedHash}). This means the extension descriptor was published with stale \`headRef.hash\` — typically because the contract was bumped without rerunning the extension's emit pipeline.`,
74563
74854
  fix: "Re-run the extension authoring pipeline so `contractJson.storage.storageHash` and `headRef.hash` agree, then republish the extension. If you are the extension author and you intentionally bumped `contractJson`, recompute and update `headRef.hash` (and refresh any on-disk migration metadata that derives from it).",
74564
- details: {
74855
+ meta: {
74565
74856
  extensionId,
74566
74857
  recomputedHash,
74567
74858
  headRefHash
@@ -74572,7 +74863,7 @@ function errorInvalidRefFile(filePath, reason) {
74572
74863
  return new MigrationToolsError("MIGRATION.INVALID_REF_FILE", "Invalid ref file", {
74573
74864
  why: `Ref file at "${filePath}" is invalid: ${reason}`,
74574
74865
  fix: "Ensure the ref file contains valid JSON with { \"hash\": \"<64 hex chars>\", \"invariants\": [\"...\"] }.",
74575
- details: {
74866
+ meta: {
74576
74867
  path: filePath,
74577
74868
  reason
74578
74869
  }
@@ -74582,21 +74873,21 @@ function errorInvalidRefName(refName) {
74582
74873
  return new MigrationToolsError("MIGRATION.INVALID_REF_NAME", "Invalid ref name", {
74583
74874
  why: `Ref name "${refName}" is invalid. Names must be lowercase alphanumeric with hyphens or forward slashes (no "." or ".." segments).`,
74584
74875
  fix: `Use a valid ref name (e.g., "staging", "envs/production").`,
74585
- details: { refName }
74876
+ meta: { refName }
74586
74877
  });
74587
74878
  }
74588
74879
  function errorInvalidInvariantId(invariantId) {
74589
74880
  return new MigrationToolsError("MIGRATION.INVALID_INVARIANT_ID", "Invalid invariantId", {
74590
74881
  why: `invariantId ${JSON.stringify(invariantId)} is invalid. Ids must be non-empty and contain no whitespace or control characters (including Unicode whitespace like NBSP); other content (kebab-case, camelCase, namespaced, Unicode letters) is allowed.`,
74591
74882
  fix: "Pick an invariantId without spaces, tabs, newlines, or control characters — e.g. \"backfill-user-phone\", \"users/backfill-phone\", or \"BackfillUserPhone\".",
74592
- details: { invariantId }
74883
+ meta: { invariantId }
74593
74884
  });
74594
74885
  }
74595
74886
  function errorDuplicateInvariantInEdge(invariantId) {
74596
74887
  return new MigrationToolsError("MIGRATION.DUPLICATE_INVARIANT_IN_EDGE", "Duplicate invariantId on a single migration", {
74597
74888
  why: `invariantId "${invariantId}" is declared by more than one dataTransform on the same migration. The marker stores invariants as a set and the routing layer treats them as edge-level, so two ops cannot share a routing identity.`,
74598
74889
  fix: "Rename one of the conflicting dataTransform invariantIds, or drop invariantId on the op that does not need to be routing-visible.",
74599
- details: { invariantId }
74890
+ meta: { invariantId }
74600
74891
  });
74601
74892
  }
74602
74893
  function errorProvidedInvariantsMismatch(filePath, stored, derived) {
@@ -74607,7 +74898,7 @@ function errorProvidedInvariantsMismatch(filePath, stored, derived) {
74607
74898
  return new MigrationToolsError("MIGRATION.PROVIDED_INVARIANTS_MISMATCH", "providedInvariants on migration.json disagrees with ops.json", {
74608
74899
  why: missing.length === 0 && extra.length === 0 ? `migration.json at "${filePath}" stores providedInvariants ${JSON.stringify(stored)}, but the canonical value derived from ops.json is ${JSON.stringify(derived)} — same ids, different order. Canonical providedInvariants is sorted ascending.` : `migration.json at "${filePath}" stores providedInvariants ${JSON.stringify(stored)}, but the value derived from ops.json is ${JSON.stringify(derived)}. The manifest copy was likely hand-edited without re-emitting.`,
74609
74900
  fix: reemitHint(dirname$1(filePath), "or restore the directory from version control."),
74610
- details: {
74901
+ meta: {
74611
74902
  filePath,
74612
74903
  stored,
74613
74904
  derived,
@@ -74625,7 +74916,7 @@ function errorNoInvariantPath(args) {
74625
74916
  return new MigrationToolsError("MIGRATION.NO_INVARIANT_PATH", "No path covers the required invariants", {
74626
74917
  why: `${refClause} requires invariants the reachable path doesn't cover. required=[${required.map((id) => JSON.stringify(id)).join(", ")}], missing=[${missingList}].`,
74627
74918
  fix: "Add a migration on the path that runs `dataTransform({ invariantId: \"<id>\", … })` for each missing invariant, or retarget the ref to a hash whose path already provides them.",
74628
- details: {
74919
+ meta: {
74629
74920
  required,
74630
74921
  missing,
74631
74922
  structuralPath,
@@ -74637,7 +74928,7 @@ function errorMigrationHashMismatch(dir, storedHash, computedHash) {
74637
74928
  return new MigrationToolsError("MIGRATION.HASH_MISMATCH", "Migration package is corrupt", {
74638
74929
  why: `Stored migrationHash "${storedHash}" does not match the recomputed hash "${computedHash}" for "${relative(process.cwd(), dir)}". The migration.json or ops.json has been edited or partially written since emit.`,
74639
74930
  fix: reemitHint(dir, "or restore the directory from version control."),
74640
- details: {
74931
+ meta: {
74641
74932
  dir,
74642
74933
  storedHash,
74643
74934
  computedHash
@@ -74653,8 +74944,24 @@ function errorMigrationHashMismatch(dir, storedHash, computedHash) {
74653
74944
  function errorRefNotResolvable(refName) {
74654
74945
  return new MigrationToolsError("MIGRATION.REF_NOT_RESOLVABLE", `Ref "${refName}" is not resolvable`, {
74655
74946
  why: `Ref "${refName}" has no pointer file, and the hash being resolved is not a node in the migration graph either — there is nothing to materialize a contract from.`,
74656
- fix: `Create the ref with "prisma-next ref set ${refName} <hash>" (or advance it via "prisma-next db update --advance-ref ${refName}"), or pass a hash that is a node in the migration graph.`,
74657
- details: {
74947
+ fix: `Create the ref with "prisma ref set ${refName} <hash>" (or advance it via "prisma db update --advance-ref ${refName}"), or pass a hash that is a node in the migration graph.`,
74948
+ nextActions: [
74949
+ {
74950
+ kind: "run-command",
74951
+ label: `Create the ref "${refName}"`,
74952
+ command: `{bin} ref set ${refName} <hash>`
74953
+ },
74954
+ {
74955
+ kind: "run-command",
74956
+ label: `Advance the ref "${refName}" as part of an update`,
74957
+ command: `{bin} db update --advance-ref ${refName}`
74958
+ },
74959
+ {
74960
+ kind: "user-choice",
74961
+ label: "Pass a hash that is already a node in the migration graph"
74962
+ }
74963
+ ],
74964
+ meta: {
74658
74965
  refName,
74659
74966
  identifier: refName
74660
74967
  }
@@ -74664,20 +74971,21 @@ function errorBundleNotFoundForGraphNode(hash, explicitLabel) {
74664
74971
  return new MigrationToolsError("MIGRATION.BUNDLE_NOT_FOUND_FOR_GRAPH_NODE", explicitLabel ? `No migration bundle found for reference "${explicitLabel}" (resolved hash: ${hash})` : `No migration bundle found for graph node ${hash}`, {
74665
74972
  why: `The hash ${hash} is a graph node but no on-disk migration package has a destination (\`to\`) hash matching it.`,
74666
74973
  fix: "Provide a ref or hash that corresponds to an existing migration package, or run `migration list` to see available migrations.",
74667
- details: {
74974
+ meta: {
74668
74975
  hash,
74669
74976
  ...explicitLabel ? { explicitLabel } : {}
74670
74977
  }
74671
74978
  });
74672
74979
  }
74673
- function errorContractDeserializationFailed(filePath, message) {
74980
+ function errorContractDeserializationFailed(filePath, message, options) {
74674
74981
  return new MigrationToolsError("MIGRATION.CONTRACT_DESERIALIZATION_FAILED", "Contract failed to deserialize", {
74675
74982
  why: `Contract at "${filePath}" failed to deserialize: ${message}`,
74676
74983
  fix: reemitHint(dirname$1(filePath), "or restore the directory from version control."),
74677
- details: {
74984
+ meta: {
74678
74985
  filePath,
74679
74986
  message
74680
- }
74987
+ },
74988
+ ...ifDefined("cause", options?.cause)
74681
74989
  });
74682
74990
  }
74683
74991
  function errorHashNotInGraph(hash, graph) {
@@ -74685,8 +74993,17 @@ function errorHashNotInGraph(hash, graph) {
74685
74993
  const reachableList = reachableHashes.length > 0 ? reachableHashes.join(", ") : "(none)";
74686
74994
  return new MigrationToolsError("MIGRATION.HASH_NOT_IN_GRAPH", `Hash "${hash}" is not a node in the migration graph`, {
74687
74995
  why: `The migration graph contains nodes ${reachableList}; "${hash}" isn't one of them.`,
74688
- fix: `Pass a hash that's the from-or-to of an on-disk migration bundle, use --from with a graph-node hash, or run "prisma-next migration plan" to introduce it.`,
74689
- details: {
74996
+ fix: `Pass a hash that's the from-or-to of an on-disk migration bundle, use --from with a graph-node hash, or run "prisma migration plan" to introduce it.`,
74997
+ nextActions: [{
74998
+ kind: "user-choice",
74999
+ label: "Pass a hash that is the from-or-to of an on-disk migration bundle, or use --from with a graph-node hash",
75000
+ reason: `Graph nodes: ${reachableList}.`
75001
+ }, {
75002
+ kind: "run-command",
75003
+ label: `Introduce "${hash}" by planning a migration for it`,
75004
+ command: "{bin} migration plan"
75005
+ }],
75006
+ meta: {
74690
75007
  hash,
74691
75008
  reachableHashes
74692
75009
  }
@@ -74695,8 +75012,23 @@ function errorHashNotInGraph(hash, graph) {
74695
75012
  function errorContractSnapshotMissing(storageHash, expectedPath) {
74696
75013
  return new MigrationToolsError("MIGRATION.CONTRACT_SNAPSHOT_MISSING", "Contract snapshot is missing", {
74697
75014
  why: `Expected a contract snapshot for ${storageHash} at "${expectedPath}" but the file does not exist.`,
74698
- fix: "Re-emit the contract snapshot by re-running the command that authored the migration referencing this hash (`prisma-next migration plan` for app-space migrations; the extension's contract-space build for extension spaces), or restore migrations/snapshots/ from version control.",
74699
- details: {
75015
+ fix: "Re-emit the contract snapshot by re-running the command that authored the migration referencing this hash (`prisma migration plan` for app-space migrations; the extension's contract-space build for extension spaces), or restore migrations/snapshots/ from version control.",
75016
+ nextActions: [
75017
+ {
75018
+ kind: "run-command",
75019
+ label: "Re-emit the snapshot for an app-space migration",
75020
+ command: "{bin} migration plan"
75021
+ },
75022
+ {
75023
+ kind: "user-choice",
75024
+ label: "For an extension space, re-run that extension's contract-space build instead"
75025
+ },
75026
+ {
75027
+ kind: "user-choice",
75028
+ label: "Restore migrations/snapshots/ from version control"
75029
+ }
75030
+ ],
75031
+ meta: {
74700
75032
  storageHash,
74701
75033
  expectedPath
74702
75034
  }
@@ -74706,7 +75038,7 @@ function errorContractSnapshotHashMismatch(storageHash, actualHash, dir) {
74706
75038
  return new MigrationToolsError("MIGRATION.CONTRACT_SNAPSHOT_HASH_MISMATCH", "Contract snapshot hash mismatch", {
74707
75039
  why: `The contract JSON's inner storage.storageHash ("${actualHash}") does not match the requested storage hash ("${storageHash}") for snapshot directory "${dir}".`,
74708
75040
  fix: "Pass a contractJson whose storage.storageHash equals the storageHash argument passed to writeContractSnapshot — the two must agree by construction.",
74709
- details: {
75041
+ meta: {
74710
75042
  storageHash,
74711
75043
  actualHash,
74712
75044
  dir
@@ -74717,14 +75049,13 @@ function errorMigrationContractViewMissing(className, accessor, jsonField) {
74717
75049
  return new MigrationToolsError("MIGRATION.CONTRACT_VIEW_MISSING", `${className}.${accessor} requires ${jsonField}`, {
74718
75050
  why: `${className}.${accessor} was read, but this instance has no ${jsonField} to build the view from.`,
74719
75051
  fix: `Set ${jsonField} to the migration's committed contract JSON, or avoid reading ${accessor} on a migration that overrides describe() and carries no contract.`,
74720
- details: {
75052
+ meta: {
74721
75053
  className,
74722
75054
  accessor,
74723
75055
  jsonField
74724
75056
  }
74725
75057
  });
74726
75058
  }
74727
- init_dist();
74728
75059
  const CONTRACT_JSON_FILE = "contract.json";
74729
75060
  const CONTRACT_DTS_FILE = "contract.d.ts";
74730
75061
  function hasErrnoCode$3(error, code) {
@@ -74942,7 +75273,6 @@ const MigrationOpsSchema = type({
74942
75273
  operationClass: "'additive' | 'widening' | 'destructive' | 'data'",
74943
75274
  "invariantId?": "string"
74944
75275
  }).array();
74945
- init_dist();
74946
75276
  const MANIFEST_FILE = "migration.json";
74947
75277
  const OPS_FILE = "ops.json";
74948
75278
  function hasErrnoCode$2(error, code) {
@@ -75178,14 +75508,14 @@ async function readMigrationsDir(migrationsRoot, options) {
75178
75508
  const dirName = entry;
75179
75509
  if (MigrationToolsError.is(error)) {
75180
75510
  if (error.code === "MIGRATION.HASH_MISMATCH") {
75181
- const details = error.details;
75511
+ const meta = error.meta;
75182
75512
  const rawPkg = await readMigrationPackageRaw(entryPath);
75183
75513
  if (rawPkg !== null) packages.push(rawPkg);
75184
75514
  problems.push({
75185
75515
  kind: "hashMismatch",
75186
75516
  dirName,
75187
- stored: typeof details?.["storedHash"] === "string" ? details["storedHash"] : "",
75188
- computed: typeof details?.["computedHash"] === "string" ? details["computedHash"] : ""
75517
+ stored: typeof meta?.["storedHash"] === "string" ? meta["storedHash"] : "",
75518
+ computed: typeof meta?.["computedHash"] === "string" ? meta["computedHash"] : ""
75189
75519
  });
75190
75520
  continue;
75191
75521
  }
@@ -75213,7 +75543,6 @@ async function readMigrationsDir(migrationsRoot, options) {
75213
75543
  problems
75214
75544
  };
75215
75545
  }
75216
- init_dist();
75217
75546
  /**
75218
75547
  * Pattern a contract-space identifier must match. The constraint is
75219
75548
  * filesystem-friendly: lowercase letters / digits / hyphen / underscore,
@@ -75709,7 +76038,6 @@ function invariantViableAlternativesAtStep(required, coverageBeforeTakingEdge, o
75709
76038
  if (required.size === 0) return [...outgoing];
75710
76039
  return outgoing.filter((e) => [...required].every((id) => coverageBeforeTakingEdge.has(id) || e.invariants.includes(id)));
75711
76040
  }
75712
- init_dist();
75713
76041
  /**
75714
76042
  * Assert that an extension descriptor is self-consistent: the
75715
76043
  * `headRef.hash` it publishes must match the canonical hash recomputed
@@ -75726,7 +76054,7 @@ init_dist();
75726
76054
  *
75727
76055
  * Synchronous, pure, no I/O. Throws
75728
76056
  * `MIGRATION.DESCRIPTOR_HEAD_HASH_MISMATCH` on failure with both the
75729
- * recomputed and published hashes in `details` so callers can surface a
76057
+ * recomputed and published hashes in `meta` so callers can surface a
75730
76058
  * clear remediation hint without re-deriving them.
75731
76059
  */
75732
76060
  function assertDescriptorSelfConsistency(inputs) {
@@ -76411,70 +76739,11 @@ function resolveColumnTypeMetadata$1(column, storageTypes) {
76411
76739
  };
76412
76740
  throw new InternalError(`Storage type "${column.typeRef}" has an unknown polymorphic kind; expected a codec-typed StorageTypeInstance.`);
76413
76741
  }
76414
- /**
76415
- * Resolves a `ValueSetRef` to its permitted values from the contract storage.
76416
- *
76417
- * Throws when the referenced namespace or value-set is absent — this indicates
76418
- * the contract was built incorrectly (the check and the value-set must be
76419
- * co-emitted by the lowering step). Used by `convertCheck` (schema-IR
76420
- * projection), `verifyCheckConstraints` (verification), and
76421
- * `checkConstraintPlanCallStrategy` (migration planning) so all three agree on
76422
- * the resolved values and the error behavior on a missing reference.
76423
- */
76424
- function allStrings(values) {
76425
- return values.every((value) => typeof value === "string");
76426
- }
76427
- function resolveValueSetValues(ref, storage, contextLabel) {
76428
- const ns = storage.namespaces[ref.namespaceId];
76429
- if (!ns) throw sqlFamilyError("CONTRACT.NAMESPACE_UNKNOWN", `resolveValueSetValues: namespace "${ref.namespaceId}" not found in storage (${contextLabel})`, {
76430
- why: "A value-set reference names a namespace the contract storage does not declare.",
76431
- fix: "Regenerate the contract from its authoring source; do not hand-edit contract JSON.",
76432
- meta: {
76433
- namespaceId: ref.namespaceId,
76434
- context: contextLabel
76435
- }
76436
- });
76437
- const valueSet = ns.entries.valueSet?.[ref.entityName];
76438
- if (!valueSet) throw sqlFamilyError("CONTRACT.ENUM_UNKNOWN", `resolveValueSetValues: value-set "${ref.entityName}" not found in namespace "${ref.namespaceId}" (${contextLabel})`, {
76439
- why: "A value-set reference names an entry its namespace does not declare.",
76440
- fix: "Regenerate the contract from its authoring source; do not hand-edit contract JSON.",
76441
- meta: {
76442
- valueSet: ref.entityName,
76443
- namespaceId: ref.namespaceId,
76444
- context: contextLabel
76445
- }
76446
- });
76447
- const values = valueSet.values;
76448
- if (!allStrings(values)) throw sqlFamilyError("CONTRACT.ENUM_INVALID", `resolveValueSetValues: value-set "${ref.entityName}" in namespace "${ref.namespaceId}" has a non-string value; numeric-enum CHECK constraints are not yet supported (${contextLabel})`, {
76449
- why: "Only string value-sets can be rendered as CHECK constraints; this value-set carries a non-string value.",
76450
- fix: "Use string enum values, or drop the CHECK-constrained enum until numeric enums are supported.",
76451
- meta: {
76452
- valueSet: ref.entityName,
76453
- namespaceId: ref.namespaceId,
76454
- context: contextLabel
76455
- }
76456
- });
76457
- return values;
76458
- }
76459
- /**
76460
- * Projects a `CheckConstraint` IR into an `SqlCheckConstraintIRInput` by
76461
- * resolving the permitted values from the storage value-set it references.
76462
- *
76463
- * The `CheckConstraint.valueSet` ref points to
76464
- * `storage.namespaces[namespaceId].entries.valueSet[name]`. The resolved
76465
- * values are lifted directly from `StorageValueSet.values` so verification
76466
- * compares value sets, not SQL predicate strings.
76467
- *
76468
- * Throws if the referenced namespace or value-set is absent — this
76469
- * indicates the contract was built incorrectly (the check and the
76470
- * value-set must be co-emitted by the lowering step).
76471
- */
76472
- function convertCheck(check, storage) {
76473
- const permittedValues = resolveValueSetValues(check.valueSet, storage, `check "${check.name}"`);
76742
+ function convertCheck(check, tableName, tableColumns) {
76474
76743
  return {
76475
- name: check.name,
76476
- column: check.column,
76477
- permittedValues
76744
+ naming: namingOf(check.name, check.prefix),
76745
+ expression: check.expression,
76746
+ dependsOn: flatColumnDependsOn(tableName, tableColumns)
76478
76747
  };
76479
76748
  }
76480
76749
  function convertUnique(unique, tableName) {
@@ -76572,7 +76841,7 @@ function convertForeignKey(fk, storage) {
76572
76841
  function convertTable(name, table, storageTypes, expandNativeType, renderDefault, resolveDefault, storage) {
76573
76842
  const columns = {};
76574
76843
  for (const [colName, colDef] of Object.entries(table.columns)) columns[colName] = convertColumn(colName, colDef, storageTypes, expandNativeType, renderDefault, resolveDefault);
76575
- const checks = table.checks && table.checks.length > 0 ? table.checks.map((c) => convertCheck(c, storage)) : void 0;
76844
+ const checks = table.checks && table.checks.length > 0 ? table.checks.map((c) => convertCheck(c, name, Object.keys(table.columns))) : void 0;
76576
76845
  return new SqlTableIR({
76577
76846
  name,
76578
76847
  columns,
@@ -76947,6 +77216,19 @@ function runnerFailure(code, summary, options) {
76947
77216
  Object.freeze({ allowedOperationClasses: Object.freeze(["additive"]) });
76948
77217
  var control_default = new SqlFamilyDescriptor();
76949
77218
  /**
77219
+ * Name of the synthesised namespace bucket the framework parser uses for
77220
+ * top-level declarations that appear outside any `namespace { … }` block.
77221
+ * The double-underscore decoration signals that the identifier is parser-
77222
+ * synthesised and never appears in user-authored PSL source — writing
77223
+ * `namespace __unspecified__ { … }` is a parse error.
77224
+ *
77225
+ * Distinct from the IR sentinel `__unbound__`: the PSL bucket describes
77226
+ * syntactic absence at the parser layer; the IR sentinel describes a late-
77227
+ * bound storage slot at the IR layer. Per-target interpreters decide how
77228
+ * (or whether) to map the PSL bucket to the IR sentinel.
77229
+ */
77230
+ const UNSPECIFIED_PSL_NAMESPACE_ID = "__unspecified__";
77231
+ /**
76950
77232
  * Stores `entries`; exposes `models`/`enums`/`compositeTypes` as getters over
76951
77233
  * it. The getters are prototype members (non-enumerable), so spreading or
76952
77234
  * `JSON.stringify`-ing a namespace copies only `entries`, never a duplicate view.
@@ -78193,6 +78475,10 @@ var PostgresControlDriver = class {
78193
78475
  throw normalizePgError(error);
78194
78476
  }
78195
78477
  }
78478
+ async databaseName() {
78479
+ const name = (await this.query("select current_database() as name")).rows[0]?.name;
78480
+ return typeof name === "string" && name.length > 0 ? name : void 0;
78481
+ }
78196
78482
  async close() {
78197
78483
  await this.client.end().catch(() => {});
78198
78484
  }
@@ -78216,18 +78502,53 @@ const postgresDriverDescriptor = {
78216
78502
  } catch {}
78217
78503
  const codeFromSqlState = SqlQueryError.is(normalized) ? normalized.sqlState : void 0;
78218
78504
  const causeCode = "cause" in normalized && normalized.cause ? normalized.cause.code : void 0;
78219
- const code = codeFromSqlState ?? causeCode;
78220
- throw errorRuntime("Database connection failed", {
78505
+ const sqlState = codeFromSqlState ?? causeCode;
78506
+ throw errorRuntime("DRIVER.CONNECTION_FAILED", "Database connection failed", {
78221
78507
  why: normalized.message,
78222
78508
  fix: "Verify the database URL, ensure the database is reachable, and confirm credentials/permissions",
78223
78509
  meta: {
78224
- ...ifDefined("code", code),
78510
+ ...ifDefined("sqlState", sqlState),
78225
78511
  ...redacted
78226
- }
78512
+ },
78513
+ cause: error
78227
78514
  });
78228
78515
  }
78229
78516
  }
78230
78517
  };
78518
+ /**
78519
+ * Renders the checks a Postgres column needs, as opaque predicate text.
78520
+ *
78521
+ * A text-backed domain enum has no type-level enforcement, so membership is a
78522
+ * predicate: `IN` for a scalar, and `<@` containment for an array — an array
78523
+ * column cannot use `IN` at all (`operator does not exist: text[] = text`),
78524
+ * and containment additionally rejects NULL elements. Every list column also
78525
+ * gets an element-non-null check, which no Postgres column type can express.
78526
+ *
78527
+ * The array side casts the COLUMN to `text[]` rather than assuming its element
78528
+ * type already is: `<@` needs both operands in one type, so a `varchar[]` or
78529
+ * `char[]` column meeting a bare `text[]` literal raises the same
78530
+ * `operator does not exist` this project exists to eliminate. The scalar `IN`
78531
+ * form needs no cast — `varchar = text` resolves on its own.
78532
+ */
78533
+ function postgresRenderCheckExpressions(input) {
78534
+ const candidates = [];
78535
+ const column = quoteIdentifier(input.columnName);
78536
+ if (input.memberValues !== void 0) {
78537
+ invariant(input.memberValues.length > 0, `check for "${input.tableName}"."${input.columnName}": empty member set; both authoring surfaces reject a member-less enum before rendering`);
78538
+ const members = input.memberValues.map((value) => `'${escapeLiteral(value)}'`).join(", ");
78539
+ candidates.push({
78540
+ kind: "membership",
78541
+ columnName: input.columnName,
78542
+ expression: input.many ? `${column}::text[] <@ ARRAY[${members}]::text[]` : `${column} IN (${members})`
78543
+ });
78544
+ }
78545
+ if (input.many) candidates.push({
78546
+ kind: "elementNotNull",
78547
+ columnName: input.columnName,
78548
+ expression: `array_position(${column}, NULL) IS NULL`
78549
+ });
78550
+ return candidates;
78551
+ }
78231
78552
  /** Postgres's default schema; `postgresTargetDescriptorMeta.defaultNamespaceId` is this value. */
78232
78553
  const DEFAULT_NAMESPACE_ID = "public";
78233
78554
  /**
@@ -78298,14 +78619,30 @@ const PSL_ROLE_BLOCK_OUTSIDE_UNBOUND_NAMESPACE = "PSL_ROLE_BLOCK_OUTSIDE_UNBOUND
78298
78619
  * descriptor's `columnFromEntity` hook (see `codecs.ts`) converts that
78299
78620
  * entity into the column's `typeParams` and native type.
78300
78621
  */
78301
- const postgresAuthoringTypes = { pg: { enum: {
78302
- kind: "typeConstructor",
78303
- entityRefArg: {
78304
- index: 0,
78305
- entityKind: "native_enum"
78622
+ const postgresAuthoringTypes = {
78623
+ BigIntNumber: {
78624
+ kind: "typeConstructor",
78625
+ output: {
78626
+ codecId: "pg/int8number@1",
78627
+ nativeType: "int8"
78628
+ }
78306
78629
  },
78307
- output: { codecId: PG_ENUM_CODEC_ID }
78308
- } } };
78630
+ UnboundedInt: {
78631
+ kind: "typeConstructor",
78632
+ output: {
78633
+ codecId: "pg/unboundedint@1",
78634
+ nativeType: "numeric"
78635
+ }
78636
+ },
78637
+ pg: { enum: {
78638
+ kind: "typeConstructor",
78639
+ entityRefArg: {
78640
+ index: 0,
78641
+ entityKind: "native_enum"
78642
+ },
78643
+ output: { codecId: PG_ENUM_CODEC_ID }
78644
+ } }
78645
+ };
78309
78646
  /**
78310
78647
  * Maps a `policy_<op>` keyword to the RLS operation it authors. The keyword
78311
78648
  * IS the operation (per the project's rejection of a `policy { operation = … }`
@@ -79042,6 +79379,7 @@ const postgresTargetDescriptorMeta = {
79042
79379
  modelAttributes: postgresAuthoringModelAttributes,
79043
79380
  createNamespace: postgresCreateNamespace,
79044
79381
  qualifyColumnType: postgresQualifyColumnType,
79382
+ renderCheckExpressions: postgresRenderCheckExpressions,
79045
79383
  lowerEntityHandles: postgresLowerEntityHandles
79046
79384
  }
79047
79385
  };
@@ -79651,9 +79989,8 @@ async function addForeignKey(schemaName, tableName, fk, lowerer) {
79651
79989
  postcheck: [step(`verify FK "${fk.name}" exists`, present.sql, present.params)]
79652
79990
  };
79653
79991
  }
79654
- async function addCheckConstraint(schemaName, tableName, constraintName, column, values, lowerer) {
79992
+ async function addCheckConstraint(schemaName, tableName, constraintName, expression, lowerer) {
79655
79993
  const qualified = qualifyTableName(schemaName, tableName);
79656
- const valueList = values.map((v) => `'${escapeLiteral(v)}'`).join(", ");
79657
79994
  const { absent, present } = await constraintCheckSteps(lowerer, {
79658
79995
  constraintName,
79659
79996
  schema: schemaName,
@@ -79661,14 +79998,36 @@ async function addCheckConstraint(schemaName, tableName, constraintName, column,
79661
79998
  });
79662
79999
  return {
79663
80000
  id: `checkConstraint.${tableName}.${constraintName}`,
79664
- label: `Add check constraint "${constraintName}" on "${tableName}"."${column}"`,
80001
+ label: `Add check constraint "${constraintName}" on "${tableName}"`,
79665
80002
  operationClass: "additive",
79666
80003
  target: targetDetails("checkConstraint", constraintName, schemaName, tableName),
79667
80004
  precheck: [step(`ensure constraint "${constraintName}" does not exist`, absent.sql, absent.params)],
79668
- execute: [step(`add check constraint "${constraintName}"`, `ALTER TABLE ${qualified} ADD CONSTRAINT ${quoteIdentifier(constraintName)} CHECK (${quoteIdentifier(column)} IN (${valueList}))`)],
80005
+ execute: [step(`add check constraint "${constraintName}"`, `ALTER TABLE ${qualified} ADD CONSTRAINT ${quoteIdentifier(constraintName)} CHECK (${expression})`)],
79669
80006
  postcheck: [step(`verify constraint "${constraintName}" exists`, present.sql, present.params)]
79670
80007
  };
79671
80008
  }
80009
+ async function renameCheckConstraint(schemaName, tableName, fromName, toName, lowerer) {
80010
+ const qualified = qualifyTableName(schemaName, tableName);
80011
+ const from = await constraintCheckSteps(lowerer, {
80012
+ constraintName: fromName,
80013
+ schema: schemaName,
80014
+ table: tableName
80015
+ });
80016
+ const to = await constraintCheckSteps(lowerer, {
80017
+ constraintName: toName,
80018
+ schema: schemaName,
80019
+ table: tableName
80020
+ });
80021
+ return {
80022
+ id: `checkConstraint.${schemaName}.${tableName}.${fromName}.rename`,
80023
+ label: `Rename check constraint "${fromName}" to "${toName}" on "${tableName}"`,
80024
+ operationClass: "widening",
80025
+ target: targetDetails("checkConstraint", toName, schemaName, tableName),
80026
+ precheck: [step(`ensure constraint "${fromName}" exists`, from.present.sql, from.present.params), step(`ensure constraint "${toName}" does not exist`, to.absent.sql, to.absent.params)],
80027
+ execute: [step(`rename check constraint "${fromName}" to "${toName}"`, `ALTER TABLE ${qualified} RENAME CONSTRAINT ${quoteIdentifier(fromName)} TO ${quoteIdentifier(toName)}`)],
80028
+ postcheck: [step(`verify constraint "${toName}" exists`, to.present.sql, to.present.params)]
80029
+ };
80030
+ }
79672
80031
  async function dropCheckConstraint(schemaName, tableName, constraintName, lowerer) {
79673
80032
  const qualified = qualifyTableName(schemaName, tableName);
79674
80033
  const { absent, present } = await constraintCheckSteps(lowerer, {
@@ -80750,31 +81109,63 @@ var DropConstraintCall = class extends PostgresOpFactoryCallNode {
80750
81109
  return [];
80751
81110
  }
80752
81111
  };
81112
+ var RenameCheckConstraintCall = class extends PostgresOpFactoryCallNode {
81113
+ factoryName = "renameCheckConstraint";
81114
+ operationClass = "widening";
81115
+ schemaName;
81116
+ tableName;
81117
+ oldConstraintName;
81118
+ newConstraintName;
81119
+ label;
81120
+ constructor(schemaName, tableName, oldConstraintName, newConstraintName) {
81121
+ super();
81122
+ this.schemaName = schemaName;
81123
+ this.tableName = tableName;
81124
+ this.oldConstraintName = oldConstraintName;
81125
+ this.newConstraintName = newConstraintName;
81126
+ this.label = `Rename check constraint "${oldConstraintName}" to "${newConstraintName}" on "${tableName}"`;
81127
+ this.freeze();
81128
+ }
81129
+ async toOp(lowerer) {
81130
+ if (lowerer === void 0) throw postgresError("MIGRATION.POSTGRES_CONTROL_STACK_MISSING", `RenameCheckConstraintCall.toOp: a lowerer is required on the Postgres planner path (constraint "${this.oldConstraintName}" on table "${this.tableName}"). Pass the control adapter to createPostgresMigrationPlanner.`, { meta: { factory: "RenameCheckConstraintCall" } });
81131
+ return renameCheckConstraint(this.schemaName, this.tableName, this.oldConstraintName, this.newConstraintName, lowerer);
81132
+ }
81133
+ renderTypeScript() {
81134
+ const opts = [];
81135
+ if (this.schemaName !== "__unbound__") opts.push(`schema: ${jsonToTsSource(this.schemaName)}`);
81136
+ opts.push(`table: ${jsonToTsSource(this.tableName)}`);
81137
+ opts.push(`from: ${jsonToTsSource(this.oldConstraintName)}`);
81138
+ opts.push(`to: ${jsonToTsSource(this.newConstraintName)}`);
81139
+ return `this.renameCheckConstraint({ ${opts.join(", ")} })`;
81140
+ }
81141
+ importRequirements() {
81142
+ return [];
81143
+ }
81144
+ };
80753
81145
  var AddCheckConstraintCall = class extends PostgresOpFactoryCallNode {
80754
81146
  factoryName = "addCheckConstraint";
80755
81147
  operationClass = "additive";
80756
81148
  schemaName;
80757
81149
  tableName;
80758
81150
  constraintName;
80759
- column;
80760
- values;
81151
+ /** Opaque SQL: the predicate body, rendered verbatim inside `CHECK (…)`. */
81152
+ expression;
80761
81153
  label;
80762
- constructor(schemaName, tableName, constraintName, column, values) {
81154
+ constructor(schemaName, tableName, constraintName, expression) {
80763
81155
  super();
80764
81156
  this.schemaName = schemaName;
80765
81157
  this.tableName = tableName;
80766
81158
  this.constraintName = constraintName;
80767
- this.column = column;
80768
- this.values = values;
80769
- this.label = `Add check constraint "${constraintName}" on "${tableName}"."${column}"`;
81159
+ this.expression = expression;
81160
+ this.label = `Add check constraint "${constraintName}" on "${tableName}"`;
80770
81161
  this.freeze();
80771
81162
  }
80772
81163
  async toOp(lowerer) {
80773
81164
  if (lowerer === void 0) throw postgresError("MIGRATION.POSTGRES_CONTROL_STACK_MISSING", `AddCheckConstraintCall.toOp: a lowerer is required on the Postgres planner path (constraint "${this.constraintName}" on table "${this.tableName}"). Pass the control adapter to createPostgresMigrationPlanner.`, { meta: { factory: "AddCheckConstraintCall" } });
80774
- return addCheckConstraint(this.schemaName, this.tableName, this.constraintName, this.column, this.values, lowerer);
81165
+ return addCheckConstraint(this.schemaName, this.tableName, this.constraintName, this.expression, lowerer);
80775
81166
  }
80776
81167
  renderTypeScript() {
80777
- return `this.addCheckConstraint({ ${constraintCallOptions(this.schemaName, this.tableName, this.constraintName)}, column: ${jsonToTsSource(this.column)}, values: ${jsonToTsSource(this.values)} })`;
81168
+ return `this.addCheckConstraint({ ${constraintCallOptions(this.schemaName, this.tableName, this.constraintName)}, expression: ${jsonToTsSource(this.expression)} })`;
80778
81169
  }
80779
81170
  importRequirements() {
80780
81171
  return [];
@@ -81542,21 +81933,6 @@ function tableAt(storage, namespaceId, tableName) {
81542
81933
  return ns.entries.table?.[tableName];
81543
81934
  }
81544
81935
  /**
81545
- * Resolve the DDL schema name for a namespace coordinate. Postgres-aware
81546
- * namespaces dispatch to their polymorphic `ddlSchemaName` override —
81547
- * named schemas return their own id; the unbound singleton returns
81548
- * `UNBOUND_NAMESPACE_ID`. Legacy single-namespace contracts whose
81549
- * `__unbound__` slot is the framework-default `SqlUnboundNamespace`
81550
- * (rather than the Postgres-aware `PostgresUnboundSchema`) flow the
81551
- * coordinate through unchanged so downstream `qualifyTableName`
81552
- * resolves polymorphically.
81553
- */
81554
- function resolveDdlSchemaForNamespace(ctx, namespaceId) {
81555
- const namespace = ctx.toContract.storage.namespaces[namespaceId];
81556
- if (isPostgresSchema(namespace)) return namespace.ddlSchemaName(ctx.toContract.storage);
81557
- return namespaceId;
81558
- }
81559
- /**
81560
81936
  * Recovers the contract namespace id for a DDL schema name embedded in a
81561
81937
  * diff-issue path (`path[1]`). The strategies need the CONTRACT column/table
81562
81938
  * (for codec-hook reads and eligibility probes the retained subsystems still
@@ -81709,90 +82085,6 @@ const nullableTighteningCallStrategy = (issues, ctx) => {
81709
82085
  };
81710
82086
  };
81711
82087
  /**
81712
- * Collects every check constraint from a table in the contract storage.
81713
- * Returns an empty array when the table has no checks or the table is absent.
81714
- */
81715
- function collectContractChecks(storage, namespaceId, tableName) {
81716
- const ns = storage.namespaces[namespaceId];
81717
- const tableRaw = ns !== void 0 ? ns.entries.table?.[tableName] : void 0;
81718
- if (!(tableRaw instanceof StorageTable)) return [];
81719
- const checks = tableRaw.checks;
81720
- if (!checks || checks.length === 0) return [];
81721
- return checks.map((c) => ({
81722
- name: c.name,
81723
- column: c.column,
81724
- permittedValues: resolveValueSetValues(c.valueSet, storage, `check "${c.name}" on "${tableName}"`)
81725
- }));
81726
- }
81727
- /**
81728
- * Compares two value arrays as unordered sets.
81729
- */
81730
- function checkValueSetsEqual(a, b) {
81731
- if (a.length !== b.length) return false;
81732
- const bSet = new Set(b);
81733
- return a.every((v) => bSet.has(v));
81734
- }
81735
- /**
81736
- * Plans check-constraint migrations for `enumType`-authored columns.
81737
- *
81738
- * Walks every namespace's tables in the target contract (the check nodes'
81739
- * resolved `permittedValues` are ultimately sourced from the same
81740
- * contract-declared value sets, so walking the contract directly is the
81741
- * simplest faithful port — the strategy's decisions never depend on which
81742
- * ISSUES happen to be in the input list, only on the contract + live schema
81743
- * shapes). For each table that carries `checks`, diffs the contract-expected
81744
- * checks against the live schema's checks:
81745
- *
81746
- * - Check in contract, absent from live DB → `AddCheckConstraintCall`.
81747
- * - Check in live DB, absent from contract → `DropCheckConstraintCall`.
81748
- * - Check on both sides but value sets differ → `DropCheckConstraintCall`
81749
- * then `AddCheckConstraintCall` (drop + recreate; a check predicate cannot
81750
- * be altered in place).
81751
- *
81752
- * Consumes every `sql-check-constraint` issue on a table this walk handles
81753
- * (not-found/not-expected/not-equal), leaving check issues on tables with
81754
- * NO contract checks to `mapNodeIssueToCall`'s `not-expected` fallback.
81755
- */
81756
- const checkConstraintPlanCallStrategy = (issues, ctx) => {
81757
- const calls = [];
81758
- const handledIssueKeys = /* @__PURE__ */ new Set();
81759
- for (const [namespaceId, ns] of Object.entries(ctx.toContract.storage.namespaces)) for (const tableName of Object.keys(ns.entries.table ?? {})) {
81760
- const contractChecks = collectContractChecks(ctx.toContract.storage, namespaceId, tableName);
81761
- if (contractChecks.length === 0) continue;
81762
- const liveChecks = ctx.schema.tables[tableName]?.checks ?? [];
81763
- const ddlSchema = resolveDdlSchemaForNamespace(ctx, namespaceId);
81764
- for (const contractCheck of contractChecks) {
81765
- const liveCheck = liveChecks.find((c) => c.name === contractCheck.name);
81766
- const issueKey = `${tableName} ${contractCheck.name}`;
81767
- if (!liveCheck) {
81768
- calls.push(new AddCheckConstraintCall(ddlSchema, tableName, contractCheck.name, contractCheck.column, contractCheck.permittedValues));
81769
- handledIssueKeys.add(issueKey);
81770
- } else if (!checkValueSetsEqual(contractCheck.permittedValues, liveCheck.permittedValues)) {
81771
- calls.push(new DropCheckConstraintCall(ddlSchema, tableName, contractCheck.name), new AddCheckConstraintCall(ddlSchema, tableName, contractCheck.name, contractCheck.column, contractCheck.permittedValues));
81772
- handledIssueKeys.add(issueKey);
81773
- } else handledIssueKeys.add(issueKey);
81774
- }
81775
- for (const liveCheck of liveChecks) if (!contractChecks.some((c) => c.name === liveCheck.name)) {
81776
- const issueKey = `${tableName} ${liveCheck.name}`;
81777
- calls.push(new DropCheckConstraintCall(ddlSchema, tableName, liveCheck.name));
81778
- handledIssueKeys.add(issueKey);
81779
- }
81780
- }
81781
- if (calls.length === 0 && handledIssueKeys.size === 0) return { kind: "no_match" };
81782
- return {
81783
- kind: "match",
81784
- issues: issues.filter((issue) => {
81785
- const node = issueNode(issue);
81786
- if (node === void 0 || node.nodeKind !== RelationalSchemaNodeKind.check) return true;
81787
- const tableName = issueTableName(issue);
81788
- if (tableName === void 0) return true;
81789
- const checkName = blindCast(node).name;
81790
- return !handledIssueKeys.has(`${tableName} ${checkName}`);
81791
- }),
81792
- calls
81793
- };
81794
- };
81795
- /**
81796
82088
  * Dispatches codec-typed storage types through their codec's
81797
82089
  * `planTypeOperations` hook (the authoritative source for codec-driven DDL
81798
82090
  * such as custom type creation). Codec extension/type ops are not modeled as
@@ -81938,28 +82230,9 @@ const postgresPlannerStrategies = [
81938
82230
  notNullBackfillCallStrategy,
81939
82231
  typeChangeCallStrategy,
81940
82232
  nullableTighteningCallStrategy,
81941
- checkConstraintPlanCallStrategy,
81942
82233
  storageTypePlanCallStrategy,
81943
82234
  notNullAddColumnCallStrategy
81944
82235
  ];
81945
- /**
81946
- * Deterministic name for the element-non-null CHECK constraint on a scalar-array
81947
- * column. Distinct `_elem_not_null` suffix avoids collision with the enum
81948
- * value-set `_check` constraints. Re-emitting the same schema produces the same
81949
- * name, so `pg_get_constraintdef`-based verify sees no drift.
81950
- */
81951
- function elementNonNullCheckName(tableName, columnName) {
81952
- return `${tableName}_${columnName}_elem_not_null`;
81953
- }
81954
- /**
81955
- * Predicate enforcing that a scalar-array column carries no NULL element. The
81956
- * array column itself may be NULL (container nullability is the column's NOT NULL
81957
- * clause); `array_position` over a NULL array yields NULL, which a CHECK treats
81958
- * as satisfied, so a nullable array column is unaffected.
81959
- */
81960
- function elementNonNullCheckExpression(columnName) {
81961
- return `array_position(${quoteIdentifier(columnName)}, NULL) IS NULL`;
81962
- }
81963
82236
  function issueConflict(kind, summary, location) {
81964
82237
  return {
81965
82238
  kind,
@@ -81994,7 +82267,8 @@ function classifyCall(call) {
81994
82267
  case "dropCheckConstraint":
81995
82268
  case "dropIndex":
81996
82269
  case "dropDefault": return "drop";
81997
- case "addCheckConstraint": return "unique";
82270
+ case "addCheckConstraint":
82271
+ case "renameCheckConstraint": return "unique";
81998
82272
  case "createTable": return "table";
81999
82273
  case "enableRowLevelSecurity":
82000
82274
  case "disableRowLevelSecurity": return "rlsEnable";
@@ -82055,6 +82329,7 @@ function locationForCall(call) {
82055
82329
  if (anyCall.indexName) location.index = anyCall.indexName;
82056
82330
  else if (anyCall.newIndexName) location.index = anyCall.newIndexName;
82057
82331
  if (anyCall.constraintName) location.constraint = anyCall.constraintName;
82332
+ else if (anyCall.newConstraintName) location.constraint = anyCall.newConstraintName;
82058
82333
  if (anyCall.policyName) location.rlsPolicy = anyCall.policyName;
82059
82334
  else if (anyCall.policy?.name) location.rlsPolicy = anyCall.policy.name;
82060
82335
  else if (anyCall.newPolicyName) location.rlsPolicy = anyCall.newPolicyName;
@@ -82105,17 +82380,6 @@ function issueColumnName(issue) {
82105
82380
  function emissionSchemaName(ctx, ddlSchemaName) {
82106
82381
  return resolveNamespaceIdForDdlSchema(ctx.toContract, ddlSchemaName) === "__unbound__" ? UNBOUND_NAMESPACE_ID : ddlSchemaName;
82107
82382
  }
82108
- /**
82109
- * Whether a column node is a scalar-array (`many: true`) column. The family
82110
- * converter (`contractToSchemaIR`'s `convertColumn`) never stamps `many` on
82111
- * the derived node — array-ness is folded into the `[]` suffix on
82112
- * `nativeType` instead — so the node-derived check reads the suffix; `.many`
82113
- * is still checked first for nodes a caller stamps directly (e.g. hand-built
82114
- * test fixtures, or an adapter that populates it at introspection).
82115
- */
82116
- function isManyColumn(column) {
82117
- return column.many === true || column.nativeType.endsWith("[]");
82118
- }
82119
82383
  /** Whether the expected/actual native type (resolved, or raw+many fallback) differs — mirrors `SqlColumnIR.isEqualTo`'s type comparison. */
82120
82384
  function columnTypeChanged(expected, actual) {
82121
82385
  if (expected.resolvedNativeType !== void 0 && actual.resolvedNativeType !== void 0) return expected.resolvedNativeType !== actual.resolvedNativeType;
@@ -82156,7 +82420,7 @@ function fkSpecFromNode(fk, tableName) {
82156
82420
  /**
82157
82421
  * Builds the `CreateTable` + child `CreateIndex` / `AddForeignKey` / `AddUnique`
82158
82422
  * calls for a newly-expected table, reading only the table node's children. The
82159
- * PK and element-non-null CHECKs go inline as table constraints; indexes
82423
+ * PK and every declared CHECK go inline as table constraints; indexes
82160
82424
  * (declared + FK-backing, already merged and ordered at derivation) and the
82161
82425
  * FK / unique constraints are separate calls (re-bucketed downstream). Every
82162
82426
  * column's DDL is resolved from its `codecRef` via `renderColumnDdl`.
@@ -82164,8 +82428,8 @@ function fkSpecFromNode(fk, tableName) {
82164
82428
  function buildCreateTableCallsFromNode(schemaName, ddlSchemaName, table, codecHooks) {
82165
82429
  const ddlColumns = Object.values(table.columns).map((c) => renderColumnDdl(c.name, c, codecHooks));
82166
82430
  const primaryKeyConstraints = table.primaryKey ? [primaryKey([...table.primaryKey.columns], { ...ifDefined("name", table.primaryKey.name) })] : [];
82167
- const elementNonNullChecks = Object.values(table.columns).filter((c) => isManyColumn(c)).map((c) => checkExpression(elementNonNullCheckName(table.name, c.name), elementNonNullCheckExpression(c.name)));
82168
- const allTableConstraints = [...primaryKeyConstraints, ...elementNonNullChecks];
82431
+ const declaredChecks = (table.checks ?? []).map((c) => checkExpression(c.name, c.expression));
82432
+ const allTableConstraints = [...primaryKeyConstraints, ...declaredChecks];
82169
82433
  const calls = [new CreateTableCall(schemaName, table.name, ddlColumns, allTableConstraints.length > 0 ? allTableConstraints : void 0)];
82170
82434
  for (const index of table.indexes) calls.push(createIndexCallFromNode(index, schemaName, table.name));
82171
82435
  for (const fk of table.foreignKeys) calls.push(new AddForeignKeyCall(schemaName, table.name, fkSpecFromNode(fk, table.name)));
@@ -82307,9 +82571,20 @@ function mapIndexNodeIssue(issue, schemaName, tableName) {
82307
82571
  if (issueOutcome(issue) === "not-expected") return ok$1([new DropIndexCall(schemaName, tableName, blindCast(issue.actual).name)]);
82308
82572
  return notOk(nodeConflict("indexIncompatible", issue.path.join("/")));
82309
82573
  }
82574
+ /**
82575
+ * The index treatment: a missing check is added, an undeclared live check is
82576
+ * dropped, and a paired divergence is a conflict. `not-equal` is reachable only
82577
+ * for an exact-named expected check — a wire-named one compares by name, so a
82578
+ * changed predicate re-suffixes the name and arrives as missing + extra
82579
+ * instead.
82580
+ */
82310
82581
  function mapCheckNodeIssue(issue, schemaName, tableName) {
82582
+ if (issueOutcome(issue) === "not-found") {
82583
+ const check = blindCast(issue.expected);
82584
+ return ok$1([new AddCheckConstraintCall(schemaName, tableName, check.name, check.expression)]);
82585
+ }
82311
82586
  if (issueOutcome(issue) === "not-expected") return ok$1([new DropCheckConstraintCall(schemaName, tableName, blindCast(issue.actual).name)]);
82312
- return notOk(nodeConflict("unsupportedOperation", `Check constraint drift on "${tableName}" — handled by checkConstraintPlanCallStrategy: ${issue.path.join("/")}`));
82587
+ return notOk(nodeConflict("unsupportedOperation", issue.path.join("/")));
82313
82588
  }
82314
82589
  /**
82315
82590
  * Maps one node-typed diff issue to its migration call(s), dispatching on the
@@ -83554,7 +83829,10 @@ var PostgresMigration = class extends SqlMigration {
83554
83829
  return new AddForeignKeyCall(options.schema, options.table, options.foreignKey).toOp(this.controlAdapterFor("addForeignKey"));
83555
83830
  }
83556
83831
  addCheckConstraint(options) {
83557
- return new AddCheckConstraintCall(options.schema, options.table, options.constraint, options.column, options.values).toOp(this.controlAdapterFor("addCheckConstraint"));
83832
+ return new AddCheckConstraintCall(options.schema, options.table, options.constraint, options.expression).toOp(this.controlAdapterFor("addCheckConstraint"));
83833
+ }
83834
+ renameCheckConstraint(options) {
83835
+ return new RenameCheckConstraintCall(options.schema ?? "__unbound__", options.table, options.from, options.to).toOp(this.controlAdapterFor("renameCheckConstraint"));
83558
83836
  }
83559
83837
  dropCheckConstraint(options) {
83560
83838
  return new DropCheckConstraintCall(options.schema, options.table, options.constraint).toOp(this.controlAdapterFor("dropCheckConstraint"));
@@ -214683,7 +214961,7 @@ function shebangLineFor(runtime) {
214683
214961
  * to `'postgres'`, so user-authored migrations don't need to thread
214684
214962
  * target-details or redeclare `targetId`.
214685
214963
  * - `MigrationCLI` — the migration-file CLI entrypoint, re-exported from
214686
- * `@internal/cli/migration-cli`. Loads `prisma-next.config.ts`,
214964
+ * `@internal/cli/migration-cli`. Loads `prisma.config.ts`,
214687
214965
  * assembles a `ControlStack`, and instantiates the migration class.
214688
214966
  * The migration file owns this dependency directly: pulling CLI
214689
214967
  * machinery in at script run time is acceptable because the script's
@@ -214945,7 +215223,9 @@ var PostgresMigrationPlanner = class {
214945
215223
  schema: options.schema
214946
215224
  }), ...gated];
214947
215225
  const indexRenames = this.pairIndexRenames(options, schemaIssues);
214948
- const plannableIssues = indexRenames.consumed.size === 0 ? schemaIssues : schemaIssues.filter((issue) => !indexRenames.consumed.has(issue));
215226
+ const checkRenames = this.pairCheckRenames(options, schemaIssues);
215227
+ const renameConsumed = /* @__PURE__ */ new Set([...indexRenames.consumed, ...checkRenames.consumed]);
215228
+ const plannableIssues = renameConsumed.size === 0 ? schemaIssues : schemaIssues.filter((issue) => !renameConsumed.has(issue));
214949
215229
  const codecHooks = extractCodecControlHooks(options.frameworkComponents);
214950
215230
  const storageTypes = options.contract.storage.types ?? {};
214951
215231
  const relationalSchema = relationalNamespaceNode(options.schema, schemaName);
@@ -214970,7 +215250,7 @@ var PostgresMigrationPlanner = class {
214970
215250
  const schemaDiff = this.planPostgresSchemaDiff(options, policyDiffIssues);
214971
215251
  if (!result.ok || schemaDiff.conflicts.length > 0) return plannerFailure([...result.ok ? [] : result.failure, ...schemaDiff.conflicts]);
214972
215252
  const indexRenamePartition = partitionCallsByControlPolicy({
214973
- calls: indexRenames.calls,
215253
+ calls: [...indexRenames.calls, ...checkRenames.calls],
214974
215254
  contract: options.contract,
214975
215255
  resolveControlPolicySubject: (call) => resolvePostgresCallControlPolicySubject(call, options.contract),
214976
215256
  resolveFactoryName: (call) => call.factoryName
@@ -215078,11 +215358,101 @@ var PostgresMigrationPlanner = class {
215078
215358
  finding.tableName,
215079
215359
  hash
215080
215360
  ]);
215081
- const rename = (missingFinding, candidate) => {
215082
- consumed.add(missingFinding.issue);
215083
- consumed.add(candidate.issue);
215084
- calls.push(new RenameIndexCall(emissionSchema(missingFinding.ddlSchema), missingFinding.tableName, candidate.node.name, missingFinding.node.name));
215085
- };
215361
+ const rename = (missingFinding, candidate) => {
215362
+ consumed.add(missingFinding.issue);
215363
+ consumed.add(candidate.issue);
215364
+ calls.push(new RenameIndexCall(emissionSchema(missingFinding.ddlSchema), missingFinding.tableName, candidate.node.name, missingFinding.node.name));
215365
+ };
215366
+ const sortedMissing = [...missing].sort(byName);
215367
+ const extrasByHash = /* @__PURE__ */ new Map();
215368
+ for (const finding of extra) {
215369
+ const parsed = parseWireName(finding.node.name);
215370
+ if (parsed === void 0) continue;
215371
+ const key = pairingKey(finding, parsed.hash);
215372
+ const group = extrasByHash.get(key) ?? [];
215373
+ group.push(finding);
215374
+ extrasByHash.set(key, group);
215375
+ }
215376
+ for (const group of extrasByHash.values()) group.sort(byName);
215377
+ for (const missingFinding of sortedMissing) {
215378
+ const parsed = parseWireName(missingFinding.node.name);
215379
+ if (parsed === void 0) continue;
215380
+ const candidate = extrasByHash.get(pairingKey(missingFinding, parsed.hash))?.shift();
215381
+ if (candidate === void 0) continue;
215382
+ rename(missingFinding, candidate);
215383
+ }
215384
+ const sortedExtras = [...extra].sort(byName);
215385
+ for (const missingFinding of sortedMissing) {
215386
+ if (consumed.has(missingFinding.issue)) continue;
215387
+ if (missingFinding.node.prefix === void 0) continue;
215388
+ const candidate = sortedExtras.find((extraFinding) => !consumed.has(extraFinding.issue) && extraFinding.ddlSchema === missingFinding.ddlSchema && extraFinding.tableName === missingFinding.tableName && missingFinding.node.contentEquals(extraFinding.node, {
215389
+ columnPresence: "matching",
215390
+ bodies: "verbatim"
215391
+ }));
215392
+ if (candidate === void 0) continue;
215393
+ rename(missingFinding, candidate);
215394
+ }
215395
+ return {
215396
+ calls,
215397
+ consumed
215398
+ };
215399
+ }
215400
+ /**
215401
+ * Check-constraint rename post-pass: a `not-found` and a `not-expected`
215402
+ * check on the same table whose wire-name content hashes match but whose
215403
+ * prefixes differ is a prefix-only rename, and collapses into one
215404
+ * `ALTER TABLE … RENAME CONSTRAINT`.
215405
+ *
215406
+ * This is the index pass's hash-pairing phase and nothing else. There is
215407
+ * deliberately no content-pairing phase: a live check body is whatever
215408
+ * Postgres reprinted, so it never byte-matches the authored text, and
215409
+ * pairing an exact-named live check by content would bless whatever
215410
+ * predicate is actually live. Adoption of an old exact-named check stays
215411
+ * drop + add.
215412
+ *
215413
+ * Runs only when the policy allows `widening` (rename's class). Without it
215414
+ * the pass no-ops and the pair degrades to the slice-1 behavior: an add,
215415
+ * plus a drop when `destructive` is allowed too.
215416
+ */
215417
+ pairCheckRenames(options, issues) {
215418
+ const consumed = /* @__PURE__ */ new Set();
215419
+ const calls = [];
215420
+ if (!options.policy.allowedOperationClasses.includes("widening")) return {
215421
+ calls,
215422
+ consumed
215423
+ };
215424
+ const missing = [];
215425
+ const extra = [];
215426
+ for (const issue of issues) {
215427
+ const node = issueNode(issue);
215428
+ if (node === void 0 || !SqlCheckConstraintIR.is(node)) continue;
215429
+ const ddlSchema = issue.path[1];
215430
+ const tableName = issue.path[2];
215431
+ if (ddlSchema === void 0 || tableName === void 0) continue;
215432
+ if (issueOutcome(issue) === "not-found") missing.push({
215433
+ issue,
215434
+ node,
215435
+ ddlSchema,
215436
+ tableName
215437
+ });
215438
+ else if (issueOutcome(issue) === "not-expected") extra.push({
215439
+ issue,
215440
+ node,
215441
+ ddlSchema,
215442
+ tableName
215443
+ });
215444
+ }
215445
+ if (missing.length === 0 || extra.length === 0) return {
215446
+ calls,
215447
+ consumed
215448
+ };
215449
+ const byName = (a, b) => a.node.name < b.node.name ? -1 : a.node.name > b.node.name ? 1 : 0;
215450
+ const emissionSchema = (ddlSchema) => resolveNamespaceIdForDdlSchema(options.contract, ddlSchema) === "__unbound__" ? UNBOUND_NAMESPACE_ID : ddlSchema;
215451
+ const pairingKey = (finding, hash) => JSON.stringify([
215452
+ finding.ddlSchema,
215453
+ finding.tableName,
215454
+ hash
215455
+ ]);
215086
215456
  const sortedMissing = [...missing].sort(byName);
215087
215457
  const extrasByHash = /* @__PURE__ */ new Map();
215088
215458
  for (const finding of extra) {
@@ -215099,18 +215469,9 @@ var PostgresMigrationPlanner = class {
215099
215469
  if (parsed === void 0) continue;
215100
215470
  const candidate = extrasByHash.get(pairingKey(missingFinding, parsed.hash))?.shift();
215101
215471
  if (candidate === void 0) continue;
215102
- rename(missingFinding, candidate);
215103
- }
215104
- const sortedExtras = [...extra].sort(byName);
215105
- for (const missingFinding of sortedMissing) {
215106
- if (consumed.has(missingFinding.issue)) continue;
215107
- if (missingFinding.node.prefix === void 0) continue;
215108
- const candidate = sortedExtras.find((extraFinding) => !consumed.has(extraFinding.issue) && extraFinding.ddlSchema === missingFinding.ddlSchema && extraFinding.tableName === missingFinding.tableName && missingFinding.node.contentEquals(extraFinding.node, {
215109
- columnPresence: "matching",
215110
- bodies: "verbatim"
215111
- }));
215112
- if (candidate === void 0) continue;
215113
- rename(missingFinding, candidate);
215472
+ consumed.add(missingFinding.issue);
215473
+ consumed.add(candidate.issue);
215474
+ calls.push(new RenameCheckConstraintCall(emissionSchema(missingFinding.ddlSchema), missingFinding.tableName, candidate.node.name, missingFinding.node.name));
215114
215475
  }
215115
215476
  return {
215116
215477
  calls,
@@ -216945,6 +217306,20 @@ function buildIndexAttribute(index, fieldNames) {
216945
217306
  }
216946
217307
  return buildAttribute("model", "index", args);
216947
217308
  }
217309
+ /**
217310
+ * Emits one `@@check` attribute for a live, non-derived check, always in the
217311
+ * `map:` form. Re-detecting `name:` is not attempted: the live expression is
217312
+ * Postgres's own reprint, but a wire-named check's hash was taken over the
217313
+ * author's original text, so recomputing the hash from the reprint would
217314
+ * essentially never match. `map:` plus the verbatim reprint is correct
217315
+ * regardless — a reprint compared against a later reprint of the same
217316
+ * expression is stable, so the emitted contract signs the live database with
217317
+ * zero pending operations. `buildPolicyBlocks` makes the same call for
217318
+ * `@@map` on adopted RLS policies, for the same reason.
217319
+ */
217320
+ function buildCheckAttribute(check) {
217321
+ return buildAttribute("model", "check", [namedArg("expression", `"${escapePslString(check.expression)}"`), namedArg("map", `"${escapePslString(check.name)}"`)]);
217322
+ }
216948
217323
  function buildModel(table, typeMap, enumNameMap, fieldNamesByTable, defaultMapping, rawDefaultParser, relationFields, danglingForeignKeys, rlsEnabled = false, policySkipNotes = []) {
216949
217324
  const { name: modelName, map: mapName } = toModelName(table.name);
216950
217325
  const fieldNameMap = fieldNamesByTable.get(table.name);
@@ -216957,8 +217332,9 @@ function buildModel(table, typeMap, enumNameMap, fieldNamesByTable, defaultMappi
216957
217332
  const existingConstraintName = uniqueColumns.get(columnName);
216958
217333
  if (!uniqueColumns.has(columnName) || existingConstraintName === void 0 && unique.name) uniqueColumns.set(columnName, unique.name);
216959
217334
  }
217335
+ const derivedCheckNames = computeDerivedCheckNames(table);
216960
217336
  const fields = [];
216961
- for (const column of Object.values(table.columns)) fields.push(buildScalarField(column, table, typeMap, enumNameMap, fieldNameMap, defaultMapping, rawDefaultParser, pkColumns, isSinglePk, singlePkConstraintName, uniqueColumns));
217337
+ for (const column of Object.values(table.columns)) fields.push(buildScalarField(column, table, typeMap, enumNameMap, fieldNameMap, defaultMapping, rawDefaultParser, pkColumns, isSinglePk, singlePkConstraintName, uniqueColumns, derivedCheckNames));
216962
217338
  const usedFieldNames = new Set(fields.map((field) => field.name));
216963
217339
  for (const rel of relationFields) fields.push(buildRelationField(rel, table.name, fieldNamesByTable, usedFieldNames));
216964
217340
  const modelAttributes = [];
@@ -216974,6 +217350,7 @@ function buildModel(table, typeMap, enumNameMap, fieldNamesByTable, defaultMappi
216974
217350
  const indexFieldNames = index.columns?.map((columnName) => resolveColumnFieldName(fieldNamesByTable, table.name, columnName));
216975
217351
  modelAttributes.push(buildIndexAttribute(index, indexFieldNames));
216976
217352
  }
217353
+ for (const check of table.checks ?? []) if (!derivedCheckNames.has(check.name)) modelAttributes.push(buildCheckAttribute(check));
216977
217354
  if (mapName) modelAttributes.push(buildMapAttribute("model", mapName));
216978
217355
  if (rlsEnabled) modelAttributes.push(buildAttribute("model", "rls", []));
216979
217356
  const warnings = [];
@@ -216990,7 +217367,35 @@ function buildModel(table, typeMap, enumNameMap, fieldNamesByTable, defaultMappi
216990
217367
  ...comment !== void 0 ? { comment } : {}
216991
217368
  };
216992
217369
  }
216993
- function buildScalarField(column, table, typeMap, enumNameMap, fieldNameMap, defaultMapping, rawDefaultParser, pkColumns, isSinglePk, singlePkConstraintName, uniqueColumns) {
217370
+ /**
217371
+ * The live check names that are derived: a live check's name matches
217372
+ * `formatWireName(composeCheckWirePrefix(table, column, kind), computeCheckContentHash(expression))`
217373
+ * for some column of the table and some candidate `postgresRenderCheckExpressions`
217374
+ * would render for that column. Never by comparing expressions — the live
217375
+ * body is a Postgres reprint, never the authored text. One set serves both
217376
+ * the `@noCheck` waiver below and `@@check` exclusion in `buildModel`, so the
217377
+ * two decisions cannot drift apart.
217378
+ *
217379
+ * `membership` is unreachable here today: infer never emits domain enums
217380
+ * (`enumType()` is not inferred), so no inferred column has member values and
217381
+ * no membership check is ever derived. The day domain-enum inference exists,
217382
+ * its slice extends this by threading the column's member values through.
217383
+ */
217384
+ function computeDerivedCheckNames(table) {
217385
+ const liveCheckNames = new Set((table.checks ?? []).map((check) => check.name));
217386
+ const derivedCheckNames = /* @__PURE__ */ new Set();
217387
+ for (const column of Object.values(table.columns)) for (const candidate of postgresRenderCheckExpressions({
217388
+ tableName: table.name,
217389
+ columnName: column.name,
217390
+ many: column.many === true,
217391
+ memberValues: void 0
217392
+ })) {
217393
+ const derivedName = formatWireName(composeCheckWirePrefix(table.name, column.name, candidate.kind), computeCheckContentHash(candidate.expression));
217394
+ if (liveCheckNames.has(derivedName)) derivedCheckNames.add(derivedName);
217395
+ }
217396
+ return derivedCheckNames;
217397
+ }
217398
+ function buildScalarField(column, table, typeMap, enumNameMap, fieldNameMap, defaultMapping, rawDefaultParser, pkColumns, isSinglePk, singlePkConstraintName, uniqueColumns, derivedCheckNames) {
216994
217399
  const resolvedField = fieldNameMap?.get(column.name);
216995
217400
  const fieldName = resolvedField?.fieldName ?? toFieldName(column.name).name;
216996
217401
  const fieldMap = resolvedField?.fieldMap;
@@ -217043,6 +217448,15 @@ function buildScalarField(column, table, typeMap, enumNameMap, fieldNameMap, def
217043
217448
  const uniqueConstraintName = uniqueColumns.get(column.name);
217044
217449
  attributes.push(buildSimpleConstraintFieldAttribute("unique", uniqueConstraintName));
217045
217450
  }
217451
+ if (column.many === true) {
217452
+ const waivedKinds = postgresRenderCheckExpressions({
217453
+ tableName: table.name,
217454
+ columnName: column.name,
217455
+ many: true,
217456
+ memberValues: void 0
217457
+ }).filter((candidate) => !derivedCheckNames.has(formatWireName(composeCheckWirePrefix(table.name, column.name, candidate.kind), computeCheckContentHash(candidate.expression)))).map((candidate) => candidate.kind);
217458
+ if (waivedKinds.length > 0) attributes.push(buildAttribute("field", "noCheck", waivedKinds.map(positionalArg)));
217459
+ }
217046
217460
  if (fieldMap !== void 0) attributes.push(buildMapAttribute("field", fieldMap));
217047
217461
  return {
217048
217462
  kind: "field",
@@ -217299,11 +217713,15 @@ function createPostgresTypeMap(enumTypeNames) {
217299
217713
  * Relation inference, name transforms, generic default mapping, and raw-default
217300
217714
  * parsing are shape-neutral utilities imported from the SQL family.
217301
217715
  *
217302
- * This slice emits relational-only PSL, byte-identical to the prior flat
217303
- * inference: the tree's tables (across its namespaces `contract infer`
217304
- * introspects a single live namespace) are gathered into the model set and
217305
- * emitted as one `UNSPECIFIED_PSL_NAMESPACE_ID` bucket. Top-level entities
217306
- * (policies/roles PSL extension blocks) are a later slice.
217716
+ * The tree's tables (across its namespaces `contract infer` introspects a
217717
+ * single live namespace) are gathered into the model set and emitted in one
217718
+ * bucket, alongside native-enum and RLS policy blocks. That bucket is named
217719
+ * after the introspected schema when the content needs a `namespace { }`
217720
+ * wrap, and is the flat `UNSPECIFIED_PSL_NAMESPACE_ID` bucket otherwise. This
217721
+ * entry point emits nothing else, so its output is always exactly one bucket
217722
+ * and byte-identical to the prior flat inference. {@link buildPslDocumentAst}
217723
+ * can emit a second, always-flat bucket for content that must stay top-level
217724
+ * even under a wrap; no caller asks for one yet.
217307
217725
  *
217308
217726
  * `describedContracts` — the stack's extension packs' already-assembled
217309
217727
  * contracts, each paired with its space id — is consulted while gathering
@@ -217391,7 +217809,24 @@ function inferPostgresPslContract(tree, describedContracts) {
217391
217809
  policiesByTable
217392
217810
  });
217393
217811
  }
217394
- function buildPslDocumentAst(schemaIR, options, foreignKeyExtras, namespaceName, rlsExtras) {
217812
+ /**
217813
+ * Builds the PSL document for one introspected schema.
217814
+ *
217815
+ * `namespaceName` wraps the output in `namespace <name> { … }`; omit it for
217816
+ * flat output. `topLevelExtensionBlocks` are declarations that must stay
217817
+ * top-level even when a wrap applies, such as a recovered domain enum — a
217818
+ * family `enum` inside a namespace is a hard diagnostic. They land in their
217819
+ * own always-flat bucket when a wrap applies, and in the single flat bucket
217820
+ * when none does; either way they print unwrapped.
217821
+ *
217822
+ * Their names are reserved before the policy blocks are built, so a policy
217823
+ * renames itself out of the way. Against the rest of the top-level scope — the
217824
+ * models, the native enums, PSL's scalar type names, and the other blocks in
217825
+ * the list — a clash throws instead: a block's name is its contract key
217826
+ * (`entries.valueSet[name]`, with no `@@map` escape), so it cannot be rewritten
217827
+ * here.
217828
+ */
217829
+ function buildPslDocumentAst(schemaIR, options, foreignKeyExtras, namespaceName, rlsExtras, topLevelExtensionBlocks = []) {
217395
217830
  const { typeMap, defaultMapping, parseRawDefault: rawDefaultParser } = options;
217396
217831
  const { extraRelationsByTable, crossSpaceFieldNamesByTable, danglingForeignKeysByTable } = foreignKeyExtras;
217397
217832
  const modelNames = buildTopLevelNameMap(Object.keys(schemaIR.tables), toModelName, "model", "table");
@@ -217401,19 +217836,48 @@ function buildPslDocumentAst(schemaIR, options, foreignKeyExtras, namespaceName,
217401
217836
  if (namespaceName !== void 0) for (const [typeName, pslName] of bareEnumNameMap) enumNameMap.set(`${namespaceName}.${typeName}`, pslName);
217402
217837
  const fieldNamesByTable = new Map([...crossSpaceFieldNamesByTable, ...buildFieldNamesByTable(schemaIR.tables)]);
217403
217838
  const { relationsByTable } = inferRelations(schemaIR.tables, modelNameMap);
217404
- const policyEmission = buildPolicyBlocks(rlsExtras?.policiesByTable ?? /* @__PURE__ */ new Map(), modelNameMap, /* @__PURE__ */ new Set([...modelNameMap.values(), ...bareEnumNameMap.values()]));
217839
+ const policyEmission = buildPolicyBlocks(rlsExtras?.policiesByTable ?? /* @__PURE__ */ new Map(), modelNameMap, /* @__PURE__ */ new Set([
217840
+ ...modelNameMap.values(),
217841
+ ...bareEnumNameMap.values(),
217842
+ ...topLevelExtensionBlocks.map((block) => block.name)
217843
+ ]));
217844
+ const claimedTopLevelNames = /* @__PURE__ */ new Set([
217845
+ ...PSL_SCALAR_TYPE_NAMES,
217846
+ ...modelNameMap.values(),
217847
+ ...bareEnumNameMap.values()
217848
+ ]);
217849
+ for (const block of topLevelExtensionBlocks) {
217850
+ if (claimedTopLevelNames.has(block.name)) throw postgresError("CONTRACT.NAME_DUPLICATE", `contract infer: recovered ${block.keyword} "${block.name}" collides with a model, a native enum, a PSL scalar type, or another recovered declaration of the same name. Rename the recovered declaration, or exclude it.`, { meta: {
217851
+ kind: block.keyword,
217852
+ name: block.name
217853
+ } });
217854
+ claimedTopLevelNames.add(block.name);
217855
+ }
217405
217856
  const models = [];
217406
217857
  for (const table of Object.values(schemaIR.tables)) models.push(buildModel(table, typeMap, enumNameMap, fieldNamesByTable, defaultMapping, rawDefaultParser, [...relationsByTable.get(table.name) ?? [], ...extraRelationsByTable.get(table.name) ?? []], danglingForeignKeysByTable.get(table.name) ?? [], rlsExtras?.rlsEnabledTables.has(table.name) ?? false, policyEmission.skipNotesByTable.get(table.name) ?? []));
217407
217858
  const sortedModels = topologicalSort(models, schemaIR.tables, modelNameMap);
217859
+ const separateTopLevelBucket = namespaceName !== void 0 && namespaceName !== "__unspecified__" && topLevelExtensionBlocks.length > 0;
217860
+ const namespaces = [];
217861
+ if (separateTopLevelBucket) namespaces.push(makePslNamespace({
217862
+ kind: "namespace",
217863
+ name: UNSPECIFIED_PSL_NAMESPACE_ID,
217864
+ entries: makePslNamespaceEntries([], [], topLevelExtensionBlocks),
217865
+ span: SYNTHETIC_SPAN
217866
+ }));
217867
+ namespaces.push(makePslNamespace({
217868
+ kind: "namespace",
217869
+ name: namespaceName ?? "__unspecified__",
217870
+ entries: makePslNamespaceEntries(sortedModels, [], [
217871
+ ...separateTopLevelBucket ? [] : topLevelExtensionBlocks,
217872
+ ...enumBlocks,
217873
+ ...policyEmission.blocks
217874
+ ]),
217875
+ span: SYNTHETIC_SPAN
217876
+ }));
217408
217877
  return {
217409
217878
  kind: "document",
217410
217879
  sourceId: "<sql-schema-ir>",
217411
- namespaces: [makePslNamespace({
217412
- kind: "namespace",
217413
- name: namespaceName ?? "__unspecified__",
217414
- entries: makePslNamespaceEntries(sortedModels, [], [...enumBlocks, ...policyEmission.blocks]),
217415
- span: SYNTHETIC_SPAN
217416
- })],
217880
+ namespaces,
217417
217881
  span: SYNTHETIC_SPAN
217418
217882
  };
217419
217883
  }
@@ -217472,107 +217936,6 @@ const postgresTargetDescriptor = {
217472
217936
  return createPostgresMigrationRunner(family);
217473
217937
  }
217474
217938
  };
217475
- /**
217476
- * Asserts that all framework components are compatible with the expected family and target.
217477
- *
217478
- * This function validates that each component in the framework components array:
217479
- * - Has kind 'target', 'adapter', 'extension', or 'driver'
217480
- * - Has familyId matching expectedFamilyId
217481
- * - Has targetId matching expectedTargetId
217482
- *
217483
- * This validation happens at the CLI composition boundary, before passing components
217484
- * to typed planner/runner instances. It fills the gap between runtime validation
217485
- * (via `validateConfig()`) and compile-time type enforcement.
217486
- *
217487
- * @param expectedFamilyId - The expected family ID (e.g., 'sql')
217488
- * @param expectedTargetId - The expected target ID (e.g., 'postgres')
217489
- * @param frameworkComponents - Array of framework components to validate
217490
- * @returns The same array typed as TargetBoundComponentDescriptor
217491
- * @throws CliStructuredError if any component is incompatible
217492
- *
217493
- * @example
217494
- * ```ts
217495
- * const config = await loadConfig();
217496
- * const frameworkComponents = [config.target, config.adapter, ...(config.extensions ?? [])];
217497
- *
217498
- * // Validate and type-narrow components before passing to planner
217499
- * const typedComponents = assertFrameworkComponentsCompatible(
217500
- * config.family.familyId,
217501
- * config.target.targetId,
217502
- * frameworkComponents
217503
- * );
217504
- *
217505
- * const planner = target.migrations.createPlanner(familyInstance);
217506
- * planner.plan({ contract, schema, policy, frameworkComponents: typedComponents });
217507
- * ```
217508
- */
217509
- function assertFrameworkComponentsCompatible(expectedFamilyId, expectedTargetId, frameworkComponents) {
217510
- for (let i = 0; i < frameworkComponents.length; i++) {
217511
- const component = frameworkComponents[i];
217512
- if (typeof component !== "object" || component === null) throw errorConfigValidation("frameworkComponents[]", { why: `Framework component at index ${i} must be an object` });
217513
- const record = component;
217514
- if (!Object.hasOwn(record, "kind")) throw errorConfigValidation("frameworkComponents[].kind", { why: `Framework component at index ${i} must have 'kind' property` });
217515
- const kind = record["kind"];
217516
- if (kind !== "target" && kind !== "adapter" && kind !== "extension" && kind !== "driver") throw errorConfigValidation("frameworkComponents[].kind", { why: `Framework component at index ${i} has invalid kind '${String(kind)}' (must be 'target', 'adapter', 'extension', or 'driver')` });
217517
- if (!Object.hasOwn(record, "familyId")) throw errorConfigValidation("frameworkComponents[].familyId", { why: `Framework component at index ${i} (kind: ${String(kind)}) must have 'familyId' property` });
217518
- const familyId = record["familyId"];
217519
- if (familyId !== expectedFamilyId) throw errorConfigValidation("frameworkComponents[].familyId", { why: `Framework component at index ${i} (kind: ${String(kind)}) has familyId '${String(familyId)}' but expected '${expectedFamilyId}'` });
217520
- if (!Object.hasOwn(record, "targetId")) throw errorConfigValidation("frameworkComponents[].targetId", { why: `Framework component at index ${i} (kind: ${String(kind)}) must have 'targetId' property` });
217521
- const targetId = record["targetId"];
217522
- if (targetId !== expectedTargetId) throw errorConfigValidation("frameworkComponents[].targetId", { why: `Framework component at index ${i} (kind: ${String(kind)}) has targetId '${String(targetId)}' but expected '${expectedTargetId}'` });
217523
- }
217524
- return frameworkComponents;
217525
- }
217526
- function isPlainObject(value) {
217527
- return typeof value === "object" && value !== null && !Array.isArray(value);
217528
- }
217529
- function sortDeep(value) {
217530
- if (Array.isArray(value)) return value.map(sortDeep);
217531
- if (!isPlainObject(value)) return value;
217532
- const entries = Object.entries(value).sort(([a], [b]) => a.localeCompare(b));
217533
- const next = {};
217534
- for (const [key, child] of entries) next[key] = sortDeep(child);
217535
- return next;
217536
- }
217537
- function sortDeepTyped(value) {
217538
- return sortDeep(value);
217539
- }
217540
- function extractExtensionPackMeta(component) {
217541
- const { kind, id, version, capabilities, types } = component;
217542
- const base = {
217543
- kind,
217544
- id,
217545
- familyId: component.familyId,
217546
- targetId: component.targetId,
217547
- version
217548
- };
217549
- if (capabilities) base["capabilities"] = capabilities;
217550
- if (types) if (types.codecTypes) {
217551
- const { controlPlaneHooks: _, codecDescriptors: _cd, ...cleanedCodecTypes } = types.codecTypes;
217552
- base["types"] = {
217553
- ...types,
217554
- codecTypes: cleanedCodecTypes
217555
- };
217556
- } else base["types"] = types;
217557
- return base;
217558
- }
217559
- /**
217560
- * Enriches a raw contract with framework-derived metadata: capabilities from all component descriptors and extension pack metadata from extension descriptors. Produces deterministically sorted output.
217561
- */
217562
- function enrichContract(ir, components) {
217563
- const mergedCapabilities = mergeCapabilityMatrices(ir.capabilities, components);
217564
- const extensionsMeta = {};
217565
- for (const component of components) if (component.kind === "extension") extensionsMeta[component.id] = extractExtensionPackMeta(component);
217566
- const extensions = Object.keys(extensionsMeta).length > 0 ? {
217567
- ...ir.extensions,
217568
- ...extensionsMeta
217569
- } : ir.extensions;
217570
- return {
217571
- ...ir,
217572
- capabilities: sortDeepTyped(mergedCapabilities),
217573
- extensions: sortDeepTyped(extensions)
217574
- };
217575
- }
217576
217939
  const JSON_EXTENSION = ".json";
217577
217940
  function getEmittedArtifactPaths(outputJsonPath) {
217578
217941
  if (!outputJsonPath.endsWith(JSON_EXTENSION)) throw emitterError("CONFIG.VALIDATION_FAILED", "Contract output path must end with .json", { meta: {
@@ -217633,8 +217996,8 @@ function generateContractDts(contract, emitter, codecTypeImports, hashes, option
217633
217996
  const extraTypeExports = emitter.getStorageTypeExports?.(contract, codecLookup);
217634
217997
  const contractWrapper = emitter.getContractWrapper("ContractBase", "TypeMaps");
217635
217998
  return `// ⚠️ GENERATED FILE - DO NOT EDIT
217636
- // This file is automatically generated by 'prisma-next contract emit'.
217637
- // To regenerate, run: prisma-next contract emit
217999
+ // This file is automatically generated by 'prisma contract emit'.
218000
+ // To regenerate, run: prisma contract emit
217638
218001
  ${importLines.join("\n")}
217639
218002
 
217640
218003
  ${familyImportLines.join("\n")}
@@ -217694,8 +218057,8 @@ async function emit(contract, stack, targetFamily, options) {
217694
218057
  ...canonicalized,
217695
218058
  _generated: {
217696
218059
  warning: "⚠️ GENERATED FILE - DO NOT EDIT",
217697
- message: "This file is automatically generated by \"prisma-next contract emit\".",
217698
- regenerate: "To regenerate, run: prisma-next contract emit"
218060
+ message: "This file is automatically generated by \"prisma contract emit\".",
218061
+ regenerate: "To regenerate, run: prisma contract emit"
217699
218062
  }
217700
218063
  }, null, 2);
217701
218064
  const generateOptions = {
@@ -217725,7 +218088,6 @@ function isGraphNode(hash, graph) {
217725
218088
  if (hash === "empty") return true;
217726
218089
  return graph.nodes.has(hash);
217727
218090
  }
217728
- init_dist();
217729
218091
  /**
217730
218092
  * The system head ref lives at `refs/head.json`. It is read (and its
217731
218093
  * corruption judged) through `readContractSpaceHeadRef`, not as a
@@ -217766,8 +218128,13 @@ async function readRef(refsDir, name) {
217766
218128
  } catch (error) {
217767
218129
  if (error instanceof Error && error.code === "ENOENT") throw new MigrationToolsError("MIGRATION.UNKNOWN_REF", `Unknown ref "${name}"`, {
217768
218130
  why: `No ref file found at "${filePath}".`,
217769
- fix: `Create the ref with: prisma-next ref set ${name} <hash>`,
217770
- details: {
218131
+ fix: `Create the ref with: prisma ref set ${name} <hash>`,
218132
+ nextActions: [{
218133
+ kind: "run-command",
218134
+ label: `Create the ref "${name}"`,
218135
+ command: `{bin} ref set ${name} <hash>`
218136
+ }],
218137
+ meta: {
217771
218138
  refName: name,
217772
218139
  filePath
217773
218140
  }
@@ -217850,7 +218217,6 @@ async function readRefsTolerant(refsDir) {
217850
218217
  problems
217851
218218
  };
217852
218219
  }
217853
- init_dist();
217854
218220
  function contractAtMemoKey(hash, refName) {
217855
218221
  return `${hash}\0${refName ?? ""}`;
217856
218222
  }
@@ -218844,6 +219210,109 @@ function runVerifyMigration(input) {
218844
219210
  });
218845
219211
  }
218846
219212
  /**
219213
+ * Asserts that all framework components are compatible with the expected family and target.
219214
+ *
219215
+ * This function validates that each component in the framework components array:
219216
+ * - Has kind 'target', 'adapter', 'extension', or 'driver'
219217
+ * - Has familyId matching expectedFamilyId
219218
+ * - Has targetId matching expectedTargetId
219219
+ *
219220
+ * This validation happens at the CLI composition boundary, before passing components
219221
+ * to typed planner/runner instances. It fills the gap between runtime validation
219222
+ * (via the config loader's `collectConfigIssues` diagnostics) and compile-time
219223
+ * type enforcement.
219224
+ *
219225
+ * @param expectedFamilyId - The expected family ID (e.g., 'sql')
219226
+ * @param expectedTargetId - The expected target ID (e.g., 'postgres')
219227
+ * @param frameworkComponents - Array of framework components to validate
219228
+ * @returns The same array typed as TargetBoundComponentDescriptor
219229
+ * @throws CliStructuredError if any component is incompatible
219230
+ *
219231
+ * @example
219232
+ * ```ts
219233
+ * const configResult = await loadConfigForSections(undefined, ['family', 'target', 'adapter', 'extensions']);
219234
+ * const config = configResult.assertOk();
219235
+ * const frameworkComponents = [config.target, config.adapter, ...(config.extensions ?? [])];
219236
+ *
219237
+ * // Validate and type-narrow components before passing to planner
219238
+ * const typedComponents = assertFrameworkComponentsCompatible(
219239
+ * config.family.familyId,
219240
+ * config.target.targetId,
219241
+ * frameworkComponents
219242
+ * );
219243
+ *
219244
+ * const planner = target.migrations.createPlanner(familyInstance);
219245
+ * planner.plan({ contract, schema, policy, frameworkComponents: typedComponents });
219246
+ * ```
219247
+ */
219248
+ function assertFrameworkComponentsCompatible(expectedFamilyId, expectedTargetId, frameworkComponents) {
219249
+ for (let i = 0; i < frameworkComponents.length; i++) {
219250
+ const component = frameworkComponents[i];
219251
+ if (typeof component !== "object" || component === null) throw errorConfigValidation("frameworkComponents[]", { why: `Framework component at index ${i} must be an object` });
219252
+ const record = component;
219253
+ if (!Object.hasOwn(record, "kind")) throw errorConfigValidation("frameworkComponents[].kind", { why: `Framework component at index ${i} must have 'kind' property` });
219254
+ const kind = record["kind"];
219255
+ if (kind !== "target" && kind !== "adapter" && kind !== "extension" && kind !== "driver") throw errorConfigValidation("frameworkComponents[].kind", { why: `Framework component at index ${i} has invalid kind '${String(kind)}' (must be 'target', 'adapter', 'extension', or 'driver')` });
219256
+ if (!Object.hasOwn(record, "familyId")) throw errorConfigValidation("frameworkComponents[].familyId", { why: `Framework component at index ${i} (kind: ${String(kind)}) must have 'familyId' property` });
219257
+ const familyId = record["familyId"];
219258
+ if (familyId !== expectedFamilyId) throw errorConfigValidation("frameworkComponents[].familyId", { why: `Framework component at index ${i} (kind: ${String(kind)}) has familyId '${String(familyId)}' but expected '${expectedFamilyId}'` });
219259
+ if (!Object.hasOwn(record, "targetId")) throw errorConfigValidation("frameworkComponents[].targetId", { why: `Framework component at index ${i} (kind: ${String(kind)}) must have 'targetId' property` });
219260
+ const targetId = record["targetId"];
219261
+ if (targetId !== expectedTargetId) throw errorConfigValidation("frameworkComponents[].targetId", { why: `Framework component at index ${i} (kind: ${String(kind)}) has targetId '${String(targetId)}' but expected '${expectedTargetId}'` });
219262
+ }
219263
+ return frameworkComponents;
219264
+ }
219265
+ function isPlainObject(value) {
219266
+ return typeof value === "object" && value !== null && !Array.isArray(value);
219267
+ }
219268
+ function sortDeep(value) {
219269
+ if (Array.isArray(value)) return value.map(sortDeep);
219270
+ if (!isPlainObject(value)) return value;
219271
+ const entries = Object.entries(value).sort(([a], [b]) => a.localeCompare(b));
219272
+ const next = {};
219273
+ for (const [key, child] of entries) next[key] = sortDeep(child);
219274
+ return next;
219275
+ }
219276
+ function sortDeepTyped(value) {
219277
+ return sortDeep(value);
219278
+ }
219279
+ function extractExtensionPackMeta(component) {
219280
+ const { kind, id, version, capabilities, types } = component;
219281
+ const base = {
219282
+ kind,
219283
+ id,
219284
+ familyId: component.familyId,
219285
+ targetId: component.targetId,
219286
+ version
219287
+ };
219288
+ if (capabilities) base["capabilities"] = capabilities;
219289
+ if (types) if (types.codecTypes) {
219290
+ const { controlPlaneHooks: _, codecDescriptors: _cd, ...cleanedCodecTypes } = types.codecTypes;
219291
+ base["types"] = {
219292
+ ...types,
219293
+ codecTypes: cleanedCodecTypes
219294
+ };
219295
+ } else base["types"] = types;
219296
+ return base;
219297
+ }
219298
+ /**
219299
+ * Enriches a raw contract with framework-derived metadata: capabilities from all component descriptors and extension pack metadata from extension descriptors. Produces deterministically sorted output.
219300
+ */
219301
+ function enrichContract(ir, components) {
219302
+ const mergedCapabilities = mergeCapabilityMatrices(ir.capabilities, components);
219303
+ const extensionsMeta = {};
219304
+ for (const component of components) if (component.kind === "extension") extensionsMeta[component.id] = extractExtensionPackMeta(component);
219305
+ const extensions = Object.keys(extensionsMeta).length > 0 ? {
219306
+ ...ir.extensions,
219307
+ ...extensionsMeta
219308
+ } : ir.extensions;
219309
+ return {
219310
+ ...ir,
219311
+ capabilities: sortDeepTyped(mergedCapabilities),
219312
+ extensions: sortDeepTyped(extensions)
219313
+ };
219314
+ }
219315
+ /**
218847
219316
  * Minimal aggregate-loader projection that extracts `id` + `targetId`
218848
219317
  * from raw extension pack descriptors **without invoking any
218849
219318
  * `contractSpace` accessor**. Inspects the own-property descriptor so
@@ -218962,7 +219431,7 @@ function mapIntegrityViolations(violations) {
218962
219431
  const contractUnreadable = violations.find((v) => v.kind === "contractUnreadable");
218963
219432
  if (contractUnreadable && contractUnreadable.kind === "contractUnreadable") return contractSpaceViolationError(`Contract-space contract validation failed for "${contractUnreadable.spaceId}"`, {
218964
219433
  why: contractUnreadable.detail,
218965
- fix: "Re-emit the extension contract with `prisma-next contract emit`, or fix the extension pack descriptor producing the invalid contract.",
219434
+ fix: "Re-emit the extension contract with `prisma-cli contract emit`, or fix the extension pack descriptor producing the invalid contract.",
218966
219435
  violations: [contractUnreadable]
218967
219436
  });
218968
219437
  const structural = violations[0];
@@ -219036,6 +219505,20 @@ function stripOperations(operations) {
219036
219505
  }));
219037
219506
  }
219038
219507
  /**
219508
+ * Content identity of a `db update` plan: what it does (the ordered display
219509
+ * operations) and where it lands (the destination storage hash). A
219510
+ * `DESTRUCTIVE_CHANGES` refusal names the refused plan by this hash, and the
219511
+ * apply that carries the consent back recomputes it to prove it is still
219512
+ * applying the plan that was consented to.
219513
+ */
219514
+ function computePlanHash(plan) {
219515
+ const canonical = canonicalizeJson({
219516
+ operations: plan.operations,
219517
+ destination: { storageHash: plan.destination.storageHash }
219518
+ });
219519
+ return createHash("sha256").update(canonical).digest("hex");
219520
+ }
219521
+ /**
219039
219522
  * Span id emitted via `onProgress` for the run phase. Stable
219040
219523
  * identifier consumed by the structured-output renderer and by tests.
219041
219524
  */
@@ -219094,7 +219577,8 @@ async function runMigration(inputs) {
219094
219577
  ...runnerResult.failure.meta ?? {},
219095
219578
  failingSpace: runnerResult.failure.failingSpace,
219096
219579
  runnerErrorCode: runnerResult.failure.code
219097
- }
219580
+ },
219581
+ cause: runnerResult.failure
219098
219582
  });
219099
219583
  }
219100
219584
  onProgress?.({
@@ -219287,6 +219771,24 @@ async function executeRun(options) {
219287
219771
  ...ifDefined("warnings", plannerWarnings)
219288
219772
  });
219289
219773
  }
219774
+ if (options.consentedPlanHash !== void 0) {
219775
+ const planHash = computePlanHash({
219776
+ operations: stripOperations(orderedResolutions.flatMap((r) => r.entry.displayOps)),
219777
+ destination: appPlan.destination
219778
+ });
219779
+ if (planHash !== options.consentedPlanHash) return notOk({
219780
+ code: "CONSENT_PLAN_MISMATCH",
219781
+ summary: "The plan changed between consent and apply",
219782
+ why: "The plan recomputed for the consented apply is not the plan that was consented to, so applying it could destroy something nobody agreed to.",
219783
+ conflicts: void 0,
219784
+ meta: void 0,
219785
+ consentPlanMismatch: {
219786
+ consentedPlanHash: options.consentedPlanHash,
219787
+ planHash
219788
+ },
219789
+ ...ifDefined("warnings", plannerWarnings)
219790
+ });
219791
+ }
219290
219792
  const applied = await runMigration({
219291
219793
  aggregate,
219292
219794
  perSpacePlans: planResult.value.perSpace,
@@ -219303,7 +219805,8 @@ async function executeRun(options) {
219303
219805
  summary: applied.failure.summary,
219304
219806
  ...ifDefined("why", applied.failure.why),
219305
219807
  meta: applied.failure.meta,
219306
- ...ifDefined("warnings", plannerWarnings)
219808
+ ...ifDefined("warnings", plannerWarnings),
219809
+ ...ifDefined("cause", applied.failure.cause)
219307
219810
  });
219308
219811
  const aggregateOps = applied.value.orderedResolutions.flatMap((r) => r.entry.displayOps);
219309
219812
  const summary = action === "dbInit" ? `Applied ${applied.value.totalOpsExecuted} operation(s) across ${applied.value.orderedResolutions.length} space(s), database signed` : applied.value.totalOpsExecuted === 0 ? `Database already matches contract across ${applied.value.orderedResolutions.length} space(s), signature updated` : `Applied ${applied.value.totalOpsExecuted} operation(s) across ${applied.value.orderedResolutions.length} space(s), signature updated`;
@@ -219426,7 +219929,8 @@ function buildRunnerFailure(args) {
219426
219929
  why: args.why,
219427
219930
  meta: args.meta,
219428
219931
  conflicts: void 0,
219429
- ...ifDefined("warnings", args.warnings)
219932
+ ...ifDefined("warnings", args.warnings),
219933
+ ...ifDefined("cause", args.cause)
219430
219934
  }));
219431
219935
  }
219432
219936
  /**
@@ -219482,13 +219986,14 @@ async function executeDbUpdate(options) {
219482
219986
  action: "dbUpdate",
219483
219987
  ...ifDefined("onProgress", options.onProgress)
219484
219988
  };
219485
- if (options.mode === "apply" && !options.acceptDataLoss) {
219486
- const gate = await guardDestructiveChanges(sharedInputs);
219487
- if (gate !== null) return gate;
219989
+ if (options.mode === "apply" && !options.acceptDataLoss && options.consent === void 0) {
219990
+ const refusal = await guardDestructiveChanges(sharedInputs);
219991
+ if (refusal !== null) return refusal;
219488
219992
  }
219489
219993
  return await executeRun({
219490
219994
  ...sharedInputs,
219491
- mode: options.mode
219995
+ mode: options.mode,
219996
+ ...ifDefined("consentedPlanHash", options.consent?.planHash)
219492
219997
  });
219493
219998
  }
219494
219999
  /**
@@ -219509,12 +220014,22 @@ async function guardDestructiveChanges(sharedInputs) {
219509
220014
  label: op.label
219510
220015
  }));
219511
220016
  if (destructiveOps.length === 0) return null;
220017
+ const databaseName = await sharedInputs.driver.databaseName?.();
219512
220018
  return notOk({
219513
220019
  code: "DESTRUCTIVE_CHANGES",
219514
220020
  summary: `Planned ${destructiveOps.length} destructive operation(s) that require confirmation`,
219515
- why: "Destructive operations require confirmation re-run with -y to accept",
220021
+ why: "Destructive operations require explicit consent, which the caller has not given",
219516
220022
  conflicts: void 0,
219517
- meta: { destructiveOperations: destructiveOps }
220023
+ meta: void 0,
220024
+ destructiveChanges: {
220025
+ destructiveOperations: destructiveOps,
220026
+ databaseName,
220027
+ planHash: computePlanHash({
220028
+ operations: planResult.value.plan.operations,
220029
+ destination: planResult.value.destination
220030
+ })
220031
+ },
220032
+ ...ifDefined("warnings", planResult.value.warnings)
219518
220033
  });
219519
220034
  }
219520
220035
  /**
@@ -219538,9 +220053,9 @@ const SPAN_IDS = {
219538
220053
  * schema introspection.
219539
220054
  * 3. **Verify**: {@link verifyMigration} returns per-space `markerCheck` +
219540
220055
  * per-space `schemaCheck` (each contract space verified against the full schema,
219541
- * then scoped to its own contract space). Marker mismatches map to
219542
- * `CliStructuredError` (code `5002`) so callers (CLI command) can render
219543
- * and exit. Verify results are returned to the caller verbatim.
220056
+ * then scoped to its own contract space). Marker drift is returned as the
220057
+ * success value's `markerDrift` envelope for callers to settle as a
220058
+ * finding. Verify results are returned to the caller verbatim.
219544
220059
  */
219545
220060
  async function executeDbVerify(options) {
219546
220061
  const { driver, familyInstance, onProgress, skipSchema, skipMarker } = options;
@@ -219661,17 +220176,14 @@ function finaliseVerifyResult(args) {
219661
220176
  docsUrl: "https://pris.ly/contract-spaces"
219662
220177
  }));
219663
220178
  }
219664
- const markerError = skipMarker ? null : mapMarkerCheckFailures(aggregate.app.spaceId, verifyResult.value.markerCheck);
219665
- if (markerError !== null) {
219666
- emitVerifySpan(onProgress, "spanEndError");
219667
- return notOk(markerError);
219668
- }
219669
- emitVerifySpan(onProgress, "spanEndOk");
220179
+ const markerDrift = skipMarker ? null : mapMarkerCheckFailures(aggregate.app.spaceId, verifyResult.value.markerCheck);
220180
+ emitVerifySpan(onProgress, markerDrift === null ? "spanEndOk" : "spanEndError");
219670
220181
  return ok$1({
219671
220182
  schemaResults: verifyResult.value.schemaCheck.perSpace,
219672
220183
  unclaimed: verifyResult.value.schemaCheck.unclaimed,
219673
220184
  spaceOrder: [aggregate.app.spaceId, ...aggregate.extensions.map((e) => e.spaceId)],
219674
- appSpaceId: aggregate.app.spaceId
220185
+ appSpaceId: aggregate.app.spaceId,
220186
+ markerDrift
219675
220187
  });
219676
220188
  }
219677
220189
  function buildSkippedSchemaResult(space) {
@@ -219704,7 +220216,7 @@ function mapMarkerCheckFailures(appSpaceId, section) {
219704
220216
  violations.push({
219705
220217
  kind: "hashMismatch",
219706
220218
  spaceId,
219707
- remediation: spaceId === appSpaceId ? "Run `prisma-next db update` to advance the marker, or roll the database back to the recorded hash." : `Apply on-disk migrations under \`migrations/${spaceId}/\` to advance the marker, or remove the conflicting marker row.`
220219
+ remediation: spaceId === appSpaceId ? "Run `prisma-cli db update` to advance the marker, or roll the database back to the recorded hash." : `Apply on-disk migrations under \`migrations/${spaceId}/\` to advance the marker, or remove the conflicting marker row.`
219708
220220
  });
219709
220221
  continue;
219710
220222
  }
@@ -219717,7 +220229,7 @@ function mapMarkerCheckFailures(appSpaceId, section) {
219717
220229
  for (const orphan of section.orphanMarkers) violations.push({
219718
220230
  kind: "orphanMarker",
219719
220231
  spaceId: orphan.spaceId,
219720
- remediation: `Add the corresponding extension to \`extensions\` in \`prisma-next.config.ts\`, or delete the orphan marker row for "${orphan.spaceId}".`
220232
+ remediation: `Add the corresponding extension to \`extensions\` in \`prisma.config.ts\`, or delete the orphan marker row for "${orphan.spaceId}".`
219721
220233
  });
219722
220234
  if (violations.length === 0) return null;
219723
220235
  const lines = violations.map((v) => `- [${v.kind}] ${v.spaceId}: ${v.remediation}`);
@@ -219849,7 +220361,8 @@ async function executeMigrate(options) {
219849
220361
  code: "RUNNER_FAILED",
219850
220362
  summary: applied.failure.summary,
219851
220363
  why: applied.failure.why,
219852
- meta: applied.failure.meta
220364
+ meta: applied.failure.meta,
220365
+ ...ifDefined("cause", applied.failure.cause)
219853
220366
  });
219854
220367
  const orderedAll = canonicalOrder.filter((spaceId) => perSpacePlans.has(spaceId) || atHeadResolutions.has(spaceId)).map((spaceId) => {
219855
220368
  if (perSpacePlans.has(spaceId)) {
@@ -220374,6 +220887,7 @@ var ControlClientImpl = class {
220374
220887
  targetId: this.options.target.targetId,
220375
220888
  extensions: this.options.extensions ?? [],
220376
220889
  ...ifDefined("acceptDataLoss", options.acceptDataLoss),
220890
+ ...ifDefined("consent", options.consent),
220377
220891
  ...ifDefined("onProgress", onProgress)
220378
220892
  });
220379
220893
  }
@@ -220627,7 +221141,7 @@ function createPostgresControlClient(options = {}) {
220627
221141
  ...ifDefined("extensions", options.extensions)
220628
221142
  });
220629
221143
  }
220630
- var version = "0.9.0";
221144
+ var version = "0.10.0-dev.2";
220631
221145
  var migration_default = {
220632
221146
  from: null,
220633
221147
  to: "6bbd4dc1c19c8aa5e0d60c9755e0f8ea07ba1c01d20c48cf3aa7226e4ee7d33f",