@prisma/composer-prisma-cloud 0.18.0-dev.1 → 0.18.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.
@@ -18391,7 +18391,7 @@ const ZodRecord = /*@__PURE__*/ $constructor("ZodRecord", (inst, def) => {
18391
18391
  inst.keyType = def.keyType;
18392
18392
  inst.valueType = def.valueType;
18393
18393
  });
18394
- function record(keyType, valueType, params) {
18394
+ function record$1(keyType, valueType, params) {
18395
18395
  if (!valueType || !valueType._zod) return new ZodRecord({
18396
18396
  type: "record",
18397
18397
  keyType: string$1(),
@@ -28188,7 +28188,7 @@ const linkSocialAccount = createAuthEndpoint("/link-social", {
28188
28188
  /**
28189
28189
  * Any additional data to pass through the oauth flow.
28190
28190
  */
28191
- additionalData: record(string$1(), any()).optional()
28191
+ additionalData: record$1(string$1(), any()).optional()
28192
28192
  }),
28193
28193
  use: [sessionMiddleware],
28194
28194
  metadata: { openapi: {
@@ -29514,7 +29514,7 @@ const socialSignInBodySchema = object({
29514
29514
  /**
29515
29515
  * Additional data to be passed through the OAuth flow
29516
29516
  */
29517
- additionalData: record(string$1(), any()).optional().meta({ description: "Additional data to be passed through the OAuth flow" })
29517
+ additionalData: record$1(string$1(), any()).optional().meta({ description: "Additional data to be passed through the OAuth flow" })
29518
29518
  });
29519
29519
  const signInSocial = () => createAuthEndpoint("/sign-in/social", {
29520
29520
  method: "POST",
@@ -29788,7 +29788,7 @@ const signUpEmailBodySchema = object({
29788
29788
  image: string$1().optional(),
29789
29789
  callbackURL: string$1().optional(),
29790
29790
  rememberMe: boolean$1().optional()
29791
- }).and(record(string$1(), any()));
29791
+ }).and(record$1(string$1(), any()));
29792
29792
  const signUpEmail = () => createAuthEndpoint("/sign-up/email", {
29793
29793
  method: "POST",
29794
29794
  operationId: "signUpWithEmailAndPassword",
@@ -30036,7 +30036,7 @@ const signUpEmail = () => createAuthEndpoint("/sign-up/email", {
30036
30036
  });
30037
30037
  });
30038
30038
  init_error();
30039
- const updateSessionBodySchema = record(string$1().meta({ description: "Field name must be a string" }), any());
30039
+ const updateSessionBodySchema = record$1(string$1().meta({ description: "Field name must be a string" }), any());
30040
30040
  const updateSession = () => createAuthEndpoint("/update-session", {
30041
30041
  method: "POST",
30042
30042
  operationId: "updateSession",
@@ -30085,7 +30085,7 @@ const updateSession = () => createAuthEndpoint("/update-session", {
30085
30085
  return ctx.json({ session: parseSessionOutput(ctx.context.options, newSession) });
30086
30086
  });
30087
30087
  init_error();
30088
- const updateUserBodySchema = record(string$1().meta({ description: "Field name must be a string" }), any());
30088
+ const updateUserBodySchema = record$1(string$1().meta({ description: "Field name must be a string" }), any());
30089
30089
  const updateUser = () => createAuthEndpoint("/update-user", {
30090
30090
  method: "POST",
30091
30091
  operationId: "updateUser",
@@ -52211,7 +52211,7 @@ const createUserBodySchema = object({
52211
52211
  /**
52212
52212
  * extra fields for user
52213
52213
  */
52214
- data: record(string$1(), any()).optional().meta({ description: "Extra fields for the user. Including custom additional fields." })
52214
+ data: record$1(string$1(), any()).optional().meta({ description: "Extra fields for the user. Including custom additional fields." })
52215
52215
  });
52216
52216
  /**
52217
52217
  * ### Endpoint
@@ -52309,7 +52309,7 @@ const createUser = (opts) => createAuthEndpoint("/admin/create-user", {
52309
52309
  });
52310
52310
  const adminUpdateUserBodySchema = object({
52311
52311
  userId: string().meta({ description: "The user id" }),
52312
- data: record(any(), any()).meta({ description: "The user data to update" })
52312
+ data: record$1(any(), any()).meta({ description: "The user data to update" })
52313
52313
  });
52314
52314
  /**
52315
52315
  * ### Endpoint
@@ -52945,7 +52945,7 @@ const setUserPassword = (opts) => createAuthEndpoint("/admin/set-user-password",
52945
52945
  const userHasPermissionBodySchema = object({
52946
52946
  userId: string().optional().meta({ description: `The user id. Eg: "user-id"` }),
52947
52947
  role: string$1().optional().meta({ description: `The role to check permission for. Eg: "admin"` })
52948
- }).and(xor([object({ permission: record(string$1(), array$1(string$1())) }), object({ permissions: record(string$1(), array$1(string$1())) })]));
52948
+ }).and(xor([object({ permission: record$1(string$1(), array$1(string$1())) }), object({ permissions: record$1(string$1(), array$1(string$1())) })]));
52949
52949
  /**
52950
52950
  * ### Endpoint
52951
52951
  *
@@ -53397,8 +53397,8 @@ const schema = { jwks: { fields: {
53397
53397
  } } };
53398
53398
  init_error();
53399
53399
  const signJWTBodySchema = object({
53400
- payload: record(string$1(), any()),
53401
- overrideOptions: record(string$1(), any()).optional()
53400
+ payload: record$1(string$1(), any()),
53401
+ overrideOptions: record$1(string$1(), any()).optional()
53402
53402
  });
53403
53403
  const verifyJWTBodySchema = object({
53404
53404
  token: string$1(),
@@ -53592,7 +53592,7 @@ const signInMagicLinkBodySchema = object({
53592
53592
  callbackURL: string$1().meta({ description: "URL to redirect after magic link verification" }).optional(),
53593
53593
  newUserCallbackURL: string$1().meta({ description: "URL to redirect after new user signup. Only used if the user is registering for the first time." }).optional(),
53594
53594
  errorCallbackURL: string$1().meta({ description: "URL to redirect after error." }).optional(),
53595
- metadata: record(string$1(), any()).meta({ description: "Additional metadata to pass to sendMagicLink." }).optional()
53595
+ metadata: record$1(string$1(), any()).meta({ description: "Additional metadata to pass to sendMagicLink." }).optional()
53596
53596
  });
53597
53597
  const magicLinkVerifyQuerySchema = object({
53598
53598
  token: string$1().meta({ description: "Verification token" }),
@@ -58072,6 +58072,7 @@ var contract_default = {
58072
58072
  },
58073
58073
  "relations": { "user": {
58074
58074
  "cardinality": "N:1",
58075
+ "nullable": false,
58075
58076
  "on": {
58076
58077
  "localFields": ["userId"],
58077
58078
  "targetFields": ["id"]
@@ -58220,6 +58221,7 @@ var contract_default = {
58220
58221
  },
58221
58222
  "relations": { "user": {
58222
58223
  "cardinality": "N:1",
58224
+ "nullable": false,
58223
58225
  "on": {
58224
58226
  "localFields": ["userId"],
58225
58227
  "targetFields": ["id"]
@@ -60018,7 +60020,7 @@ function postgresResolveDefault(def, resolvedNativeType) {
60018
60020
  return parsePostgresDefault(def.expression, resolvedNativeType) ?? def;
60019
60021
  }
60020
60022
  /**
60021
- * A bug in Prisma Next, not a user error. Never catch this except at the
60023
+ * A bug in Prisma 8, not a user error. Never catch this except at the
60022
60024
  * outermost boundary for crash reporting — an InternalError means an invariant
60023
60025
  * broke and the process cannot reliably continue. User-facing failures use
60024
60026
  * `structuredError` with a dotted code instead.
@@ -61399,7 +61401,7 @@ function isCodecTrait(value) {
61399
61401
  */
61400
61402
  const voidParamsSchema = { "~standard": {
61401
61403
  version: 1,
61402
- vendor: "prisma-next",
61404
+ vendor: "prisma",
61403
61405
  validate: (input) => input === void 0 ? { value: void 0 } : { issues: [{ message: "unexpected typeParams for non-parameterized codec (void params expected)" }] }
61404
61406
  } };
61405
61407
  function runtimeError(code, message, details) {
@@ -61469,16 +61471,13 @@ function validateCodecTypeParams(descriptor, ref) {
61469
61471
  }
61470
61472
  /**
61471
61473
  * Resolves a `Codec` instance: validates `ref.typeParams` via
61472
- * {@link validateCodecTypeParams} then calls `descriptor.factory(validated)(ctx)`.
61473
- *
61474
- * The descriptor's `factory` is typed against its own `P`; the registry erases
61475
- * `P` to `any`, so the factory is narrowed to `(params: unknown) => (ctx) => Codec`
61476
- * at the call boundary. The `paramsSchema` validates the input above before we
61477
- * forward it, so the narrowing is safe by construction.
61474
+ * {@link validateCodecTypeParams} then calls `descriptor.factory(validated)(ctx)`
61475
+ * as a method on `descriptor`, preserving `this` for factories that build
61476
+ * their returned codec from the descriptor instance (e.g. `new XCodec(this)`).
61478
61477
  */
61479
61478
  function materializeCodec(descriptor, ref, ctx) {
61480
61479
  const validated = validateCodecTypeParams(descriptor, ref);
61481
- return blindCast(descriptor.factory)(validated)(ctx);
61480
+ return descriptor.factory(validated)(ctx);
61482
61481
  }
61483
61482
  /**
61484
61483
  * Renders a string as a TypeScript source-text literal.
@@ -62783,6 +62782,103 @@ function indexInputFromSerialized(flat) {
62783
62782
  };
62784
62783
  }
62785
62784
  /**
62785
+ * Stable code emitted by the runtime when an in-flight `execute()`
62786
+ * is cancelled via the per-query `AbortSignal`. The envelope's
62787
+ * `details.phase` distinguishes where the abort was observed:
62788
+ *
62789
+ * - `'encode'` — abort fired during `encodeParams` (SQL) or
62790
+ * `resolveValue` (Mongo).
62791
+ * - `'decode'` — abort fired during `decodeRow` / `decodeField`.
62792
+ * - `'stream'` — abort fired between rows or before any codec call
62793
+ * (already-aborted at entry).
62794
+ * - `'beforeQuery'` / `'beforeExecute'` / `'afterQuery'` /
62795
+ * `'afterExecute'` / `'onRow'` — abort fired on entry to or during
62796
+ * the corresponding middleware phase
62797
+ * (cooperative cancellation per the param-transform seam).
62798
+ */
62799
+ const RUNTIME_ABORTED = "RUNTIME.ABORTED";
62800
+ /**
62801
+ * Construct a `RUNTIME.ABORTED` envelope. Phase distinguishes where the
62802
+ * abort was observed — codec call sites (`encode` / `decode` / `stream`)
62803
+ * or operation-specific middleware seams, as
62804
+ * enumerated on {@link RuntimeAbortedPhase}. Cause carries
62805
+ * `signal.reason` verbatim from the platform — native abort produces a
62806
+ * `DOMException`, explicit `controller.abort(reason)` produces whatever
62807
+ * the caller passed. No synthesis happens here.
62808
+ */
62809
+ function runtimeAborted(phase, cause) {
62810
+ const envelope = runtimeError(RUNTIME_ABORTED, `Operation aborted during ${phase}`, { phase });
62811
+ return Object.assign(envelope, { cause });
62812
+ }
62813
+ /**
62814
+ * Throw a phase-tagged `RUNTIME.ABORTED` envelope if the supplied
62815
+ * context is already aborted at the precheck site. Centralises the
62816
+ * `if (ctx.signal?.aborted) throw runtimeAborted(...)` pattern that
62817
+ * every codec dispatch site (and the `beforeExecute` middleware phase)
62818
+ * repeats. Accepts both the framework `CodecCallContext` and the
62819
+ * `RuntimeMiddlewareContext`; both expose `signal?: AbortSignal`.
62820
+ */
62821
+ function checkAborted(ctx, phase) {
62822
+ if (ctx.signal?.aborted) throw runtimeAborted(phase, ctx.signal.reason);
62823
+ }
62824
+ /**
62825
+ * Race a per-cell `Promise.all` (or any other in-flight work promise) against
62826
+ * the supplied abort signal so the runtime returns `RUNTIME.ABORTED` promptly
62827
+ * even when codec bodies ignore the signal. In-flight bodies that ignore the
62828
+ * signal are abandoned and run to completion in the background — the
62829
+ * cooperative-cancellation contract documented in ADR 204.
62830
+ *
62831
+ * Call sites still SHOULD pre-check `signal.aborted` and short-circuit with
62832
+ * a phase-tagged `RUNTIME.ABORTED` envelope before invoking this helper —
62833
+ * that path is the canonical "aborted at entry" surface and avoids
62834
+ * scheduling the work promise. As a defensive belt-and-braces, this helper
62835
+ * also handles the already-aborted case internally: `AbortSignal` does not
62836
+ * replay past abort events to listeners registered after the abort, so we
62837
+ * inspect `signal.aborted` synchronously and reject with the sentinel
62838
+ * before installing the listener. The rejection is still attributed to the
62839
+ * abort path via the sentinel-identity check.
62840
+ *
62841
+ * Distinguishing the rejection source is load-bearing for AC-ERR4
62842
+ * (`RUNTIME.ENCODE_FAILED` / `RUNTIME.DECODE_FAILED` pass through unchanged).
62843
+ * The semantically equivalent `abortable(signal)` helper in
62844
+ * `@internal/utils` rejects with `signal.reason ?? new DOMException(...)`,
62845
+ * which is not stably distinguishable from a codec-thrown error by identity
62846
+ * alone (a fresh fallback DOMException is allocated per call). We instead
62847
+ * track abort attribution with a unique sentinel: only the `onAbort` listener
62848
+ * installed here ever rejects with the sentinel, so an `error === sentinel`
62849
+ * identity check after the race is unambiguous.
62850
+ *
62851
+ * Lives in `framework-components` (rather than the SQL family, where it
62852
+ * originated in m2) so every family runtime that needs cooperative
62853
+ * cancellation around a codec-dispatch `Promise.all` (SQL encode + decode
62854
+ * today, Mongo encode in m3) shares the same attribution logic.
62855
+ */
62856
+ async function raceAgainstAbort(work, signal, phase) {
62857
+ if (signal === void 0) return await work;
62858
+ const sentinel = { reason: void 0 };
62859
+ let onAbort;
62860
+ const abortPromise = new Promise((_, reject) => {
62861
+ if (signal.aborted) {
62862
+ sentinel.reason = signal.reason;
62863
+ reject(sentinel);
62864
+ return;
62865
+ }
62866
+ onAbort = () => {
62867
+ sentinel.reason = signal.reason;
62868
+ reject(sentinel);
62869
+ };
62870
+ signal.addEventListener("abort", onAbort, { once: true });
62871
+ });
62872
+ try {
62873
+ return await Promise.race([work, abortPromise]);
62874
+ } catch (error) {
62875
+ if (error === sentinel) throw runtimeAborted(phase, sentinel.reason);
62876
+ throw error;
62877
+ } finally {
62878
+ if (onAbort) signal.removeEventListener("abort", onAbort);
62879
+ }
62880
+ }
62881
+ /**
62786
62882
  * Sentinel kind for the legacy codec-triple shape persisted under
62787
62883
  * `SqlStorage.types`. Plain JSON-clean object literals carry this
62788
62884
  * discriminator so the polymorphic slot dispatch can route them down
@@ -63942,7 +64038,7 @@ function classifyEnumMemberType(block) {
63942
64038
  */
63943
64039
  function resolveEnumCodecId(block, ctx) {
63944
64040
  const sourceId = ctx.sourceId ?? "unknown";
63945
- const typeAttr = block.blockAttributes.find((a) => a.name === "type");
64041
+ const typeAttr = block.attributes["type"];
63946
64042
  if (typeAttr === void 0) {
63947
64043
  const inferredKind = classifyEnumMemberType(block);
63948
64044
  if (inferredKind === null || ctx.enumInferenceCodecs === void 0) {
@@ -63959,20 +64055,11 @@ function resolveEnumCodecId(block, ctx) {
63959
64055
  codecSpan: block.span
63960
64056
  };
63961
64057
  }
63962
- const rawCodecArg = typeAttr.args[0]?.value;
63963
- const codecId = rawCodecArg?.startsWith("\"") && rawCodecArg.endsWith("\"") && rawCodecArg.length >= 2 ? rawCodecArg.slice(1, -1) : void 0;
63964
- if (codecId === void 0) {
63965
- ctx.diagnostics?.push({
63966
- code: "PSL_ENUM_MISSING_TYPE",
63967
- message: `enum "${block.name}" @@type attribute must have a quoted codec id argument`,
63968
- sourceId,
63969
- span: typeAttr.span
63970
- });
63971
- return;
63972
- }
64058
+ const codecId = typeAttr.args["codecId"];
64059
+ invariant(typeof codecId === "string", "@@type on an enum block parses one string argument");
63973
64060
  return {
63974
64061
  codecId,
63975
- codecSpan: typeAttr.args[0]?.span ?? typeAttr.span
64062
+ codecSpan: typeAttr.span
63976
64063
  };
63977
64064
  }
63978
64065
  function isAuthoringArgRef(value) {
@@ -64064,7 +64151,11 @@ function isWellFormedDescriptor(value, descriptorKind) {
64064
64151
  if (!("required" in name) || typeof name.required !== "boolean") return false;
64065
64152
  if (!("parameters" in value)) return false;
64066
64153
  const parameters = value.parameters;
64067
- return typeof parameters === "object" && parameters !== null && !Array.isArray(parameters);
64154
+ if (typeof parameters !== "object" || parameters === null || Array.isArray(parameters)) return false;
64155
+ if (!("attributes" in value) || value.attributes === void 0) return true;
64156
+ const attributes = value.attributes;
64157
+ if (typeof attributes !== "object" || attributes === null || Array.isArray(attributes)) return false;
64158
+ return Object.values(attributes).every((factory) => typeof factory === "function");
64068
64159
  }
64069
64160
  case "modelAttribute":
64070
64161
  if (!("attribute" in value) || typeof value.attribute !== "string" || value.attribute.length === 0) return false;
@@ -64118,6 +64209,25 @@ function mergeAuthoringNamespaces(target, source, path, descriptorKind, label) {
64118
64209
  mergeAuthoringNamespaces(existingValue, sourceValue, currentPath, descriptorKind, label);
64119
64210
  }
64120
64211
  }
64212
+ const ATTRIBUTE_SPEC_LEVELS = ["model", "field"];
64213
+ function mergeAuthoringAttributeSpecs(target, source, contributedBy, owners) {
64214
+ const invalidContribution = (detail) => runtimeError("CONTRACT.PACK_CONTRIBUTION_INVALID", `Invalid authoring attributeSpecs contribution from descriptor "${contributedBy}". ${detail}`);
64215
+ if (!isCopyableNamespaceObject(source)) throw invalidContribution("Expected a record carrying a \"model\" and a \"field\" level.");
64216
+ for (const level of ATTRIBUTE_SPEC_LEVELS) {
64217
+ const contributed = source[level];
64218
+ if (!isCopyableNamespaceObject(contributed)) throw invalidContribution(`The "${level}" level must be a record of spec factories keyed by attribute name.`);
64219
+ for (const [attribute, factory] of Object.entries(contributed)) {
64220
+ const entryPath = `${level}.${attribute}`;
64221
+ const invalidEntry = (detail) => runtimeError("CONTRACT.PACK_CONTRIBUTION_INVALID", `Invalid authoring attributeSpecs entry "${entryPath}" contributed by descriptor "${contributedBy}". ${detail}`);
64222
+ if (attribute === "__proto__" || attribute === "constructor" || attribute === "prototype") throw invalidEntry(`Attribute names must not use "${attribute}".`);
64223
+ if (typeof factory !== "function") throw invalidEntry("Each entry must be a spec factory function.");
64224
+ const existingOwner = owners.get(entryPath);
64225
+ if (existingOwner !== void 0) throw runtimeError("CONTRACT.PACK_CONTRIBUTION_INVALID", `Duplicate authoring attributeSpecs entry "${entryPath}". Descriptor "${contributedBy}" conflicts with "${existingOwner}". Each attribute name may be claimed once per level.`);
64226
+ owners.set(entryPath, contributedBy);
64227
+ target[level][attribute] = factory;
64228
+ }
64229
+ }
64230
+ }
64121
64231
  /**
64122
64232
  * Collects the full dotted paths of every well-formed descriptor of
64123
64233
  * `descriptorKind` in a raw contribution tree, using the same boundary
@@ -64654,6 +64764,11 @@ function assembleAuthoringContributions(descriptors) {
64654
64764
  const entityTypes = {};
64655
64765
  const pslBlockDescriptors = {};
64656
64766
  const modelAttributes = {};
64767
+ const attributeSpecs = {
64768
+ model: {},
64769
+ field: {}
64770
+ };
64771
+ const attributeSpecOwners = /* @__PURE__ */ new Map();
64657
64772
  const pathOwners = /* @__PURE__ */ new Map();
64658
64773
  const claimContributedPaths = (namespace, descriptorKind, label, descriptorId) => {
64659
64774
  for (const path of collectContributedDescriptorPaths(namespace, descriptorKind)) {
@@ -64692,6 +64807,7 @@ function assembleAuthoringContributions(descriptors) {
64692
64807
  mergeAuthoringNamespaces(pslBlockDescriptors, descriptor.authoring.pslBlockDescriptors, [], "pslBlock", "pslBlock");
64693
64808
  }
64694
64809
  if (descriptor.authoring?.modelAttributes) mergeAuthoringNamespaces(modelAttributes, descriptor.authoring.modelAttributes, [], "modelAttribute", "modelAttribute");
64810
+ if (descriptor.authoring?.attributeSpecs) mergeAuthoringAttributeSpecs(attributeSpecs, descriptor.authoring.attributeSpecs, descriptorId, attributeSpecOwners);
64695
64811
  }
64696
64812
  const fieldNamespace = field;
64697
64813
  const typeNamespace = type;
@@ -64706,6 +64822,7 @@ function assembleAuthoringContributions(descriptors) {
64706
64822
  entityTypes: entityTypeNamespace,
64707
64823
  pslBlockDescriptors: pslBlockDescriptorNamespace,
64708
64824
  modelAttributes: modelAttributeNamespace,
64825
+ attributeSpecs,
64709
64826
  ...valueObjectStorageDeclaration !== void 0 ? { valueObjectStorageType: valueObjectStorageDeclaration.name } : {}
64710
64827
  };
64711
64828
  }
@@ -66019,12 +66136,13 @@ var SqlCheckConstraintIR = class SqlCheckConstraintIR extends SqlSchemaIRNode {
66019
66136
  * Structural equality for two resolved column defaults, ported from the
66020
66137
  * relational walk's `columnDefaultsEqual` normalized branch: kinds must
66021
66138
  * match; literal values are normalized (Date and temporal-typed strings to
66022
- * ISO instants) then compared canonically (JSON objects match their
66023
- * canonical string form); function expressions compare case- and
66139
+ * ISO instants, and a 64-bit-integer native type's safe-integer number to
66140
+ * its decimal-text spelling) then compared canonically (JSON objects match
66141
+ * their canonical string form); function expressions compare case- and
66024
66142
  * whitespace-insensitively.
66025
66143
  *
66026
- * `nativeType` provides the temporal-normalization context (the actual
66027
- * side's resolved native type in a diff comparison).
66144
+ * `nativeType` provides the temporal- and int64-normalization context (the
66145
+ * actual side's resolved native type in a diff comparison).
66028
66146
  */
66029
66147
  function resolvedDefaultsEqual(expected, actual, nativeType) {
66030
66148
  if (expected.kind !== actual.kind) return false;
@@ -66040,12 +66158,18 @@ function isTemporalNativeType(nativeType) {
66040
66158
  const normalized = nativeType.toLowerCase();
66041
66159
  return normalized.includes("timestamp") || normalized === "date";
66042
66160
  }
66161
+ function isInt64NativeType(nativeType) {
66162
+ if (!nativeType) return false;
66163
+ const normalized = nativeType.toLowerCase();
66164
+ return normalized === "int8" || normalized === "bigint";
66165
+ }
66043
66166
  function normalizeLiteralValue(value, nativeType) {
66044
66167
  if (value instanceof Date) return value.toISOString();
66045
66168
  if (typeof value === "string" && isTemporalNativeType(nativeType)) {
66046
66169
  const parsed = new Date(value);
66047
66170
  if (!Number.isNaN(parsed.getTime())) return parsed.toISOString();
66048
66171
  }
66172
+ if (typeof value === "number" && Number.isSafeInteger(value) && isInt64NativeType(nativeType)) return String(value);
66049
66173
  return value;
66050
66174
  }
66051
66175
  function literalValuesEqual(a, b) {
@@ -66509,6 +66633,1487 @@ var SqlSchemaIR = class extends SqlSchemaIRNode {
66509
66633
  return Object.values(this.tables);
66510
66634
  }
66511
66635
  };
66636
+ /**
66637
+ * Generic Result type for representing success or failure outcomes.
66638
+ *
66639
+ * This is the standard way to return "expected failures" as values rather than
66640
+ * throwing exceptions. See docs/Error Handling.md for the full taxonomy.
66641
+ *
66642
+ * Naming rationale:
66643
+ * - `Ok<T>` / `NotOk<F>` mirror the `ok: true/false` discriminator
66644
+ * - `NotOk` avoids collision with domain types like "Failure" or "Error"
66645
+ * - `failure` property distinguishes from JS Error semantics
66646
+ */
66647
+ /**
66648
+ * Result class that implements both Ok and NotOk variants.
66649
+ */
66650
+ var ResultImpl = class ResultImpl {
66651
+ ok;
66652
+ _value;
66653
+ _failure;
66654
+ constructor(ok, valueOrFailure) {
66655
+ this.ok = ok;
66656
+ if (ok) this._value = valueOrFailure;
66657
+ else this._failure = valueOrFailure;
66658
+ Object.freeze(this);
66659
+ }
66660
+ get value() {
66661
+ if (!this.ok) throw new InternalError("Cannot access value on NotOk result");
66662
+ return this._value;
66663
+ }
66664
+ get failure() {
66665
+ if (this.ok) throw new InternalError("Cannot access failure on Ok result");
66666
+ return this._failure;
66667
+ }
66668
+ /**
66669
+ * Creates a successful result.
66670
+ */
66671
+ static ok(value) {
66672
+ return blindCast(new ResultImpl(true, value));
66673
+ }
66674
+ /**
66675
+ * Creates an unsuccessful result.
66676
+ */
66677
+ static notOk(failure) {
66678
+ return blindCast(new ResultImpl(false, failure));
66679
+ }
66680
+ /**
66681
+ * Asserts that this result is Ok and returns the value.
66682
+ * Throws if the result is NotOk.
66683
+ */
66684
+ assertOk() {
66685
+ if (!this.ok) throw new InternalError("Expected Ok result but got NotOk");
66686
+ return this.value;
66687
+ }
66688
+ /**
66689
+ * Asserts that this result is NotOk and returns the failure.
66690
+ * Throws if the result is Ok.
66691
+ */
66692
+ assertNotOk() {
66693
+ if (this.ok) throw new InternalError("Expected NotOk result but got Ok");
66694
+ return this.failure;
66695
+ }
66696
+ };
66697
+ /**
66698
+ * Creates a successful result.
66699
+ */
66700
+ function ok$1(value) {
66701
+ return ResultImpl.ok(value);
66702
+ }
66703
+ /**
66704
+ * Creates an unsuccessful result.
66705
+ */
66706
+ function notOk(failure) {
66707
+ return ResultImpl.notOk(failure);
66708
+ }
66709
+ /**
66710
+ * Singleton for void success results.
66711
+ * Use this for validation checks that don't produce a value.
66712
+ */
66713
+ const OK_VOID = ResultImpl.ok(void 0);
66714
+ /**
66715
+ * Returns a successful void result.
66716
+ * Use this for validation checks that don't produce a value.
66717
+ */
66718
+ function okVoid() {
66719
+ return OK_VOID;
66720
+ }
66721
+ /**
66722
+ * Name of the synthesised namespace bucket the framework parser uses for
66723
+ * top-level declarations that appear outside any `namespace { … }` block.
66724
+ * The double-underscore decoration signals that the identifier is parser-
66725
+ * synthesised and never appears in user-authored PSL source — writing
66726
+ * `namespace __unspecified__ { … }` is a parse error.
66727
+ *
66728
+ * Distinct from the IR sentinel `__unbound__`: the PSL bucket describes
66729
+ * syntactic absence at the parser layer; the IR sentinel describes a late-
66730
+ * bound storage slot at the IR layer. Per-target interpreters decide how
66731
+ * (or whether) to map the PSL bucket to the IR sentinel.
66732
+ */
66733
+ const UNSPECIFIED_PSL_NAMESPACE_ID = "__unspecified__";
66734
+ /**
66735
+ * Stores `entries`; exposes `models`/`enums`/`compositeTypes` as getters over
66736
+ * it. The getters are prototype members (non-enumerable), so spreading or
66737
+ * `JSON.stringify`-ing a namespace copies only `entries`, never a duplicate view.
66738
+ */
66739
+ var PslNamespaceNode = class {
66740
+ kind = "namespace";
66741
+ name;
66742
+ entries;
66743
+ span;
66744
+ constructor(init) {
66745
+ this.name = init.name;
66746
+ this.entries = init.entries;
66747
+ this.span = init.span;
66748
+ Object.freeze(this);
66749
+ }
66750
+ get models() {
66751
+ return blindCast(Object.values(this.entries["model"] ?? {}));
66752
+ }
66753
+ get compositeTypes() {
66754
+ return blindCast(Object.values(this.entries["compositeType"] ?? {}));
66755
+ }
66756
+ };
66757
+ /** Constructs a {@link PslNamespace}. Use this, never a namespace literal — the accessors must derive from `entries`. */
66758
+ function makePslNamespace(init) {
66759
+ return new PslNamespaceNode(init);
66760
+ }
66761
+ /**
66762
+ * Builds the frozen `entries[kind][name]` container from per-kind arrays.
66763
+ * Built-ins key on their PSL keyword; extension blocks key on their `kind`
66764
+ * discriminator. Call this rather than hand-building the literal.
66765
+ */
66766
+ function makePslNamespaceEntries(models, compositeTypes, extensionBlocks) {
66767
+ const container = {};
66768
+ if (models.length > 0) {
66769
+ const map = {};
66770
+ for (const m of models) map[m.name] = m;
66771
+ container["model"] = Object.freeze(map);
66772
+ }
66773
+ if (compositeTypes.length > 0) {
66774
+ const map = {};
66775
+ for (const ct of compositeTypes) map[ct.name] = ct;
66776
+ container["compositeType"] = Object.freeze(map);
66777
+ }
66778
+ for (const block of extensionBlocks) {
66779
+ const existing = container[block.kind];
66780
+ const newMap = existing ? blindCast({ ...existing }) : {};
66781
+ newMap[block.name] = block;
66782
+ container[block.kind] = Object.freeze(newMap);
66783
+ }
66784
+ return Object.freeze(container);
66785
+ }
66786
+ /**
66787
+ * A token in the red tree. Unlike the green-layer {@link Token} (kind + text
66788
+ * only), a red token also carries its absolute `offset` within the source and a
66789
+ * link back to its `parent` {@link SyntaxNode}, so a cursor anchored on a token
66790
+ * can walk outward (parent, previous/next token, siblings) without re-scanning
66791
+ * from the document root.
66792
+ */
66793
+ var SyntaxToken = class {
66794
+ green;
66795
+ kind;
66796
+ text;
66797
+ offset;
66798
+ parent;
66799
+ /** Position within the parent's children, enabling O(1) sibling navigation without rescanning the green layer. */
66800
+ index;
66801
+ constructor(green, offset, parent, index) {
66802
+ this.green = green;
66803
+ this.kind = green.kind;
66804
+ this.text = green.text;
66805
+ this.offset = offset;
66806
+ this.parent = parent;
66807
+ this.index = index;
66808
+ }
66809
+ get textLength() {
66810
+ return this.text.length;
66811
+ }
66812
+ get endOffset() {
66813
+ return this.offset + this.textLength;
66814
+ }
66815
+ /** Whether `offset` falls within this token, inclusive of both ends. */
66816
+ isInside(offset) {
66817
+ return offset >= this.offset && offset <= this.endOffset;
66818
+ }
66819
+ isOutside(offset) {
66820
+ return !this.isInside(offset);
66821
+ }
66822
+ /** The sibling element immediately after this token within its parent. */
66823
+ get nextSiblingOrToken() {
66824
+ return childAt(this.parent, this.index + 1);
66825
+ }
66826
+ /** The sibling element immediately before this token within its parent. */
66827
+ get prevSiblingOrToken() {
66828
+ return childAt(this.parent, this.index - 1);
66829
+ }
66830
+ /** The next token in document order, crossing node boundaries. */
66831
+ get nextToken() {
66832
+ for (let el = climbingNext(this); el !== void 0; el = climbingNext(el)) {
66833
+ const token = firstToken(el);
66834
+ if (token !== void 0) return token;
66835
+ }
66836
+ }
66837
+ /** The previous token in document order, crossing node boundaries. */
66838
+ get prevToken() {
66839
+ for (let el = climbingPrev(this); el !== void 0; el = climbingPrev(el)) {
66840
+ const token = lastToken(el);
66841
+ if (token !== void 0) return token;
66842
+ }
66843
+ }
66844
+ };
66845
+ var TokenAtOffset = class TokenAtOffset {
66846
+ #state;
66847
+ constructor(state) {
66848
+ this.#state = state;
66849
+ }
66850
+ static none() {
66851
+ return new TokenAtOffset({ kind: "none" });
66852
+ }
66853
+ static single(token) {
66854
+ return new TokenAtOffset({
66855
+ kind: "single",
66856
+ token
66857
+ });
66858
+ }
66859
+ static between(left, right) {
66860
+ return new TokenAtOffset({
66861
+ kind: "between",
66862
+ left,
66863
+ right
66864
+ });
66865
+ }
66866
+ get isEmpty() {
66867
+ return this.#state.kind === "none";
66868
+ }
66869
+ get isBetween() {
66870
+ return this.#state.kind === "between";
66871
+ }
66872
+ leftBiased() {
66873
+ switch (this.#state.kind) {
66874
+ case "none": return;
66875
+ case "single": return this.#state.token;
66876
+ case "between": return this.#state.left;
66877
+ }
66878
+ }
66879
+ rightBiased() {
66880
+ switch (this.#state.kind) {
66881
+ case "none": return;
66882
+ case "single": return this.#state.token;
66883
+ case "between": return this.#state.right;
66884
+ }
66885
+ }
66886
+ };
66887
+ var SyntaxNode = class SyntaxNode {
66888
+ green;
66889
+ offset;
66890
+ parent;
66891
+ /** Position within the parent's children, enabling O(1) sibling navigation without rescanning the green layer. */
66892
+ index;
66893
+ constructor(green, offset, parent, index) {
66894
+ this.green = green;
66895
+ this.offset = offset;
66896
+ this.parent = parent;
66897
+ this.index = index;
66898
+ }
66899
+ get kind() {
66900
+ return this.green.kind;
66901
+ }
66902
+ get textLength() {
66903
+ return this.green.textLength;
66904
+ }
66905
+ get endOffset() {
66906
+ return this.offset + this.textLength;
66907
+ }
66908
+ /** Whether `offset` falls within this node, inclusive of both ends. */
66909
+ isInside(offset) {
66910
+ return offset >= this.offset && offset <= this.endOffset;
66911
+ }
66912
+ isOutside(offset) {
66913
+ return !this.isInside(offset);
66914
+ }
66915
+ get firstChild() {
66916
+ return childAt(this, 0);
66917
+ }
66918
+ get lastChild() {
66919
+ const len = this.green.children.length;
66920
+ if (len === 0) return void 0;
66921
+ return childAt(this, len - 1);
66922
+ }
66923
+ get nextSibling() {
66924
+ return this.parent === void 0 ? void 0 : childAt(this.parent, this.index + 1);
66925
+ }
66926
+ get prevSibling() {
66927
+ return this.parent === void 0 ? void 0 : childAt(this.parent, this.index - 1);
66928
+ }
66929
+ /** The sibling element immediately after this node within its parent. */
66930
+ get nextSiblingOrToken() {
66931
+ return this.nextSibling;
66932
+ }
66933
+ /** The sibling element immediately before this node within its parent. */
66934
+ get prevSiblingOrToken() {
66935
+ return this.prevSibling;
66936
+ }
66937
+ /** The first token in this subtree (depth-first), or `undefined` if empty. */
66938
+ get firstToken() {
66939
+ return firstToken(this);
66940
+ }
66941
+ /** The last token in this subtree (depth-first), or `undefined` if empty. */
66942
+ get lastToken() {
66943
+ return lastToken(this);
66944
+ }
66945
+ *children() {
66946
+ let offset = this.offset;
66947
+ let index = 0;
66948
+ for (const child of this.green.children) {
66949
+ yield wrapElement(child, offset, this, index);
66950
+ offset += elementTextLength(child);
66951
+ index++;
66952
+ }
66953
+ }
66954
+ *childNodes() {
66955
+ for (const child of this.children()) if (child instanceof SyntaxNode) yield child;
66956
+ }
66957
+ *ancestors() {
66958
+ let current = this.parent;
66959
+ while (current) {
66960
+ yield current;
66961
+ current = current.parent;
66962
+ }
66963
+ }
66964
+ /** The nearest match, testing this node itself before walking its ancestors. */
66965
+ findAncestor(cast) {
66966
+ const self = cast(this);
66967
+ if (self !== void 0) return self;
66968
+ for (const ancestor of this.ancestors()) {
66969
+ const result = cast(ancestor);
66970
+ if (result !== void 0) return result;
66971
+ }
66972
+ }
66973
+ *descendants() {
66974
+ const stack = [this];
66975
+ for (let el = stack.pop(); el !== void 0; el = stack.pop()) {
66976
+ yield el;
66977
+ if (el instanceof SyntaxNode) {
66978
+ const children = Array.from(el.children());
66979
+ for (let i = children.length - 1; i >= 0; i--) {
66980
+ const child = children[i];
66981
+ if (child !== void 0) stack.push(child);
66982
+ }
66983
+ }
66984
+ }
66985
+ }
66986
+ *tokens() {
66987
+ for (const el of this.descendants()) if (el instanceof SyntaxToken) yield el;
66988
+ }
66989
+ /**
66990
+ * The token(s) at `offset`. The between-two-tokens case (offset exactly on a
66991
+ * token seam) is represented explicitly so callers can left/right bias.
66992
+ */
66993
+ tokenAtOffset(offset) {
66994
+ return tokenAtOffsetOf(this, offset);
66995
+ }
66996
+ /**
66997
+ * The smallest element fully containing the range `[start, end]`. At a seam
66998
+ * (and for empty ranges) the left-hand element is preferred, matching
66999
+ * {@link containsOffset}'s inclusive span.
67000
+ */
67001
+ coveringElement(start, end) {
67002
+ let result = this;
67003
+ for (;;) {
67004
+ if (result instanceof SyntaxToken) return result;
67005
+ let next;
67006
+ for (const child of result.children()) if (containsRange(child, start, end)) {
67007
+ next = child;
67008
+ break;
67009
+ }
67010
+ if (next === void 0) return result;
67011
+ result = next;
67012
+ }
67013
+ }
67014
+ };
67015
+ function elementTextLength(el) {
67016
+ return el.type === "token" ? el.text.length : el.textLength;
67017
+ }
67018
+ function elementLength(el) {
67019
+ return el instanceof SyntaxToken ? el.text.length : el.textLength;
67020
+ }
67021
+ /**
67022
+ * Whether `el` contains `offset`. The span is inclusive on both ends so a seam
67023
+ * offset touches both neighbours.
67024
+ */
67025
+ function containsOffset(el, offset) {
67026
+ const start = el.offset;
67027
+ const len = elementLength(el);
67028
+ return offset >= start && offset <= start + len;
67029
+ }
67030
+ function containsRange(el, start, end) {
67031
+ const elStart = el.offset;
67032
+ const len = elementLength(el);
67033
+ return elStart <= start && end <= elStart + len;
67034
+ }
67035
+ function tokenAtOffsetOf(el, offset) {
67036
+ if (el instanceof SyntaxToken) return TokenAtOffset.single(el);
67037
+ let left;
67038
+ let right;
67039
+ for (const child of el.children()) {
67040
+ if (!containsOffset(child, offset)) continue;
67041
+ if (left === void 0) left = child;
67042
+ else {
67043
+ right = child;
67044
+ break;
67045
+ }
67046
+ }
67047
+ if (left === void 0) return TokenAtOffset.none();
67048
+ if (right === void 0) return tokenAtOffsetOf(left, offset);
67049
+ const leftToken = tokenAtOffsetOf(left, offset).rightBiased();
67050
+ const rightToken = tokenAtOffsetOf(right, offset).leftBiased();
67051
+ if (leftToken !== void 0 && rightToken !== void 0) return TokenAtOffset.between(leftToken, rightToken);
67052
+ if (leftToken !== void 0) return TokenAtOffset.single(leftToken);
67053
+ if (rightToken !== void 0) return TokenAtOffset.single(rightToken);
67054
+ return TokenAtOffset.none();
67055
+ }
67056
+ function firstToken(el) {
67057
+ if (el instanceof SyntaxToken) return el;
67058
+ for (const child of el.children()) {
67059
+ const token = firstToken(child);
67060
+ if (token !== void 0) return token;
67061
+ }
67062
+ }
67063
+ function lastToken(el) {
67064
+ if (el instanceof SyntaxToken) return el;
67065
+ const children = Array.from(el.children());
67066
+ for (let i = children.length - 1; i >= 0; i--) {
67067
+ const child = children[i];
67068
+ if (child !== void 0) {
67069
+ const token = lastToken(child);
67070
+ if (token !== void 0) return token;
67071
+ }
67072
+ }
67073
+ }
67074
+ function climbingNext(el) {
67075
+ let current = el;
67076
+ for (;;) {
67077
+ const parent = current.parent;
67078
+ if (parent === void 0) return void 0;
67079
+ const sibling = childAt(parent, current.index + 1);
67080
+ if (sibling !== void 0) return sibling;
67081
+ current = parent;
67082
+ }
67083
+ }
67084
+ function climbingPrev(el) {
67085
+ let current = el;
67086
+ for (;;) {
67087
+ const parent = current.parent;
67088
+ if (parent === void 0) return void 0;
67089
+ const sibling = childAt(parent, current.index - 1);
67090
+ if (sibling !== void 0) return sibling;
67091
+ current = parent;
67092
+ }
67093
+ }
67094
+ function wrapElement(green, offset, parent, index) {
67095
+ if (green.type === "token") return new SyntaxToken(green, offset, parent, index);
67096
+ return new SyntaxNode(green, offset, parent, index);
67097
+ }
67098
+ function childAt(node, index) {
67099
+ const children = node.green.children;
67100
+ const target = children[index];
67101
+ if (target === void 0) return void 0;
67102
+ let offset = node.offset;
67103
+ for (let i = 0; i < index; i++) {
67104
+ const child = children[i];
67105
+ if (child !== void 0) offset += elementTextLength(child);
67106
+ }
67107
+ return wrapElement(target, offset, node, index);
67108
+ }
67109
+ function findChildToken(node, kind) {
67110
+ for (const child of node.children()) if (!(child instanceof SyntaxNode) && child.kind === kind) return child;
67111
+ }
67112
+ function findFirstChild(node, cast) {
67113
+ for (const child of node.childNodes()) {
67114
+ const result = cast(child);
67115
+ if (result !== void 0) return result;
67116
+ }
67117
+ }
67118
+ function* filterChildren(node, cast) {
67119
+ for (const child of node.childNodes()) {
67120
+ const result = cast(child);
67121
+ if (result !== void 0) yield result;
67122
+ }
67123
+ }
67124
+ var IdentifierAst = class IdentifierAst {
67125
+ syntax;
67126
+ constructor(syntax) {
67127
+ this.syntax = syntax;
67128
+ }
67129
+ token() {
67130
+ return findChildToken(this.syntax, "Ident");
67131
+ }
67132
+ name() {
67133
+ return this.token()?.text;
67134
+ }
67135
+ static cast(node) {
67136
+ return node.kind === "Identifier" ? new IdentifierAst(node) : void 0;
67137
+ }
67138
+ };
67139
+ /** A namespace-qualified name, e.g. `pgvector.Vector` or `supabase:auth.User`. */
67140
+ var QualifiedNameAst = class QualifiedNameAst {
67141
+ syntax;
67142
+ constructor(syntax) {
67143
+ this.syntax = syntax;
67144
+ }
67145
+ #segmentBefore(boundary) {
67146
+ let found;
67147
+ for (const segment of filterChildren(this.syntax, IdentifierAst.cast)) {
67148
+ if (segment.syntax.offset >= boundary) break;
67149
+ found = segment;
67150
+ }
67151
+ return found;
67152
+ }
67153
+ #segmentAfter(boundary) {
67154
+ for (const segment of filterChildren(this.syntax, IdentifierAst.cast)) if (segment.syntax.offset > boundary) return segment;
67155
+ }
67156
+ #separatorCount(kind) {
67157
+ let count = 0;
67158
+ for (const child of this.syntax.children()) if (!(child instanceof SyntaxNode) && child.kind === kind) count++;
67159
+ return count;
67160
+ }
67161
+ colon() {
67162
+ return findChildToken(this.syntax, "Colon");
67163
+ }
67164
+ dot() {
67165
+ return findChildToken(this.syntax, "Dot");
67166
+ }
67167
+ space() {
67168
+ const colon = this.colon();
67169
+ if (!colon) return void 0;
67170
+ return this.#segmentBefore(colon.offset);
67171
+ }
67172
+ namespace() {
67173
+ const dot = this.dot();
67174
+ if (!dot) return void 0;
67175
+ return this.#segmentBefore(dot.offset);
67176
+ }
67177
+ identifier() {
67178
+ const dot = this.dot();
67179
+ if (dot) return this.#segmentAfter(dot.offset);
67180
+ const colon = this.colon();
67181
+ if (colon) return this.#segmentAfter(colon.offset);
67182
+ return findFirstChild(this.syntax, IdentifierAst.cast);
67183
+ }
67184
+ /**
67185
+ * Every identifier segment, in source order. A bare `Vector` yields
67186
+ * `['Vector']`; a qualified `pgvector.Vector` yields `['pgvector', 'Vector']`.
67187
+ */
67188
+ path() {
67189
+ const segments = [];
67190
+ for (const segment of filterChildren(this.syntax, IdentifierAst.cast)) {
67191
+ const text = segment.token()?.text;
67192
+ if (text !== void 0) segments.push(text);
67193
+ }
67194
+ return segments;
67195
+ }
67196
+ /** True iff this is a single unqualified identifier whose text equals `name`. */
67197
+ isSimpleName(name) {
67198
+ if (this.dot() !== void 0 || this.colon() !== void 0) return false;
67199
+ return this.identifier()?.token()?.text === name;
67200
+ }
67201
+ /**
67202
+ * Flags a malformed name with more qualifier segments than allowed (a second
67203
+ * `:`-space or a second `.`-namespace).
67204
+ */
67205
+ isOverQualified() {
67206
+ return this.#separatorCount("Dot") > 1 || this.#separatorCount("Colon") > 1;
67207
+ }
67208
+ static cast(node) {
67209
+ return node.kind === "QualifiedName" ? new QualifiedNameAst(node) : void 0;
67210
+ }
67211
+ };
67212
+ var FunctionCallAst = class FunctionCallAst {
67213
+ syntax;
67214
+ constructor(syntax) {
67215
+ this.syntax = syntax;
67216
+ }
67217
+ /** The qualified-name callee, or `undefined` when identifier segments sit directly under the node. */
67218
+ name() {
67219
+ return findFirstChild(this.syntax, QualifiedNameAst.cast);
67220
+ }
67221
+ /**
67222
+ * The dotted call path, in source order. A bare `Vector(…)` yields
67223
+ * `['Vector']`; a namespace-qualified `pgvector.Vector(…)` yields
67224
+ * `['pgvector', 'Vector']`. Empty when the call carries no identifier.
67225
+ */
67226
+ path() {
67227
+ const qualified = this.name();
67228
+ const segments = [];
67229
+ for (const segment of filterChildren(qualified?.syntax ?? this.syntax, IdentifierAst.cast)) {
67230
+ const text = segment.token()?.text;
67231
+ if (text !== void 0) segments.push(text);
67232
+ }
67233
+ return segments;
67234
+ }
67235
+ lparen() {
67236
+ return findChildToken(this.syntax, "LParen");
67237
+ }
67238
+ rparen() {
67239
+ return findChildToken(this.syntax, "RParen");
67240
+ }
67241
+ *args() {
67242
+ yield* filterChildren(this.syntax, AttributeArgAst.cast);
67243
+ }
67244
+ static cast(node) {
67245
+ return node.kind === "FunctionCall" ? new FunctionCallAst(node) : void 0;
67246
+ }
67247
+ };
67248
+ var ArrayLiteralAst = class ArrayLiteralAst {
67249
+ syntax;
67250
+ constructor(syntax) {
67251
+ this.syntax = syntax;
67252
+ }
67253
+ lbracket() {
67254
+ return findChildToken(this.syntax, "LBracket");
67255
+ }
67256
+ rbracket() {
67257
+ return findChildToken(this.syntax, "RBracket");
67258
+ }
67259
+ *elements() {
67260
+ yield* filterChildren(this.syntax, castExpression);
67261
+ }
67262
+ static cast(node) {
67263
+ return node.kind === "ArrayLiteral" ? new ArrayLiteralAst(node) : void 0;
67264
+ }
67265
+ };
67266
+ const HEX = /^[0-9a-fA-F]+$/;
67267
+ function decodeFixedHex(raw, start, width) {
67268
+ if (start + width > raw.length) return void 0;
67269
+ const hex = raw.slice(start, start + width);
67270
+ if (!HEX.test(hex)) return void 0;
67271
+ return String.fromCharCode(Number.parseInt(hex, 16));
67272
+ }
67273
+ function decodeStringLiteral(raw) {
67274
+ let out = "";
67275
+ let i = 0;
67276
+ while (i < raw.length) {
67277
+ const ch = raw.charAt(i);
67278
+ if (ch !== "\\" || i + 1 >= raw.length) {
67279
+ out += ch;
67280
+ i++;
67281
+ continue;
67282
+ }
67283
+ const next = raw.charAt(i + 1);
67284
+ switch (next) {
67285
+ case "n":
67286
+ out += "\n";
67287
+ i += 2;
67288
+ continue;
67289
+ case "r":
67290
+ out += "\r";
67291
+ i += 2;
67292
+ continue;
67293
+ case "t":
67294
+ out += " ";
67295
+ i += 2;
67296
+ continue;
67297
+ case "\"":
67298
+ out += "\"";
67299
+ i += 2;
67300
+ continue;
67301
+ case "'":
67302
+ out += "'";
67303
+ i += 2;
67304
+ continue;
67305
+ case "\\":
67306
+ out += "\\";
67307
+ i += 2;
67308
+ continue;
67309
+ case "x": {
67310
+ const decoded = decodeFixedHex(raw, i + 2, 2);
67311
+ if (decoded === void 0) {
67312
+ out += "\\x";
67313
+ i += 2;
67314
+ continue;
67315
+ }
67316
+ out += decoded;
67317
+ i += 4;
67318
+ continue;
67319
+ }
67320
+ case "u": {
67321
+ const decoded = decodeFixedHex(raw, i + 2, 4);
67322
+ if (decoded === void 0) {
67323
+ out += "\\u";
67324
+ i += 2;
67325
+ continue;
67326
+ }
67327
+ out += decoded;
67328
+ i += 6;
67329
+ continue;
67330
+ }
67331
+ default:
67332
+ out += `\\${next}`;
67333
+ i += 2;
67334
+ continue;
67335
+ }
67336
+ }
67337
+ return out;
67338
+ }
67339
+ var StringLiteralExprAst = class StringLiteralExprAst {
67340
+ syntax;
67341
+ constructor(syntax) {
67342
+ this.syntax = syntax;
67343
+ }
67344
+ token() {
67345
+ return findChildToken(this.syntax, "StringLiteral");
67346
+ }
67347
+ value() {
67348
+ const tok = this.token();
67349
+ if (!tok) return void 0;
67350
+ return decodeStringLiteral(tok.text.slice(1, -1));
67351
+ }
67352
+ static cast(node) {
67353
+ return node.kind === "StringLiteralExpr" ? new StringLiteralExprAst(node) : void 0;
67354
+ }
67355
+ };
67356
+ var NumberLiteralExprAst = class NumberLiteralExprAst {
67357
+ syntax;
67358
+ constructor(syntax) {
67359
+ this.syntax = syntax;
67360
+ }
67361
+ token() {
67362
+ return findChildToken(this.syntax, "NumberLiteral");
67363
+ }
67364
+ value() {
67365
+ const tok = this.token();
67366
+ if (!tok) return void 0;
67367
+ return Number(tok.text);
67368
+ }
67369
+ static cast(node) {
67370
+ return node.kind === "NumberLiteralExpr" ? new NumberLiteralExprAst(node) : void 0;
67371
+ }
67372
+ };
67373
+ var BooleanLiteralExprAst = class BooleanLiteralExprAst {
67374
+ syntax;
67375
+ constructor(syntax) {
67376
+ this.syntax = syntax;
67377
+ }
67378
+ token() {
67379
+ return findChildToken(this.syntax, "Ident");
67380
+ }
67381
+ value() {
67382
+ const tok = this.token();
67383
+ if (!tok) return void 0;
67384
+ if (tok.text === "true") return true;
67385
+ if (tok.text === "false") return false;
67386
+ }
67387
+ static cast(node) {
67388
+ return node.kind === "BooleanLiteralExpr" ? new BooleanLiteralExprAst(node) : void 0;
67389
+ }
67390
+ };
67391
+ var ObjectLiteralExprAst = class ObjectLiteralExprAst {
67392
+ syntax;
67393
+ constructor(syntax) {
67394
+ this.syntax = syntax;
67395
+ }
67396
+ lbrace() {
67397
+ return findChildToken(this.syntax, "LBrace");
67398
+ }
67399
+ rbrace() {
67400
+ return findChildToken(this.syntax, "RBrace");
67401
+ }
67402
+ *fields() {
67403
+ yield* filterChildren(this.syntax, ObjectFieldAst.cast);
67404
+ }
67405
+ static cast(node) {
67406
+ return node.kind === "ObjectLiteralExpr" ? new ObjectLiteralExprAst(node) : void 0;
67407
+ }
67408
+ };
67409
+ var ObjectFieldAst = class ObjectFieldAst {
67410
+ syntax;
67411
+ constructor(syntax) {
67412
+ this.syntax = syntax;
67413
+ }
67414
+ key() {
67415
+ for (const child of this.syntax.children()) {
67416
+ if (!(child instanceof SyntaxNode)) {
67417
+ if (child.kind === "Colon") break;
67418
+ continue;
67419
+ }
67420
+ return IdentifierAst.cast(child);
67421
+ }
67422
+ }
67423
+ /**
67424
+ * The field's logical key name, unquoted. An identifier key (`length:`) yields
67425
+ * its text; a string-literal key (`"length":`) yields the decoded string.
67426
+ * `undefined` when the field carries no key node.
67427
+ */
67428
+ keyName() {
67429
+ for (const child of this.syntax.children()) {
67430
+ if (!(child instanceof SyntaxNode)) {
67431
+ if (child.kind === "Colon") break;
67432
+ continue;
67433
+ }
67434
+ const identifier = IdentifierAst.cast(child);
67435
+ if (identifier) return identifier.token()?.text;
67436
+ const stringKey = StringLiteralExprAst.cast(child);
67437
+ if (stringKey) return stringKey.value();
67438
+ return;
67439
+ }
67440
+ }
67441
+ colon() {
67442
+ return findChildToken(this.syntax, "Colon");
67443
+ }
67444
+ value() {
67445
+ if (this.colon()) {
67446
+ let pastColon = false;
67447
+ for (const child of this.syntax.children()) {
67448
+ if (!(child instanceof SyntaxNode)) {
67449
+ if (child.kind === "Colon") pastColon = true;
67450
+ continue;
67451
+ }
67452
+ if (pastColon) {
67453
+ const expr = castExpression(child);
67454
+ if (expr) return expr;
67455
+ }
67456
+ }
67457
+ return;
67458
+ }
67459
+ return findFirstChild(this.syntax, castExpression);
67460
+ }
67461
+ static cast(node) {
67462
+ return node.kind === "ObjectField" ? new ObjectFieldAst(node) : void 0;
67463
+ }
67464
+ };
67465
+ function castExpression(node) {
67466
+ return FunctionCallAst.cast(node) ?? ArrayLiteralAst.cast(node) ?? StringLiteralExprAst.cast(node) ?? NumberLiteralExprAst.cast(node) ?? BooleanLiteralExprAst.cast(node) ?? ObjectLiteralExprAst.cast(node) ?? IdentifierAst.cast(node);
67467
+ }
67468
+ var AttributeArgAst = class AttributeArgAst {
67469
+ syntax;
67470
+ constructor(syntax) {
67471
+ this.syntax = syntax;
67472
+ }
67473
+ name() {
67474
+ if (!this.colon()) return void 0;
67475
+ return findFirstChild(this.syntax, IdentifierAst.cast);
67476
+ }
67477
+ colon() {
67478
+ return findChildToken(this.syntax, "Colon");
67479
+ }
67480
+ value() {
67481
+ if (this.colon()) {
67482
+ let pastColon = false;
67483
+ for (const child of this.syntax.children()) {
67484
+ if (!(child instanceof SyntaxNode)) {
67485
+ if (child.kind === "Colon") pastColon = true;
67486
+ continue;
67487
+ }
67488
+ if (pastColon) {
67489
+ const expr = castExpression(child);
67490
+ if (expr) return expr;
67491
+ }
67492
+ }
67493
+ return;
67494
+ }
67495
+ return findFirstChild(this.syntax, castExpression);
67496
+ }
67497
+ static cast(node) {
67498
+ return node.kind === "AttributeArg" ? new AttributeArgAst(node) : void 0;
67499
+ }
67500
+ };
67501
+ function blockAttribute(name, config) {
67502
+ return {
67503
+ level: "block",
67504
+ name,
67505
+ positional: config.positional ?? [],
67506
+ named: config.named ?? {},
67507
+ ...config.refine !== void 0 ? { refine: config.refine } : {}
67508
+ };
67509
+ }
67510
+ function nodePslSpan(node, sourceFile) {
67511
+ const start = node.offset;
67512
+ const end = start + node.green.textLength;
67513
+ return {
67514
+ start: offsetToPslPosition(start, sourceFile),
67515
+ end: offsetToPslPosition(end, sourceFile)
67516
+ };
67517
+ }
67518
+ function offsetToPslPosition(offset, sourceFile) {
67519
+ const position = sourceFile.positionAt(offset);
67520
+ return {
67521
+ offset,
67522
+ line: position.line + 1,
67523
+ column: position.character + 1
67524
+ };
67525
+ }
67526
+ const ATTRIBUTE_DIAGNOSTIC_CODE = "PSL_INVALID_ATTRIBUTE_SYNTAX";
67527
+ function leafDiagnostic(ctx, node, message, code = ATTRIBUTE_DIAGNOSTIC_CODE) {
67528
+ return {
67529
+ code,
67530
+ message,
67531
+ sourceId: ctx.sourceId,
67532
+ span: nodePslSpan(node.syntax, ctx.sourceFile)
67533
+ };
67534
+ }
67535
+ function bool() {
67536
+ return {
67537
+ kind: "bool",
67538
+ label: "boolean",
67539
+ parse: (arg, ctx) => {
67540
+ const literal = BooleanLiteralExprAst.cast(arg.syntax);
67541
+ if (literal !== void 0) {
67542
+ const value = literal.value();
67543
+ if (value !== void 0) return ok$1(value);
67544
+ }
67545
+ return notOk([leafDiagnostic(ctx, arg, "Expected a boolean literal")]);
67546
+ }
67547
+ };
67548
+ }
67549
+ function entityRef() {
67550
+ return {
67551
+ kind: "entityRef",
67552
+ label: "model name",
67553
+ parse: (arg, ctx) => {
67554
+ const identifier = IdentifierAst.cast(arg.syntax);
67555
+ if (identifier === void 0) return notOk([leafDiagnostic(ctx, arg, "Expected a model name")]);
67556
+ const name = identifier.name();
67557
+ if (name === void 0) return notOk([leafDiagnostic(ctx, arg, "Expected a model name")]);
67558
+ return ok$1(name);
67559
+ }
67560
+ };
67561
+ }
67562
+ function parseFieldName(arg, ctx, model) {
67563
+ const identifier = IdentifierAst.cast(arg.syntax);
67564
+ if (identifier === void 0) return notOk([leafDiagnostic(ctx, arg, "Expected a field name")]);
67565
+ const name = identifier.name();
67566
+ if (name === void 0) return notOk([leafDiagnostic(ctx, arg, "Expected a field name")]);
67567
+ if (model !== void 0 && !Object.hasOwn(model.fields, name)) return notOk([leafDiagnostic(ctx, arg, `Field "${name}" does not exist on model "${model.name}"`)]);
67568
+ return ok$1(name);
67569
+ }
67570
+ function fieldRef() {
67571
+ return {
67572
+ kind: "fieldRef",
67573
+ label: "field name",
67574
+ parse: (arg, ctx) => parseFieldName(arg, ctx, ctx.selfModel)
67575
+ };
67576
+ }
67577
+ function referencedFieldRef() {
67578
+ return {
67579
+ kind: "referencedFieldRef",
67580
+ label: "field name",
67581
+ parse: (arg, ctx) => parseFieldName(arg, ctx, ctx.resolveReferencedModel())
67582
+ };
67583
+ }
67584
+ function interpretArgs(args, spec, ctx, span) {
67585
+ const diagnostics = [];
67586
+ const output = {};
67587
+ const seen = /* @__PURE__ */ new Set();
67588
+ let positionalSlot = 0;
67589
+ let reportedExcess = false;
67590
+ for (const arg of args) {
67591
+ const name = arg.name()?.name();
67592
+ let key;
67593
+ let param;
67594
+ if (name === void 0) {
67595
+ const posParam = spec.positional[positionalSlot];
67596
+ if (posParam === void 0) {
67597
+ if (!reportedExcess) {
67598
+ diagnostics.push(diagnostic(`Attribute "${spec.name}" received too many positional arguments`, ctx, span));
67599
+ reportedExcess = true;
67600
+ }
67601
+ continue;
67602
+ }
67603
+ positionalSlot += 1;
67604
+ key = posParam.key;
67605
+ param = posParam.type;
67606
+ } else {
67607
+ const namedParam = Object.hasOwn(spec.named, name) ? spec.named[name] : void 0;
67608
+ if (namedParam === void 0) {
67609
+ diagnostics.push(diagnostic(`Attribute "${spec.name}" received unknown argument "${name}"`, ctx, nodePslSpan(arg.syntax, ctx.sourceFile)));
67610
+ continue;
67611
+ }
67612
+ key = name;
67613
+ param = namedParam;
67614
+ }
67615
+ if (seen.has(key)) {
67616
+ diagnostics.push(diagnostic(`Attribute "${spec.name}" received duplicate argument "${key}"`, ctx, nodePslSpan(arg.syntax, ctx.sourceFile)));
67617
+ continue;
67618
+ }
67619
+ seen.add(key);
67620
+ const result = parseArgValue(arg, param, ctx, diagnostics);
67621
+ if (result.ok) output[key] = result.value;
67622
+ }
67623
+ const finalized = /* @__PURE__ */ new Set();
67624
+ const finalizeAbsentKey = (key, positionalParam, namedParam) => {
67625
+ if (finalized.has(key) || seen.has(key)) return;
67626
+ finalized.add(key);
67627
+ const effective = namedParam ?? positionalParam;
67628
+ if (effective === void 0) return;
67629
+ if (isOptionalArgType(effective)) {
67630
+ if (effective.hasDefault) output[key] = effective.defaultValue;
67631
+ return;
67632
+ }
67633
+ diagnostics.push(diagnostic(`Attribute "${spec.name}" is missing required argument "${key}"`, ctx, span));
67634
+ };
67635
+ for (const param of spec.positional) {
67636
+ const namedParam = Object.hasOwn(spec.named, param.key) ? spec.named[param.key] : void 0;
67637
+ finalizeAbsentKey(param.key, param.type, namedParam);
67638
+ }
67639
+ for (const key of Object.keys(spec.named)) finalizeAbsentKey(key, void 0, spec.named[key]);
67640
+ if (diagnostics.length > 0) return notOk(diagnostics);
67641
+ return ok$1(output);
67642
+ }
67643
+ function parseArgValue(arg, argType, ctx, diagnostics) {
67644
+ const value = arg.value();
67645
+ if (value === void 0) {
67646
+ const missing = diagnostic("Attribute argument is missing a value", ctx, nodePslSpan(arg.syntax, ctx.sourceFile));
67647
+ diagnostics.push(missing);
67648
+ return notOk([missing]);
67649
+ }
67650
+ const result = argType.parse(value, ctx);
67651
+ if (!result.ok) for (const failure of result.failure) diagnostics.push(failure);
67652
+ return result;
67653
+ }
67654
+ function isOptionalArgType(param) {
67655
+ return "optional" in param && param.optional === true;
67656
+ }
67657
+ function diagnostic(message, ctx, span) {
67658
+ return {
67659
+ code: ATTRIBUTE_DIAGNOSTIC_CODE,
67660
+ message,
67661
+ sourceId: ctx.sourceId,
67662
+ span
67663
+ };
67664
+ }
67665
+ function funcCall(name, sig) {
67666
+ return {
67667
+ kind: "funcCall",
67668
+ label: `${name}()`,
67669
+ name,
67670
+ signature: sig,
67671
+ parse: (arg, ctx) => {
67672
+ const guard = matchCallee(arg, name, ctx);
67673
+ if (!guard.ok) return guard;
67674
+ const span = nodePslSpan(guard.value.syntax, ctx.sourceFile);
67675
+ const bound = interpretArgs(guard.value.args(), {
67676
+ name,
67677
+ positional: sig.positional ?? [],
67678
+ named: sig.named ?? {}
67679
+ }, ctx, span);
67680
+ if (!bound.ok) return notOk(bound.failure);
67681
+ return ok$1({
67682
+ fn: name,
67683
+ span,
67684
+ args: bound.value
67685
+ });
67686
+ }
67687
+ };
67688
+ }
67689
+ function matchCallee(arg, name, ctx) {
67690
+ const call = FunctionCallAst.cast(arg.syntax);
67691
+ if (call === void 0) return notOk([leafDiagnostic(ctx, arg, "Expected a function call")]);
67692
+ const qname = call.name();
67693
+ if (qname === void 0 || qname.dot() !== void 0 || qname.colon() !== void 0) return notOk([leafDiagnostic(ctx, arg, "Expected a function call")]);
67694
+ const calleeName = qname.identifier()?.token()?.text;
67695
+ if (calleeName === void 0) return notOk([leafDiagnostic(ctx, arg, "Expected a function call")]);
67696
+ if (calleeName !== name) return notOk([leafDiagnostic(ctx, arg, `Expected ${name}()`)]);
67697
+ return ok$1(call);
67698
+ }
67699
+ function identifier(name) {
67700
+ return {
67701
+ kind: "identifier",
67702
+ label: name,
67703
+ name,
67704
+ parse: (arg, ctx) => {
67705
+ const identifier = IdentifierAst.cast(arg.syntax);
67706
+ if (identifier !== void 0 && identifier.name() === name) return ok$1(name);
67707
+ return notOk([leafDiagnostic(ctx, arg, `Expected ${name}`)]);
67708
+ }
67709
+ };
67710
+ }
67711
+ function int(opts) {
67712
+ const min = opts?.min;
67713
+ const max = opts?.max;
67714
+ return {
67715
+ kind: "int",
67716
+ label: "integer",
67717
+ ...min === void 0 ? {} : { min },
67718
+ ...max === void 0 ? {} : { max },
67719
+ parse: (arg, ctx) => {
67720
+ const literal = NumberLiteralExprAst.cast(arg.syntax);
67721
+ if (literal !== void 0) {
67722
+ const value = literal.value();
67723
+ if (value !== void 0 && Number.isInteger(value)) {
67724
+ if ((min === void 0 || value >= min) && (max === void 0 || value <= max)) return ok$1(value);
67725
+ return notOk([leafDiagnostic(ctx, arg, rangeMessage(min, max))]);
67726
+ }
67727
+ }
67728
+ return notOk([leafDiagnostic(ctx, arg, "Expected an integer literal")]);
67729
+ }
67730
+ };
67731
+ }
67732
+ function rangeMessage(min, max) {
67733
+ if (min !== void 0 && max !== void 0) return `Expected an integer between ${min} and ${max}`;
67734
+ if (min !== void 0) return `Expected an integer greater than or equal to ${min}`;
67735
+ return `Expected an integer less than or equal to ${max}`;
67736
+ }
67737
+ function list(of, opts) {
67738
+ const allowEmpty = opts?.allowEmpty ?? true;
67739
+ const unique = opts?.unique ?? false;
67740
+ return {
67741
+ kind: "list",
67742
+ label: `${of.label}[]`,
67743
+ of,
67744
+ allowEmpty,
67745
+ unique,
67746
+ parse: (arg, ctx) => {
67747
+ const literal = ArrayLiteralAst.cast(arg.syntax);
67748
+ if (literal === void 0) return notOk([leafDiagnostic(ctx, arg, `Expected a list of ${of.label}`)]);
67749
+ const diagnostics = [];
67750
+ const parsed = [];
67751
+ let count = 0;
67752
+ for (const element of literal.elements()) {
67753
+ count += 1;
67754
+ const result = of.parse(element, ctx);
67755
+ if (result.ok) parsed.push({
67756
+ node: element,
67757
+ value: result.value
67758
+ });
67759
+ else diagnostics.push(...result.failure);
67760
+ }
67761
+ if (!allowEmpty && count === 0) diagnostics.push(leafDiagnostic(ctx, arg, "Expected a non-empty list"));
67762
+ if (unique) {
67763
+ const seen = /* @__PURE__ */ new Set();
67764
+ for (const { node, value } of parsed) if (seen.has(value)) diagnostics.push(leafDiagnostic(ctx, node, "Duplicate list entry"));
67765
+ else seen.add(value);
67766
+ }
67767
+ if (diagnostics.length > 0) return notOk(diagnostics);
67768
+ return ok$1(parsed.map((entry) => entry.value));
67769
+ }
67770
+ };
67771
+ }
67772
+ function num(value) {
67773
+ if (value === void 0) return {
67774
+ kind: "num",
67775
+ label: "number",
67776
+ value: void 0,
67777
+ parse: (arg, ctx) => {
67778
+ const literal = NumberLiteralExprAst.cast(arg.syntax);
67779
+ if (literal !== void 0) {
67780
+ const parsed = literal.value();
67781
+ if (parsed !== void 0) return ok$1(parsed);
67782
+ }
67783
+ return notOk([leafDiagnostic(ctx, arg, "Expected a number literal")]);
67784
+ }
67785
+ };
67786
+ return {
67787
+ kind: "num",
67788
+ label: String(value),
67789
+ value,
67790
+ parse: (arg, ctx) => {
67791
+ const literal = NumberLiteralExprAst.cast(arg.syntax);
67792
+ if (literal !== void 0) {
67793
+ if (literal.value() === value) return ok$1(value);
67794
+ }
67795
+ return notOk([leafDiagnostic(ctx, arg, `Expected ${value}`)]);
67796
+ }
67797
+ };
67798
+ }
67799
+ function oneOf(...alts) {
67800
+ const label = alts.map((alt) => alt.label).join(" | ");
67801
+ return {
67802
+ kind: "oneOf",
67803
+ label,
67804
+ alternatives: alts,
67805
+ parse: (arg, ctx) => {
67806
+ for (const alt of alts) {
67807
+ const result = blindCast(alt.parse)(arg, ctx);
67808
+ if (result.ok) return ok$1(blindCast(result.value));
67809
+ }
67810
+ return notOk([leafDiagnostic(ctx, arg, `Expected one of: ${label}`)]);
67811
+ }
67812
+ };
67813
+ }
67814
+ function record(of) {
67815
+ return {
67816
+ kind: "record",
67817
+ label: `{ [key]: ${of.label} }`,
67818
+ of,
67819
+ parse: (arg, ctx) => {
67820
+ const literal = ObjectLiteralExprAst.cast(arg.syntax);
67821
+ if (literal === void 0) return notOk([leafDiagnostic(ctx, arg, "Expected an object literal")]);
67822
+ const diagnostics = [];
67823
+ const entries = [];
67824
+ const keys = /* @__PURE__ */ new Set();
67825
+ for (const field of Array.from(literal.fields())) {
67826
+ const key = field.keyName();
67827
+ if (key === void 0) {
67828
+ diagnostics.push(leafDiagnostic(ctx, field, "Expected a key"));
67829
+ continue;
67830
+ }
67831
+ const value = field.value();
67832
+ if (value === void 0) {
67833
+ diagnostics.push(leafDiagnostic(ctx, field, `Expected a value for key "${key}"`));
67834
+ continue;
67835
+ }
67836
+ const parsed = of.parse(value, ctx);
67837
+ if (!parsed.ok) {
67838
+ diagnostics.push(...parsed.failure);
67839
+ continue;
67840
+ }
67841
+ if (keys.has(key)) {
67842
+ diagnostics.push(leafDiagnostic(ctx, field, `Duplicate key "${key}"`));
67843
+ continue;
67844
+ }
67845
+ keys.add(key);
67846
+ entries.push([key, parsed.value]);
67847
+ }
67848
+ if (diagnostics.length > 0) return notOk(diagnostics);
67849
+ return ok$1(Object.fromEntries(entries));
67850
+ }
67851
+ };
67852
+ }
67853
+ function str(value) {
67854
+ if (value === void 0) return {
67855
+ kind: "str",
67856
+ label: "string",
67857
+ value: void 0,
67858
+ parse: (arg, ctx) => {
67859
+ const literal = StringLiteralExprAst.cast(arg.syntax);
67860
+ if (literal !== void 0) {
67861
+ const parsed = literal.value();
67862
+ if (parsed !== void 0) return ok$1(parsed);
67863
+ }
67864
+ return notOk([leafDiagnostic(ctx, arg, "Expected a string literal")]);
67865
+ }
67866
+ };
67867
+ return {
67868
+ kind: "str",
67869
+ label: JSON.stringify(value),
67870
+ value,
67871
+ parse: (arg, ctx) => {
67872
+ const literal = StringLiteralExprAst.cast(arg.syntax);
67873
+ if (literal !== void 0) {
67874
+ if (literal.value() === value) return ok$1(value);
67875
+ }
67876
+ return notOk([leafDiagnostic(ctx, arg, `Expected ${JSON.stringify(value)}`)]);
67877
+ }
67878
+ };
67879
+ }
67880
+ function fieldAttribute(name, config) {
67881
+ return {
67882
+ level: "field",
67883
+ name,
67884
+ positional: config.positional ?? [],
67885
+ named: config.named ?? {},
67886
+ ...config.refine !== void 0 ? { refine: config.refine } : {}
67887
+ };
67888
+ }
67889
+ function modelAttribute(name, config) {
67890
+ return {
67891
+ level: "model",
67892
+ name,
67893
+ positional: config.positional ?? [],
67894
+ named: config.named ?? {},
67895
+ ...config.refine !== void 0 ? { refine: config.refine } : {}
67896
+ };
67897
+ }
67898
+ function optional(type, ...rest) {
67899
+ if (rest.length === 0) return {
67900
+ ...type,
67901
+ optional: true,
67902
+ hasDefault: false
67903
+ };
67904
+ return {
67905
+ ...type,
67906
+ optional: true,
67907
+ hasDefault: true,
67908
+ defaultValue: rest[0]
67909
+ };
67910
+ }
67911
+ function findFieldAttributeNode(field, name) {
67912
+ for (const attribute of field.node.attributes()) if (attribute.name()?.isSimpleName(name) === true) return attribute;
67913
+ }
67914
+ const mapModelSpec = modelAttribute("map", { positional: [{
67915
+ key: "name",
67916
+ type: str()
67917
+ }] });
67918
+ const mapFieldSpec = fieldAttribute("map", { positional: [{
67919
+ key: "name",
67920
+ type: str()
67921
+ }] });
67922
+ function scalarDefaultArms(isList, registry) {
67923
+ const literal = () => oneOf(str(), num(), bool());
67924
+ const funcArms = [...registry.entries()].map(([name, entry]) => funcCall(name, blindCast(entry.signature)));
67925
+ return isList ? [list(literal()), ...funcArms] : [
67926
+ str(),
67927
+ num(),
67928
+ bool(),
67929
+ ...funcArms
67930
+ ];
67931
+ }
67932
+ function noEnumMember() {
67933
+ return {
67934
+ kind: "rejecting",
67935
+ label: "enum member",
67936
+ message: "Enum declares no members",
67937
+ parse: (arg, ctx) => notOk([leafDiagnostic(ctx, arg, "Enum declares no members")])
67938
+ };
67939
+ }
67940
+ function enumMemberNames(ctx) {
67941
+ const block = (ctx.field.typeNamespaceId === void 0 ? ctx.symbols.topLevel : ctx.symbols.topLevel.namespaces[ctx.field.typeNamespaceId])?.blocks[ctx.field.typeName];
67942
+ if (block === void 0 || block.keyword !== "enum") return void 0;
67943
+ return Object.keys(block.block.parameters);
67944
+ }
67945
+ function enumDefaultArms(members) {
67946
+ const [first, ...rest] = members;
67947
+ if (first === void 0) return [noEnumMember()];
67948
+ return [identifier(first), ...rest.map((name) => identifier(name))];
67949
+ }
67950
+ function defaultFieldSpec(ctx) {
67951
+ const members = enumMemberNames(ctx);
67952
+ return fieldAttribute("default", { positional: [{
67953
+ key: "value",
67954
+ type: oneOf(...members === void 0 ? scalarDefaultArms(ctx.field.list, ctx.controlMutationDefaults) : enumDefaultArms(members))
67955
+ }] });
67956
+ }
67957
+ const idFieldSpec = fieldAttribute("id", { named: { map: optional(str()) } });
67958
+ const uniqueFieldSpec = fieldAttribute("unique", { named: { map: optional(str()) } });
67959
+ const noCheckKindArgument = () => oneOf(identifier("membership"), identifier("elementNotNull"));
67960
+ /**
67961
+ * `@noCheck` waives generated CHECK constraints on one column: bare for every
67962
+ * kind the column's shape derives, or naming concrete kinds. Two optional
67963
+ * positional slots cover the whole kind vocabulary; a third argument is
67964
+ * necessarily a duplicate and fails as excess arity.
67965
+ */
67966
+ const noCheckFieldSpec = fieldAttribute("noCheck", {
67967
+ positional: [{
67968
+ key: "first",
67969
+ type: optional(noCheckKindArgument())
67970
+ }, {
67971
+ key: "second",
67972
+ type: optional(noCheckKindArgument())
67973
+ }],
67974
+ refine: (value, ctx, attributeNode) => {
67975
+ if (value.first !== void 0 && value.first === value.second) return [leafDiagnostic(ctx, attributeNode, "`@noCheck` names the same kind twice")];
67976
+ return [];
67977
+ }
67978
+ });
67979
+ const idModelSpec = modelAttribute("id", {
67980
+ positional: [{
67981
+ key: "fields",
67982
+ type: list(fieldRef(), {
67983
+ allowEmpty: false,
67984
+ unique: true
67985
+ })
67986
+ }],
67987
+ named: { map: optional(str()) }
67988
+ });
67989
+ const uniqueModelSpec = modelAttribute("unique", {
67990
+ positional: [{
67991
+ key: "fields",
67992
+ type: list(fieldRef(), {
67993
+ allowEmpty: false,
67994
+ unique: true
67995
+ })
67996
+ }],
67997
+ named: { map: optional(str()) }
67998
+ });
67999
+ const PSL_INDEX_FIELDS_XOR_EXPRESSION = "PSL_INDEX_FIELDS_XOR_EXPRESSION";
68000
+ const PSL_INDEX_EXPRESSION_REQUIRES_NAME = "PSL_INDEX_EXPRESSION_REQUIRES_NAME";
68001
+ const PSL_INDEX_NAME_XOR_MAP = "PSL_INDEX_NAME_XOR_MAP";
68002
+ const indexModelSpec = modelAttribute("index", {
68003
+ positional: [{
68004
+ key: "fields",
68005
+ type: optional(list(fieldRef(), {
68006
+ allowEmpty: false,
68007
+ unique: true
68008
+ }))
68009
+ }],
68010
+ named: {
68011
+ expression: optional(str()),
68012
+ where: optional(str()),
68013
+ unique: optional(bool()),
68014
+ name: optional(str()),
68015
+ map: optional(str()),
68016
+ type: optional(str()),
68017
+ options: optional(record(str()))
68018
+ },
68019
+ refine: (value, ctx, attributeNode) => {
68020
+ const diagnostics = [];
68021
+ if (value.fields === void 0 === (value.expression === void 0)) diagnostics.push(leafDiagnostic(ctx, attributeNode, "`@@index` requires exactly one of a fields list or an `expression` argument", PSL_INDEX_FIELDS_XOR_EXPRESSION));
68022
+ if (value.expression !== void 0 && value.name === void 0 && value.map === void 0) diagnostics.push(leafDiagnostic(ctx, attributeNode, "`@@index` with an `expression` argument requires a `name` or `map` argument (a default name cannot be derived from an expression)", PSL_INDEX_EXPRESSION_REQUIRES_NAME));
68023
+ if (value.name !== void 0 && value.map !== void 0) diagnostics.push(leafDiagnostic(ctx, attributeNode, "`@@index` takes at most one of `name` and `map`", PSL_INDEX_NAME_XOR_MAP));
68024
+ if (value.options !== void 0 && value.type === void 0) diagnostics.push(leafDiagnostic(ctx, attributeNode, "`@@index` options argument requires a type argument"));
68025
+ return diagnostics;
68026
+ }
68027
+ });
68028
+ const PSL_CHECK_REQUIRES_NAME_OR_MAP = "PSL_CHECK_REQUIRES_NAME_OR_MAP";
68029
+ const PSL_CHECK_NAME_XOR_MAP = "PSL_CHECK_NAME_XOR_MAP";
68030
+ const PSL_CHECK_EXPRESSION_EMPTY = "PSL_CHECK_EXPRESSION_EMPTY";
68031
+ const checkModelSpec = modelAttribute("check", {
68032
+ named: {
68033
+ expression: str(),
68034
+ name: optional(str()),
68035
+ map: optional(str())
68036
+ },
68037
+ refine: (value, ctx, attributeNode) => {
68038
+ const diagnostics = [];
68039
+ if (value.expression.trim().length === 0) diagnostics.push(leafDiagnostic(ctx, attributeNode, "`@@check` expression must not be empty — an empty predicate is not a constraint", PSL_CHECK_EXPRESSION_EMPTY));
68040
+ if (value.name === void 0 && value.map === void 0) diagnostics.push(leafDiagnostic(ctx, attributeNode, "`@@check` requires a `name` or `map` argument (a default name cannot be derived — a check has no column tuple to name itself after)", PSL_CHECK_REQUIRES_NAME_OR_MAP));
68041
+ if (value.name !== void 0 && value.map !== void 0) diagnostics.push(leafDiagnostic(ctx, attributeNode, "`@@check` takes at most one of `name` and `map`", PSL_CHECK_NAME_XOR_MAP));
68042
+ return diagnostics;
68043
+ }
68044
+ });
68045
+ const controlModelSpec = modelAttribute("control", { positional: [{
68046
+ key: "policy",
68047
+ type: oneOf(identifier("managed"), identifier("tolerated"), identifier("external"), identifier("observed"))
68048
+ }] });
68049
+ const discriminatorModelSpec = modelAttribute("discriminator", { positional: [{
68050
+ key: "field",
68051
+ type: fieldRef()
68052
+ }] });
68053
+ const baseModelSpec = modelAttribute("base", { positional: [{
68054
+ key: "base",
68055
+ type: entityRef()
68056
+ }, {
68057
+ key: "value",
68058
+ type: str()
68059
+ }] });
68060
+ function relationAttributeSpan(ctx) {
68061
+ const node = findFieldAttributeNode(ctx.field, "relation");
68062
+ if (node !== void 0) return nodePslSpan(node.syntax, ctx.sourceFile);
68063
+ return ctx.field.span;
68064
+ }
68065
+ function relationInvariants(parsed, ctx) {
68066
+ if (parsed.fields !== void 0 !== (parsed.references !== void 0)) return [{
68067
+ code: "PSL_INVALID_ATTRIBUTE_SYNTAX",
68068
+ message: `Relation field "${ctx.selfModel.name}.${ctx.field.name}" requires fields and references arguments`,
68069
+ sourceId: ctx.sourceId,
68070
+ span: relationAttributeSpan(ctx)
68071
+ }];
68072
+ return [];
68073
+ }
68074
+ const referentialActionArgument = () => oneOf(identifier("NoAction"), identifier("Restrict"), identifier("Cascade"), identifier("SetNull"), identifier("SetDefault"));
68075
+ const relationFieldSpec = fieldAttribute("relation", {
68076
+ positional: [{
68077
+ key: "name",
68078
+ type: optional(str())
68079
+ }],
68080
+ named: {
68081
+ name: optional(str()),
68082
+ fields: optional(list(fieldRef(), {
68083
+ allowEmpty: false,
68084
+ unique: true
68085
+ })),
68086
+ references: optional(list(referencedFieldRef(), {
68087
+ allowEmpty: false,
68088
+ unique: true
68089
+ })),
68090
+ map: optional(str()),
68091
+ onDelete: optional(referentialActionArgument()),
68092
+ onUpdate: optional(referentialActionArgument()),
68093
+ index: optional(bool())
68094
+ },
68095
+ refine: relationInvariants
68096
+ });
68097
+ const sqlAttributeSpecs = {
68098
+ model: {
68099
+ map: () => mapModelSpec,
68100
+ id: () => idModelSpec,
68101
+ unique: () => uniqueModelSpec,
68102
+ index: () => indexModelSpec,
68103
+ check: () => checkModelSpec,
68104
+ control: () => controlModelSpec,
68105
+ discriminator: () => discriminatorModelSpec,
68106
+ base: () => baseModelSpec
68107
+ },
68108
+ field: {
68109
+ map: () => mapFieldSpec,
68110
+ id: () => idFieldSpec,
68111
+ unique: () => uniqueFieldSpec,
68112
+ noCheck: () => noCheckFieldSpec,
68113
+ relation: () => relationFieldSpec,
68114
+ default: defaultFieldSpec
68115
+ }
68116
+ };
66512
68117
  function isSafeTypeExpression(expr) {
66513
68118
  return !/import\s*\(|require\s*\(|declare\s|export\s|eval\s*\(/.test(expr);
66514
68119
  }
@@ -66595,6 +68200,7 @@ function generateModelRelationsType(relations) {
66595
68200
  const parts = [];
66596
68201
  if (toRef) parts.push(`readonly to: ${serializeCrossReference(blindCast(toRef))}`);
66597
68202
  if (relObj["cardinality"]) parts.push(`readonly cardinality: ${serializeValue(relObj["cardinality"])}`);
68203
+ if (typeof relObj["nullable"] === "boolean") parts.push(`readonly nullable: ${relObj["nullable"]}`);
66598
68204
  const on = relObj["on"];
66599
68205
  if (on && (!on.localFields || !on.targetFields)) throw emitterError("CONTRACT.RELATION_INVALID", `Relation "${relName}" has an "on" block but is missing localFields or targetFields`, { meta: { relation: relName } });
66600
68206
  if (on?.localFields && on.targetFields) {
@@ -66748,11 +68354,26 @@ function resolveFieldType(field, codecLookup, resolvedTypeParams, resolvedValueS
66748
68354
  };
66749
68355
  }
66750
68356
  }
68357
+ /**
68358
+ * Resolves one model field's input and output types the way `FieldOutputTypes` /
68359
+ * `FieldInputTypes` do: inline type params win over the family resolver, and a family-resolved
68360
+ * value set renders as a literal union.
68361
+ */
68362
+ function resolveModelFieldType(modelName, fieldName, field, model, resolvers) {
68363
+ const resolvedTypeParams = (field.type.kind === "scalar" && field.type.typeParams && Object.keys(field.type.typeParams).length > 0 ? field.type.typeParams : void 0) ?? resolvers.resolveFieldTypeParams?.(modelName, fieldName, model);
68364
+ const resolvedValueSet = resolvers.resolveFieldValueSet?.(modelName, fieldName, model);
68365
+ return resolveFieldType(field, resolvers.codecLookup, resolvedTypeParams, resolvedValueSet);
68366
+ }
66751
68367
  function generateBothFieldTypesMaps(models, codecLookup, resolveFieldTypeParams, resolveFieldValueSet) {
66752
68368
  if (!models || Object.keys(models).length === 0) return {
66753
68369
  output: "Record<string, never>",
66754
68370
  input: "Record<string, never>"
66755
68371
  };
68372
+ const resolvers = {
68373
+ codecLookup,
68374
+ resolveFieldTypeParams,
68375
+ resolveFieldValueSet
68376
+ };
66756
68377
  const outputModelEntries = [];
66757
68378
  const inputModelEntries = [];
66758
68379
  for (const [modelName, model] of Object.entries(models).sort(([a], [b]) => a.localeCompare(b))) {
@@ -66760,9 +68381,7 @@ function generateBothFieldTypesMaps(models, codecLookup, resolveFieldTypeParams,
66760
68381
  const outputFieldEntries = [];
66761
68382
  const inputFieldEntries = [];
66762
68383
  for (const [fieldName, field] of Object.entries(model.fields)) {
66763
- const resolvedTypeParams = (field.type.kind === "scalar" && field.type.typeParams && Object.keys(field.type.typeParams).length > 0 ? field.type.typeParams : void 0) ?? resolveFieldTypeParams?.(modelName, fieldName, model);
66764
- const resolvedValueSet = resolveFieldValueSet?.(modelName, fieldName, model);
66765
- const resolved = resolveFieldType(field, codecLookup, resolvedTypeParams, resolvedValueSet);
68384
+ const resolved = resolveModelFieldType(modelName, fieldName, field, model, resolvers);
66766
68385
  const key = `readonly ${serializeObjectKey(fieldName)}`;
66767
68386
  outputFieldEntries.push(`${key}: ${resolved.output}`);
66768
68387
  inputFieldEntries.push(`${key}: ${resolved.input}`);
@@ -67197,6 +68816,7 @@ const sqlEmission = {
67197
68816
  return [
67198
68817
  "import type {",
67199
68818
  " ContractWithTypeMaps,",
68819
+ " RelationKeys,",
67200
68820
  " TypeMaps as TypeMapsType,",
67201
68821
  `} from '${resolveImportSpecifier("@internal/sql-contract/types")}';`
67202
68822
  ];
@@ -67390,9 +69010,9 @@ const EXACT_NAME_BODY_PREAMBLE = "Drift detection compares the authored SQL text
67390
69010
  * block's head the wire prefix.
67391
69011
  */
67392
69012
  const EXACT_NAME_BODY_REMEDIATION = {
67393
- 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.",
69013
+ index: "For hand-authored definitions, use name: and let Prisma 8 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.",
67394
69014
  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.",
67395
- 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."
69015
+ check: "For hand-authored definitions, use name: and let Prisma 8 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."
67396
69016
  };
67397
69017
  /** What the user actually wrote, per subject: index and check `map:`, policy `@@map`. */
67398
69018
  const EXACT_NAME_FEATURE = {
@@ -67493,6 +69113,7 @@ function validateContractDomain(contract) {
67493
69113
  validateRoots(contract, modelIndex, errors);
67494
69114
  validateVariantsAndBases(modelIndex, errors);
67495
69115
  validateRelationTargets(modelIndex, errors);
69116
+ validateRelationNullability(modelIndex, errors);
67496
69117
  validateDiscriminators(modelIndex, errors);
67497
69118
  validateOwnership(contract, modelIndex, errors);
67498
69119
  validateValueObjectReferences(contract, errors);
@@ -67542,6 +69163,19 @@ function validateRelationTargets(modelIndex, errors) {
67542
69163
  if (!lookupModel(modelIndex, relation.to)) errors.push(`Relation "${relName}" on model "${namespaceId}:${modelName}" targets "${relation.to.namespace}:${relation.to.model}" which does not exist in domain.namespaces`);
67543
69164
  }
67544
69165
  }
69166
+ function relationKindLabel(relation) {
69167
+ return relation.on === void 0 ? "embed relation" : `${relation.cardinality} relation`;
69168
+ }
69169
+ function validateRelationNullability(modelIndex, errors) {
69170
+ for (const { namespaceId, name: modelName, model } of iterateIndexedModels(modelIndex)) for (const [relName, relation] of Object.entries(model.relations ?? {})) {
69171
+ const location = `Relation "${relName}" on model "${namespaceId}:${modelName}"`;
69172
+ if (relation.on !== void 0 && (relation.cardinality === "1:1" || relation.cardinality === "N:1")) {
69173
+ if (relation.nullable !== void 0 && typeof relation.nullable !== "boolean") errors.push(`${location} is a ${relation.cardinality} relation and its "nullable" must be a boolean`);
69174
+ continue;
69175
+ }
69176
+ if (relation.nullable !== void 0) errors.push(`${location} is a ${relationKindLabel(relation)} and must not carry "nullable"`);
69177
+ }
69178
+ }
67545
69179
  function validateDiscriminators(modelIndex, errors) {
67546
69180
  for (const { namespaceId, name: modelName, model } of iterateIndexedModels(modelIndex)) {
67547
69181
  if (model.discriminator) {
@@ -67600,6 +69234,29 @@ function validateFieldModifiers(modelIndex, contract, errors) {
67600
69234
  }
67601
69235
  }
67602
69236
  }
69237
+ function sameColumns(left, right) {
69238
+ return left.length === right.length && left.every((column, index) => column === right[index]);
69239
+ }
69240
+ /**
69241
+ * The storage facts behind a same-space to-one relation's nullability: which side owns the
69242
+ * foreign key, and whether each local column is nullable.
69243
+ */
69244
+ function resolveSqlToOneRelationStorage(contract, modelStorage, relation) {
69245
+ const table = blindCast(contract.storage.namespaces[modelStorage.namespaceId]?.entries.table?.[modelStorage.table]);
69246
+ const columns = relation.on.localFields.map((fieldName) => {
69247
+ const columnName = modelStorage.fields[fieldName]?.column;
69248
+ const column = columnName === void 0 ? void 0 : table?.columns[columnName];
69249
+ return {
69250
+ name: columnName ?? fieldName,
69251
+ nullable: column?.nullable ?? true
69252
+ };
69253
+ });
69254
+ const columnNames = columns.map((column) => column.name);
69255
+ return {
69256
+ ownsForeignKey: relation.cardinality === "N:1" || (table?.foreignKeys ?? []).some((foreignKey) => sameColumns(foreignKey.source.columns, columnNames)),
69257
+ columns
69258
+ };
69259
+ }
67603
69260
  const generatorKindSchema = type("'generator'");
67604
69261
  const ControlPolicySchema = type("'managed' | 'tolerated' | 'external' | 'observed'");
67605
69262
  const ExecutionMutationDefaultValueSchema = type({
@@ -67849,13 +69506,20 @@ const ContractManyToManyRelationSchema = type({
67849
69506
  on: ContractRelationOnSchema,
67850
69507
  through: ContractRelationThroughSchema
67851
69508
  });
67852
- const ContractNonJunctionRelationSchema = type({
69509
+ const ContractToOneRelationSchema = type({
69510
+ "+": "reject",
69511
+ to: CrossReferenceSchema,
69512
+ cardinality: "'1:1' | 'N:1'",
69513
+ "nullable?": "boolean",
69514
+ on: ContractRelationOnSchema
69515
+ });
69516
+ const ContractToManyRelationSchema = type({
67853
69517
  "+": "reject",
67854
69518
  to: CrossReferenceSchema,
67855
- cardinality: "'1:1' | '1:N' | 'N:1'",
69519
+ cardinality: "'1:N'",
67856
69520
  on: ContractRelationOnSchema
67857
69521
  });
67858
- const ContractReferenceRelationSchema = ContractManyToManyRelationSchema.or(ContractNonJunctionRelationSchema);
69522
+ const ContractReferenceRelationSchema = ContractManyToManyRelationSchema.or(ContractToOneRelationSchema).or(ContractToManyRelationSchema);
67859
69523
  const ContractEmbedRelationSchema = type({
67860
69524
  "+": "reject",
67861
69525
  to: CrossReferenceSchema,
@@ -68070,8 +69734,32 @@ function validateSqlContractFully(value, options) {
68070
69734
  if (semanticErrors.length > 0) throw new ContractValidationError(`Contract semantic validation failed: ${semanticErrors.join("; ")}`, "storage");
68071
69735
  validateModelStorageReferences(validated);
68072
69736
  validateRelationThroughConsistency(validated);
69737
+ validateToOneRelationNullabilityAgainstStorage(validated);
68073
69738
  return validated;
68074
69739
  }
69740
+ /**
69741
+ * A same-space to-one relation that states `nullable` must agree with its local FK columns:
69742
+ * nullable exactly when one of them is nullable (a column that cannot be resolved counts as
69743
+ * nullable). A relation without the flag is left to hydration, which derives it the same way.
69744
+ */
69745
+ function validateToOneRelationNullabilityAgainstStorage(contract) {
69746
+ for (const [namespaceId, namespace] of Object.entries(contract.domain.namespaces)) for (const [modelName, model] of Object.entries(namespace.models)) {
69747
+ const storage = blindCast(model.storage);
69748
+ for (const [relationName, relation] of Object.entries(model.relations)) {
69749
+ if (!("on" in relation && (relation.cardinality === "1:1" || relation.cardinality === "N:1") && relation.to.space === void 0) || relation.nullable === void 0) continue;
69750
+ const location = `Relation "${relationName}" on model "${namespaceId}:${modelName}"`;
69751
+ const { ownsForeignKey, columns } = resolveSqlToOneRelationStorage(contract, storage, relation);
69752
+ if (!ownsForeignKey) {
69753
+ if (relation.nullable) continue;
69754
+ throw new ContractValidationError(`${location} is required but does not own the foreign key, so nothing in storage guarantees the related row exists`, "storage");
69755
+ }
69756
+ const anyNullable = columns.some((column) => column.nullable);
69757
+ if (relation.nullable === anyNullable) continue;
69758
+ const columnList = columns.filter((column) => column.nullable !== relation.nullable).map((column) => `"${column.name}"`).join(", ");
69759
+ throw new ContractValidationError(relation.nullable ? `${location} is nullable but every local FK column is NOT NULL (columns ${columnList})` : `${location} is required but a local FK column is nullable (columns ${columnList})`, "storage");
69760
+ }
69761
+ }
69762
+ }
68075
69763
  /** Storage column lookup for through-consistency validation. */
68076
69764
  function lookupStorageColumn(contract, namespaceId, tableName, columnName) {
68077
69765
  const rawTable = contract.storage.namespaces[namespaceId]?.entries.table?.[tableName];
@@ -68173,188 +69861,6 @@ function validateRelationThroughConsistency(contract) {
68173
69861
  });
68174
69862
  }
68175
69863
  }
68176
- const DOMAIN_NAMESPACE_SLOT_PATTERN = [
68177
- "domain",
68178
- "namespaces",
68179
- "*"
68180
- ];
68181
- const DOMAIN_MODELS_CONTAINER_PATTERN = [
68182
- "domain",
68183
- "namespaces",
68184
- "*",
68185
- "models"
68186
- ];
68187
- const DOMAIN_MODEL_RELATIONS_PATTERN = [
68188
- "domain",
68189
- "namespaces",
68190
- "*",
68191
- "models",
68192
- "*",
68193
- "relations"
68194
- ];
68195
- const DOMAIN_MODEL_STORAGE_PATTERN = [
68196
- "domain",
68197
- "namespaces",
68198
- "*",
68199
- "models",
68200
- "*",
68201
- "storage"
68202
- ];
68203
- const STORAGE_NAMESPACE_ENTRIES_PATTERN = [
68204
- "storage",
68205
- "namespaces",
68206
- "*",
68207
- "entries"
68208
- ];
68209
- const TOP_LEVEL_ORDER = [
68210
- "schemaVersion",
68211
- "canonicalVersion",
68212
- "targetFamily",
68213
- "target",
68214
- "profileHash",
68215
- "roots",
68216
- "domain",
68217
- "storage",
68218
- "execution",
68219
- "capabilities",
68220
- "extensions",
68221
- "defaultControlPolicy",
68222
- "meta"
68223
- ];
68224
- function isDefaultValue(value) {
68225
- if (value === false) return true;
68226
- if (value === null) return false;
68227
- if (Array.isArray(value) && value.length === 0) return true;
68228
- if (typeof value === "object" && value !== null) return Object.keys(value).length === 0;
68229
- return false;
68230
- }
68231
- function omitDefaults(obj, path, shouldPreserveEmpty) {
68232
- if (obj === null || typeof obj !== "object") return obj;
68233
- if (Array.isArray(obj)) return obj.map((item) => omitDefaults(item, path, shouldPreserveEmpty));
68234
- const result = {};
68235
- for (const [key, value] of Object.entries(obj)) {
68236
- const currentPath = [...path, key];
68237
- if (key === "_generated") continue;
68238
- if (key === "generated" && value === false) continue;
68239
- if ((key === "onDelete" || key === "onUpdate") && value === "noAction") continue;
68240
- if (isDefaultValue(value)) {
68241
- const isRequiredDomainNamespaces = isArrayEqual(currentPath, ["domain", "namespaces"]);
68242
- const isDomainNamespaceSlot = matchesPathPattern(currentPath, DOMAIN_NAMESPACE_SLOT_PATTERN);
68243
- const isRequiredDomainModels = matchesPathPattern(currentPath, DOMAIN_MODELS_CONTAINER_PATTERN);
68244
- const isRequiredStorageNamespaces = isArrayEqual(currentPath, ["storage", "namespaces"]);
68245
- const isStorageNamespaceEntries = matchesPathPattern(currentPath, STORAGE_NAMESPACE_ENTRIES_PATTERN);
68246
- const isRequiredRoots = isArrayEqual(currentPath, ["roots"]);
68247
- const isRequiredExtensions = isArrayEqual(currentPath, ["extensions"]);
68248
- const isRequiredCapabilities = isArrayEqual(currentPath, ["capabilities"]);
68249
- const isRequiredMeta = isArrayEqual(currentPath, ["meta"]);
68250
- const isRequiredExecutionDefaults = isArrayEqual(currentPath, [
68251
- "execution",
68252
- "mutations",
68253
- "defaults"
68254
- ]);
68255
- const isExtensionNamespace = currentPath.length === 2 && currentPath[0] === "extensions";
68256
- const isModelRelations = matchesPathPattern(currentPath, DOMAIN_MODEL_RELATIONS_PATTERN);
68257
- const isModelStorage = matchesPathPattern(currentPath, DOMAIN_MODEL_STORAGE_PATTERN);
68258
- const isNullableField = key === "nullable";
68259
- const isFamilyPreserved = shouldPreserveEmpty?.(currentPath) ?? false;
68260
- if (!isRequiredDomainNamespaces && !isDomainNamespaceSlot && !isRequiredDomainModels && !isRequiredStorageNamespaces && !isStorageNamespaceEntries && !isRequiredRoots && !isRequiredExtensions && !isRequiredCapabilities && !isRequiredMeta && !isRequiredExecutionDefaults && !isExtensionNamespace && !isModelRelations && !isModelStorage && !isNullableField && !isFamilyPreserved) continue;
68261
- }
68262
- result[key] = omitDefaults(value, currentPath, shouldPreserveEmpty);
68263
- }
68264
- return result;
68265
- }
68266
- function sortObjectKeys(obj) {
68267
- if (obj === null || typeof obj !== "object") return obj;
68268
- if (Array.isArray(obj)) return obj.map((item) => sortObjectKeys(item));
68269
- const sorted = {};
68270
- const keys = Object.keys(obj).sort();
68271
- for (const key of keys) sorted[key] = sortObjectKeys(obj[key]);
68272
- return sorted;
68273
- }
68274
- function orderTopLevel(obj) {
68275
- const ordered = {};
68276
- const remaining = new Set(Object.keys(obj));
68277
- for (const key of TOP_LEVEL_ORDER) if (remaining.has(key)) {
68278
- ordered[key] = obj[key];
68279
- remaining.delete(key);
68280
- }
68281
- for (const key of Array.from(remaining).sort()) ordered[key] = obj[key];
68282
- return ordered;
68283
- }
68284
- /**
68285
- * Object-form variant of {@link canonicalizeContract}. Exported because the
68286
- * emitter writes the canonical contract through a separate JSON-stringify
68287
- * pass and consumes the structured object directly.
68288
- */
68289
- function canonicalizeContractToObject(contract, options) {
68290
- const serialized = options.serializeContract(contract);
68291
- const withDefaultsOmitted = omitDefaults({
68292
- ...ifDefined("schemaVersion", options.schemaVersion),
68293
- targetFamily: serialized["targetFamily"],
68294
- target: serialized["target"],
68295
- profileHash: serialized["profileHash"],
68296
- roots: serialized["roots"],
68297
- domain: serialized["domain"],
68298
- storage: serialized["storage"],
68299
- ...ifDefined("execution", serialized["execution"]),
68300
- extensions: serialized["extensions"],
68301
- capabilities: serialized["capabilities"],
68302
- ...ifDefined("defaultControlPolicy", serialized["defaultControlPolicy"]),
68303
- meta: serialized["meta"]
68304
- }, [], options.shouldPreserveEmpty);
68305
- return orderTopLevel(sortObjectKeys(options.sortStorage ? {
68306
- ...withDefaultsOmitted,
68307
- storage: options.sortStorage(withDefaultsOmitted["storage"])
68308
- } : withDefaultsOmitted));
68309
- }
68310
- function canonicalizeContract(contract, options) {
68311
- return JSON.stringify(canonicalizeContractToObject(contract, options), null, 2);
68312
- }
68313
- const SCHEMA_VERSION$1 = "1";
68314
- function omitNamespaceKindsForHash(storage) {
68315
- if (!isPlainRecord(storage)) return storage;
68316
- const namespaces = storage["namespaces"];
68317
- if (!isPlainRecord(namespaces)) return storage;
68318
- const stripped = {};
68319
- for (const [nsId, ns] of Object.entries(namespaces)) if (isPlainRecord(ns)) {
68320
- const { kind: _kind, ...rest } = ns;
68321
- stripped[nsId] = rest;
68322
- } else stripped[nsId] = ns;
68323
- return {
68324
- ...storage,
68325
- namespaces: stripped
68326
- };
68327
- }
68328
- function sha256(content) {
68329
- const hash = createHash("sha256");
68330
- hash.update(content);
68331
- return hash.digest("hex");
68332
- }
68333
- function hashContract(section) {
68334
- const { shouldPreserveEmpty, sortStorage, ...sectionData } = section;
68335
- const storageForHash = omitNamespaceKindsForHash(sectionData["storage"] ?? {});
68336
- return canonicalizeContract(blindCast({
68337
- targetFamily: sectionData["targetFamily"],
68338
- target: sectionData["target"],
68339
- roots: {},
68340
- domain: { namespaces: {} },
68341
- execution: sectionData["execution"],
68342
- extensions: {},
68343
- capabilities: sectionData["capabilities"] ?? {},
68344
- meta: {},
68345
- profileHash: "",
68346
- ...sectionData,
68347
- storage: storageForHash
68348
- }), {
68349
- schemaVersion: SCHEMA_VERSION$1,
68350
- serializeContract: (c) => castAs(JSON.parse(JSON.stringify(c))),
68351
- ...ifDefined("shouldPreserveEmpty", shouldPreserveEmpty),
68352
- ...ifDefined("sortStorage", sortStorage)
68353
- });
68354
- }
68355
- function computeStorageHash(args) {
68356
- return blindCast(sha256(hashContract(args)));
68357
- }
68358
69864
  function contractError$1(code, message, options) {
68359
69865
  return structuredError(code, message, options);
68360
69866
  }
@@ -68405,6 +69911,251 @@ function enumType(name, codec, ...members) {
68405
69911
  ordinalOf: (v) => valueToOrdinal.get(v) ?? -1
68406
69912
  };
68407
69913
  }
69914
+ /**
69915
+ * The one rule for whether a to-one relation may be absent. The side that holds the reference
69916
+ * (in SQL, the foreign key) is nullable exactly when one of its local fields is; the other side
69917
+ * is always nullable, because nothing in storage guarantees the related record exists. A
69918
+ * declaration that disagrees is reported as a contradiction; `nullable` is always the derived
69919
+ * value.
69920
+ */
69921
+ function resolveToOneRelationNullable(input) {
69922
+ const nullable = input.ownsReference ? input.localFieldNullability.some(Boolean) : true;
69923
+ const declared = input.declaredNullable;
69924
+ if (declared === void 0 || declared === nullable) return {
69925
+ nullable,
69926
+ contradiction: void 0
69927
+ };
69928
+ return {
69929
+ nullable,
69930
+ contradiction: declared ? "declared-optional" : "declared-required"
69931
+ };
69932
+ }
69933
+ function isToOneReference(relation) {
69934
+ return "on" in relation && (relation.cardinality === "1:1" || relation.cardinality === "N:1");
69935
+ }
69936
+ /**
69937
+ * Fills in `nullable` on every same-space to-one relation that lacks it from the ownership and
69938
+ * local-field nullability the lookup reports. A cross-space relation defaults to nullable.
69939
+ * Relations that already carry the flag are left as they are.
69940
+ */
69941
+ function withDerivedToOneRelationNullability(domain, localFieldNullability) {
69942
+ const namespaces = Object.fromEntries(Object.entries(domain.namespaces).map(([namespaceId, namespace]) => [namespaceId, withDerivedNamespace(namespaceId, namespace, localFieldNullability)]));
69943
+ return {
69944
+ ...domain,
69945
+ namespaces
69946
+ };
69947
+ }
69948
+ function withDerivedNamespace(namespaceId, namespace, localFieldNullability) {
69949
+ const models = Object.fromEntries(Object.entries(namespace.models).map(([modelName, model]) => [modelName, withDerivedModel(namespaceId, modelName, model, localFieldNullability)]));
69950
+ return {
69951
+ ...namespace,
69952
+ models
69953
+ };
69954
+ }
69955
+ function withDerivedModel(namespaceId, modelName, model, localFieldNullability) {
69956
+ const relations = Object.fromEntries(Object.entries(model.relations ?? {}).map(([relationName, relation]) => {
69957
+ if (!isToOneReference(relation) || relation.nullable !== void 0) return [relationName, relation];
69958
+ const nullable = relation.to.space !== void 0 ? true : resolveToOneRelationNullable({
69959
+ declaredNullable: void 0,
69960
+ ...localFieldNullability({
69961
+ namespaceId,
69962
+ modelName,
69963
+ model,
69964
+ relation
69965
+ })
69966
+ }).nullable;
69967
+ return [relationName, {
69968
+ ...relation,
69969
+ nullable
69970
+ }];
69971
+ }));
69972
+ return {
69973
+ ...model,
69974
+ relations
69975
+ };
69976
+ }
69977
+ const DOMAIN_NAMESPACE_SLOT_PATTERN = [
69978
+ "domain",
69979
+ "namespaces",
69980
+ "*"
69981
+ ];
69982
+ const DOMAIN_MODELS_CONTAINER_PATTERN = [
69983
+ "domain",
69984
+ "namespaces",
69985
+ "*",
69986
+ "models"
69987
+ ];
69988
+ const DOMAIN_MODEL_RELATIONS_PATTERN = [
69989
+ "domain",
69990
+ "namespaces",
69991
+ "*",
69992
+ "models",
69993
+ "*",
69994
+ "relations"
69995
+ ];
69996
+ const DOMAIN_MODEL_STORAGE_PATTERN = [
69997
+ "domain",
69998
+ "namespaces",
69999
+ "*",
70000
+ "models",
70001
+ "*",
70002
+ "storage"
70003
+ ];
70004
+ const STORAGE_NAMESPACE_ENTRIES_PATTERN = [
70005
+ "storage",
70006
+ "namespaces",
70007
+ "*",
70008
+ "entries"
70009
+ ];
70010
+ const TOP_LEVEL_ORDER = [
70011
+ "schemaVersion",
70012
+ "canonicalVersion",
70013
+ "targetFamily",
70014
+ "target",
70015
+ "profileHash",
70016
+ "roots",
70017
+ "domain",
70018
+ "storage",
70019
+ "execution",
70020
+ "capabilities",
70021
+ "extensions",
70022
+ "defaultControlPolicy",
70023
+ "meta"
70024
+ ];
70025
+ function isDefaultValue(value) {
70026
+ if (value === false) return true;
70027
+ if (value === null) return false;
70028
+ if (Array.isArray(value) && value.length === 0) return true;
70029
+ if (typeof value === "object" && value !== null) return Object.keys(value).length === 0;
70030
+ return false;
70031
+ }
70032
+ function omitDefaults(obj, path, shouldPreserveEmpty) {
70033
+ if (obj === null || typeof obj !== "object") return obj;
70034
+ if (Array.isArray(obj)) return obj.map((item) => omitDefaults(item, path, shouldPreserveEmpty));
70035
+ const result = {};
70036
+ for (const [key, value] of Object.entries(obj)) {
70037
+ const currentPath = [...path, key];
70038
+ if (key === "_generated") continue;
70039
+ if (key === "generated" && value === false) continue;
70040
+ if ((key === "onDelete" || key === "onUpdate") && value === "noAction") continue;
70041
+ if (isDefaultValue(value)) {
70042
+ const isRequiredDomainNamespaces = isArrayEqual(currentPath, ["domain", "namespaces"]);
70043
+ const isDomainNamespaceSlot = matchesPathPattern(currentPath, DOMAIN_NAMESPACE_SLOT_PATTERN);
70044
+ const isRequiredDomainModels = matchesPathPattern(currentPath, DOMAIN_MODELS_CONTAINER_PATTERN);
70045
+ const isRequiredStorageNamespaces = isArrayEqual(currentPath, ["storage", "namespaces"]);
70046
+ const isStorageNamespaceEntries = matchesPathPattern(currentPath, STORAGE_NAMESPACE_ENTRIES_PATTERN);
70047
+ const isRequiredRoots = isArrayEqual(currentPath, ["roots"]);
70048
+ const isRequiredExtensions = isArrayEqual(currentPath, ["extensions"]);
70049
+ const isRequiredCapabilities = isArrayEqual(currentPath, ["capabilities"]);
70050
+ const isRequiredMeta = isArrayEqual(currentPath, ["meta"]);
70051
+ const isRequiredExecutionDefaults = isArrayEqual(currentPath, [
70052
+ "execution",
70053
+ "mutations",
70054
+ "defaults"
70055
+ ]);
70056
+ const isExtensionNamespace = currentPath.length === 2 && currentPath[0] === "extensions";
70057
+ const isModelRelations = matchesPathPattern(currentPath, DOMAIN_MODEL_RELATIONS_PATTERN);
70058
+ const isModelStorage = matchesPathPattern(currentPath, DOMAIN_MODEL_STORAGE_PATTERN);
70059
+ const isNullableField = key === "nullable";
70060
+ const isFamilyPreserved = shouldPreserveEmpty?.(currentPath) ?? false;
70061
+ if (!isRequiredDomainNamespaces && !isDomainNamespaceSlot && !isRequiredDomainModels && !isRequiredStorageNamespaces && !isStorageNamespaceEntries && !isRequiredRoots && !isRequiredExtensions && !isRequiredCapabilities && !isRequiredMeta && !isRequiredExecutionDefaults && !isExtensionNamespace && !isModelRelations && !isModelStorage && !isNullableField && !isFamilyPreserved) continue;
70062
+ }
70063
+ result[key] = omitDefaults(value, currentPath, shouldPreserveEmpty);
70064
+ }
70065
+ return result;
70066
+ }
70067
+ function sortObjectKeys(obj) {
70068
+ if (obj === null || typeof obj !== "object") return obj;
70069
+ if (Array.isArray(obj)) return obj.map((item) => sortObjectKeys(item));
70070
+ const sorted = {};
70071
+ const keys = Object.keys(obj).sort();
70072
+ for (const key of keys) sorted[key] = sortObjectKeys(obj[key]);
70073
+ return sorted;
70074
+ }
70075
+ function orderTopLevel(obj) {
70076
+ const ordered = {};
70077
+ const remaining = new Set(Object.keys(obj));
70078
+ for (const key of TOP_LEVEL_ORDER) if (remaining.has(key)) {
70079
+ ordered[key] = obj[key];
70080
+ remaining.delete(key);
70081
+ }
70082
+ for (const key of Array.from(remaining).sort()) ordered[key] = obj[key];
70083
+ return ordered;
70084
+ }
70085
+ /**
70086
+ * Object-form variant of {@link canonicalizeContract}. Exported because the
70087
+ * emitter writes the canonical contract through a separate JSON-stringify
70088
+ * pass and consumes the structured object directly.
70089
+ */
70090
+ function canonicalizeContractToObject(contract, options) {
70091
+ const serialized = options.serializeContract(contract);
70092
+ const withDefaultsOmitted = omitDefaults({
70093
+ ...ifDefined("schemaVersion", options.schemaVersion),
70094
+ targetFamily: serialized["targetFamily"],
70095
+ target: serialized["target"],
70096
+ profileHash: serialized["profileHash"],
70097
+ roots: serialized["roots"],
70098
+ domain: serialized["domain"],
70099
+ storage: serialized["storage"],
70100
+ ...ifDefined("execution", serialized["execution"]),
70101
+ extensions: serialized["extensions"],
70102
+ capabilities: serialized["capabilities"],
70103
+ ...ifDefined("defaultControlPolicy", serialized["defaultControlPolicy"]),
70104
+ meta: serialized["meta"]
70105
+ }, [], options.shouldPreserveEmpty);
70106
+ return orderTopLevel(sortObjectKeys(options.sortStorage ? {
70107
+ ...withDefaultsOmitted,
70108
+ storage: options.sortStorage(withDefaultsOmitted["storage"])
70109
+ } : withDefaultsOmitted));
70110
+ }
70111
+ function canonicalizeContract(contract, options) {
70112
+ return JSON.stringify(canonicalizeContractToObject(contract, options), null, 2);
70113
+ }
70114
+ const SCHEMA_VERSION$1 = "1";
70115
+ function omitNamespaceKindsForHash(storage) {
70116
+ if (!isPlainRecord(storage)) return storage;
70117
+ const namespaces = storage["namespaces"];
70118
+ if (!isPlainRecord(namespaces)) return storage;
70119
+ const stripped = {};
70120
+ for (const [nsId, ns] of Object.entries(namespaces)) if (isPlainRecord(ns)) {
70121
+ const { kind: _kind, ...rest } = ns;
70122
+ stripped[nsId] = rest;
70123
+ } else stripped[nsId] = ns;
70124
+ return {
70125
+ ...storage,
70126
+ namespaces: stripped
70127
+ };
70128
+ }
70129
+ function sha256(content) {
70130
+ const hash = createHash("sha256");
70131
+ hash.update(content);
70132
+ return hash.digest("hex");
70133
+ }
70134
+ function hashContract(section) {
70135
+ const { shouldPreserveEmpty, sortStorage, ...sectionData } = section;
70136
+ const storageForHash = omitNamespaceKindsForHash(sectionData["storage"] ?? {});
70137
+ return canonicalizeContract(blindCast({
70138
+ targetFamily: sectionData["targetFamily"],
70139
+ target: sectionData["target"],
70140
+ roots: {},
70141
+ domain: { namespaces: {} },
70142
+ execution: sectionData["execution"],
70143
+ extensions: {},
70144
+ capabilities: sectionData["capabilities"] ?? {},
70145
+ meta: {},
70146
+ profileHash: "",
70147
+ ...sectionData,
70148
+ storage: storageForHash
70149
+ }), {
70150
+ schemaVersion: SCHEMA_VERSION$1,
70151
+ serializeContract: (c) => castAs(JSON.parse(JSON.stringify(c))),
70152
+ ...ifDefined("shouldPreserveEmpty", shouldPreserveEmpty),
70153
+ ...ifDefined("sortStorage", sortStorage)
70154
+ });
70155
+ }
70156
+ function computeStorageHash(args) {
70157
+ return blindCast(sha256(hashContract(args)));
70158
+ }
68408
70159
  const sqlFamilyEntityTypes = { enum: {
68409
70160
  kind: "entity",
68410
70161
  discriminator: "enum",
@@ -68515,13 +70266,18 @@ const sqlFamilyEntityTypes = { enum: {
68515
70266
  })));
68516
70267
  } }
68517
70268
  } };
70269
+ const enumTypeBlockAttribute = blockAttribute("type", { positional: [{
70270
+ key: "codecId",
70271
+ type: str()
70272
+ }] });
68518
70273
  const sqlFamilyPslBlockDescriptors = { enum: {
68519
70274
  kind: "pslBlock",
68520
70275
  keyword: "enum",
68521
70276
  discriminator: "enum",
68522
70277
  name: { required: true },
68523
70278
  parameters: {},
68524
- variadicParameters: true
70279
+ variadicParameters: true,
70280
+ attributes: { type: () => enumTypeBlockAttribute }
68525
70281
  } };
68526
70282
  /**
68527
70283
  * Family-level SQL authoring field presets.
@@ -68722,6 +70478,24 @@ const NamespaceRawSchema = type({
68722
70478
  entries: type({ "+": "ignore" })
68723
70479
  });
68724
70480
  /**
70481
+ * A `contract.json` written before to-one relations recorded `nullable` (rc.9 and earlier)
70482
+ * loads with the flag derived from storage: nullable when any local FK column is nullable or
70483
+ * cannot be resolved.
70484
+ */
70485
+ function withSqlToOneRelationNullability(contract) {
70486
+ const domain = withDerivedToOneRelationNullability(contract.domain, ({ model, relation }) => {
70487
+ const { ownsForeignKey, columns } = resolveSqlToOneRelationStorage(contract, blindCast(model.storage), relation);
70488
+ return {
70489
+ ownsReference: ownsForeignKey,
70490
+ localFieldNullability: columns.map((column) => column.nullable)
70491
+ };
70492
+ });
70493
+ return {
70494
+ ...contract,
70495
+ domain
70496
+ };
70497
+ }
70498
+ /**
68725
70499
  * SQL family `ContractSerializer` abstract base. Carries the SQL-shared
68726
70500
  * deserialization pipeline:
68727
70501
  *
@@ -68755,7 +70529,7 @@ var SqlContractSerializerBase = class {
68755
70529
  this.contractSchema = packEntityKinds.length > 0 ? createSqlContractSchema(this.entryKinds) : void 0;
68756
70530
  }
68757
70531
  deserializeContract(json) {
68758
- const validated = this.parseSqlContractStructure(json);
70532
+ const validated = withSqlToOneRelationNullability(this.parseSqlContractStructure(json));
68759
70533
  const hydrated = this.hydrateSqlStorage(validated);
68760
70534
  return this.constructTargetContract(hydrated);
68761
70535
  }
@@ -68959,91 +70733,6 @@ function parseContractMarkerRow(row) {
68959
70733
  function collectSupportedCodecTypeIds(descriptors) {
68960
70734
  return [];
68961
70735
  }
68962
- /**
68963
- * Generic Result type for representing success or failure outcomes.
68964
- *
68965
- * This is the standard way to return "expected failures" as values rather than
68966
- * throwing exceptions. See docs/Error Handling.md for the full taxonomy.
68967
- *
68968
- * Naming rationale:
68969
- * - `Ok<T>` / `NotOk<F>` mirror the `ok: true/false` discriminator
68970
- * - `NotOk` avoids collision with domain types like "Failure" or "Error"
68971
- * - `failure` property distinguishes from JS Error semantics
68972
- */
68973
- /**
68974
- * Result class that implements both Ok and NotOk variants.
68975
- */
68976
- var ResultImpl = class ResultImpl {
68977
- ok;
68978
- _value;
68979
- _failure;
68980
- constructor(ok, valueOrFailure) {
68981
- this.ok = ok;
68982
- if (ok) this._value = valueOrFailure;
68983
- else this._failure = valueOrFailure;
68984
- Object.freeze(this);
68985
- }
68986
- get value() {
68987
- if (!this.ok) throw new InternalError("Cannot access value on NotOk result");
68988
- return this._value;
68989
- }
68990
- get failure() {
68991
- if (this.ok) throw new InternalError("Cannot access failure on Ok result");
68992
- return this._failure;
68993
- }
68994
- /**
68995
- * Creates a successful result.
68996
- */
68997
- static ok(value) {
68998
- return blindCast(new ResultImpl(true, value));
68999
- }
69000
- /**
69001
- * Creates an unsuccessful result.
69002
- */
69003
- static notOk(failure) {
69004
- return blindCast(new ResultImpl(false, failure));
69005
- }
69006
- /**
69007
- * Asserts that this result is Ok and returns the value.
69008
- * Throws if the result is NotOk.
69009
- */
69010
- assertOk() {
69011
- if (!this.ok) throw new InternalError("Expected Ok result but got NotOk");
69012
- return this.value;
69013
- }
69014
- /**
69015
- * Asserts that this result is NotOk and returns the failure.
69016
- * Throws if the result is Ok.
69017
- */
69018
- assertNotOk() {
69019
- if (this.ok) throw new InternalError("Expected NotOk result but got Ok");
69020
- return this.failure;
69021
- }
69022
- };
69023
- /**
69024
- * Creates a successful result.
69025
- */
69026
- function ok$1(value) {
69027
- return ResultImpl.ok(value);
69028
- }
69029
- /**
69030
- * Creates an unsuccessful result.
69031
- */
69032
- function notOk(failure) {
69033
- return ResultImpl.notOk(failure);
69034
- }
69035
- /**
69036
- * Singleton for void success results.
69037
- * Use this for validation checks that don't produce a value.
69038
- */
69039
- const OK_VOID = ResultImpl.ok(void 0);
69040
- /**
69041
- * Returns a successful void result.
69042
- * Use this for validation checks that don't produce a value.
69043
- */
69044
- function okVoid() {
69045
- return OK_VOID;
69046
- }
69047
70736
  const _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
69048
70737
  function normalizeWindowsPath(input = "") {
69049
70738
  if (!input) return input;
@@ -71133,7 +72822,8 @@ var SqlFamilyDescriptor = class {
71133
72822
  field: sqlFamilyAuthoringFieldPresets,
71134
72823
  type: sqlFamilyAuthoringTypes,
71135
72824
  entityTypes: sqlFamilyEntityTypes,
71136
- pslBlockDescriptors: sqlFamilyPslBlockDescriptors
72825
+ pslBlockDescriptors: sqlFamilyPslBlockDescriptors,
72826
+ attributeSpecs: sqlAttributeSpecs
71137
72827
  };
71138
72828
  create(stack) {
71139
72829
  return createSqlFamilyInstance(stack);
@@ -71666,614 +73356,6 @@ function runnerFailure(code, summary, options) {
71666
73356
  }
71667
73357
  Object.freeze({ allowedOperationClasses: Object.freeze(["additive"]) });
71668
73358
  var control_default = new SqlFamilyDescriptor();
71669
- /**
71670
- * Name of the synthesised namespace bucket the framework parser uses for
71671
- * top-level declarations that appear outside any `namespace { … }` block.
71672
- * The double-underscore decoration signals that the identifier is parser-
71673
- * synthesised and never appears in user-authored PSL source — writing
71674
- * `namespace __unspecified__ { … }` is a parse error.
71675
- *
71676
- * Distinct from the IR sentinel `__unbound__`: the PSL bucket describes
71677
- * syntactic absence at the parser layer; the IR sentinel describes a late-
71678
- * bound storage slot at the IR layer. Per-target interpreters decide how
71679
- * (or whether) to map the PSL bucket to the IR sentinel.
71680
- */
71681
- const UNSPECIFIED_PSL_NAMESPACE_ID = "__unspecified__";
71682
- /**
71683
- * Stores `entries`; exposes `models`/`enums`/`compositeTypes` as getters over
71684
- * it. The getters are prototype members (non-enumerable), so spreading or
71685
- * `JSON.stringify`-ing a namespace copies only `entries`, never a duplicate view.
71686
- */
71687
- var PslNamespaceNode = class {
71688
- kind = "namespace";
71689
- name;
71690
- entries;
71691
- span;
71692
- constructor(init) {
71693
- this.name = init.name;
71694
- this.entries = init.entries;
71695
- this.span = init.span;
71696
- Object.freeze(this);
71697
- }
71698
- get models() {
71699
- return blindCast(Object.values(this.entries["model"] ?? {}));
71700
- }
71701
- get compositeTypes() {
71702
- return blindCast(Object.values(this.entries["compositeType"] ?? {}));
71703
- }
71704
- };
71705
- /** Constructs a {@link PslNamespace}. Use this, never a namespace literal — the accessors must derive from `entries`. */
71706
- function makePslNamespace(init) {
71707
- return new PslNamespaceNode(init);
71708
- }
71709
- /**
71710
- * Builds the frozen `entries[kind][name]` container from per-kind arrays.
71711
- * Built-ins key on their PSL keyword; extension blocks key on their `kind`
71712
- * discriminator. Call this rather than hand-building the literal.
71713
- */
71714
- function makePslNamespaceEntries(models, compositeTypes, extensionBlocks) {
71715
- const container = {};
71716
- if (models.length > 0) {
71717
- const map = {};
71718
- for (const m of models) map[m.name] = m;
71719
- container["model"] = Object.freeze(map);
71720
- }
71721
- if (compositeTypes.length > 0) {
71722
- const map = {};
71723
- for (const ct of compositeTypes) map[ct.name] = ct;
71724
- container["compositeType"] = Object.freeze(map);
71725
- }
71726
- for (const block of extensionBlocks) {
71727
- const existing = container[block.kind];
71728
- const newMap = existing ? blindCast({ ...existing }) : {};
71729
- newMap[block.name] = block;
71730
- container[block.kind] = Object.freeze(newMap);
71731
- }
71732
- return Object.freeze(container);
71733
- }
71734
- /**
71735
- * A token in the red tree. Unlike the green-layer {@link Token} (kind + text
71736
- * only), a red token also carries its absolute `offset` within the source and a
71737
- * link back to its `parent` {@link SyntaxNode}, so a cursor anchored on a token
71738
- * can walk outward (parent, previous/next token, siblings) without re-scanning
71739
- * from the document root.
71740
- */
71741
- var SyntaxToken = class {
71742
- green;
71743
- kind;
71744
- text;
71745
- offset;
71746
- parent;
71747
- /** Position within the parent's children, enabling O(1) sibling navigation without rescanning the green layer. */
71748
- index;
71749
- constructor(green, offset, parent, index) {
71750
- this.green = green;
71751
- this.kind = green.kind;
71752
- this.text = green.text;
71753
- this.offset = offset;
71754
- this.parent = parent;
71755
- this.index = index;
71756
- }
71757
- get textLength() {
71758
- return this.text.length;
71759
- }
71760
- get endOffset() {
71761
- return this.offset + this.textLength;
71762
- }
71763
- /** Whether `offset` falls within this token, inclusive of both ends. */
71764
- isInside(offset) {
71765
- return offset >= this.offset && offset <= this.endOffset;
71766
- }
71767
- isOutside(offset) {
71768
- return !this.isInside(offset);
71769
- }
71770
- /** The sibling element immediately after this token within its parent. */
71771
- get nextSiblingOrToken() {
71772
- return childAt(this.parent, this.index + 1);
71773
- }
71774
- /** The sibling element immediately before this token within its parent. */
71775
- get prevSiblingOrToken() {
71776
- return childAt(this.parent, this.index - 1);
71777
- }
71778
- /** The next token in document order, crossing node boundaries. */
71779
- get nextToken() {
71780
- for (let el = climbingNext(this); el !== void 0; el = climbingNext(el)) {
71781
- const token = firstToken(el);
71782
- if (token !== void 0) return token;
71783
- }
71784
- }
71785
- /** The previous token in document order, crossing node boundaries. */
71786
- get prevToken() {
71787
- for (let el = climbingPrev(this); el !== void 0; el = climbingPrev(el)) {
71788
- const token = lastToken(el);
71789
- if (token !== void 0) return token;
71790
- }
71791
- }
71792
- };
71793
- var TokenAtOffset = class TokenAtOffset {
71794
- #state;
71795
- constructor(state) {
71796
- this.#state = state;
71797
- }
71798
- static none() {
71799
- return new TokenAtOffset({ kind: "none" });
71800
- }
71801
- static single(token) {
71802
- return new TokenAtOffset({
71803
- kind: "single",
71804
- token
71805
- });
71806
- }
71807
- static between(left, right) {
71808
- return new TokenAtOffset({
71809
- kind: "between",
71810
- left,
71811
- right
71812
- });
71813
- }
71814
- get isEmpty() {
71815
- return this.#state.kind === "none";
71816
- }
71817
- get isBetween() {
71818
- return this.#state.kind === "between";
71819
- }
71820
- leftBiased() {
71821
- switch (this.#state.kind) {
71822
- case "none": return;
71823
- case "single": return this.#state.token;
71824
- case "between": return this.#state.left;
71825
- }
71826
- }
71827
- rightBiased() {
71828
- switch (this.#state.kind) {
71829
- case "none": return;
71830
- case "single": return this.#state.token;
71831
- case "between": return this.#state.right;
71832
- }
71833
- }
71834
- };
71835
- var SyntaxNode = class SyntaxNode {
71836
- green;
71837
- offset;
71838
- parent;
71839
- /** Position within the parent's children, enabling O(1) sibling navigation without rescanning the green layer. */
71840
- index;
71841
- constructor(green, offset, parent, index) {
71842
- this.green = green;
71843
- this.offset = offset;
71844
- this.parent = parent;
71845
- this.index = index;
71846
- }
71847
- get kind() {
71848
- return this.green.kind;
71849
- }
71850
- get textLength() {
71851
- return this.green.textLength;
71852
- }
71853
- get endOffset() {
71854
- return this.offset + this.textLength;
71855
- }
71856
- /** Whether `offset` falls within this node, inclusive of both ends. */
71857
- isInside(offset) {
71858
- return offset >= this.offset && offset <= this.endOffset;
71859
- }
71860
- isOutside(offset) {
71861
- return !this.isInside(offset);
71862
- }
71863
- get firstChild() {
71864
- return childAt(this, 0);
71865
- }
71866
- get lastChild() {
71867
- const len = this.green.children.length;
71868
- if (len === 0) return void 0;
71869
- return childAt(this, len - 1);
71870
- }
71871
- get nextSibling() {
71872
- return this.parent === void 0 ? void 0 : childAt(this.parent, this.index + 1);
71873
- }
71874
- get prevSibling() {
71875
- return this.parent === void 0 ? void 0 : childAt(this.parent, this.index - 1);
71876
- }
71877
- /** The sibling element immediately after this node within its parent. */
71878
- get nextSiblingOrToken() {
71879
- return this.nextSibling;
71880
- }
71881
- /** The sibling element immediately before this node within its parent. */
71882
- get prevSiblingOrToken() {
71883
- return this.prevSibling;
71884
- }
71885
- /** The first token in this subtree (depth-first), or `undefined` if empty. */
71886
- get firstToken() {
71887
- return firstToken(this);
71888
- }
71889
- /** The last token in this subtree (depth-first), or `undefined` if empty. */
71890
- get lastToken() {
71891
- return lastToken(this);
71892
- }
71893
- *children() {
71894
- let offset = this.offset;
71895
- let index = 0;
71896
- for (const child of this.green.children) {
71897
- yield wrapElement(child, offset, this, index);
71898
- offset += elementTextLength(child);
71899
- index++;
71900
- }
71901
- }
71902
- *childNodes() {
71903
- for (const child of this.children()) if (child instanceof SyntaxNode) yield child;
71904
- }
71905
- *ancestors() {
71906
- let current = this.parent;
71907
- while (current) {
71908
- yield current;
71909
- current = current.parent;
71910
- }
71911
- }
71912
- /** The nearest match, testing this node itself before walking its ancestors. */
71913
- findAncestor(cast) {
71914
- const self = cast(this);
71915
- if (self !== void 0) return self;
71916
- for (const ancestor of this.ancestors()) {
71917
- const result = cast(ancestor);
71918
- if (result !== void 0) return result;
71919
- }
71920
- }
71921
- *descendants() {
71922
- const stack = [this];
71923
- for (let el = stack.pop(); el !== void 0; el = stack.pop()) {
71924
- yield el;
71925
- if (el instanceof SyntaxNode) {
71926
- const children = Array.from(el.children());
71927
- for (let i = children.length - 1; i >= 0; i--) {
71928
- const child = children[i];
71929
- if (child !== void 0) stack.push(child);
71930
- }
71931
- }
71932
- }
71933
- }
71934
- *tokens() {
71935
- for (const el of this.descendants()) if (el instanceof SyntaxToken) yield el;
71936
- }
71937
- /**
71938
- * The token(s) at `offset`. The between-two-tokens case (offset exactly on a
71939
- * token seam) is represented explicitly so callers can left/right bias.
71940
- */
71941
- tokenAtOffset(offset) {
71942
- return tokenAtOffsetOf(this, offset);
71943
- }
71944
- /**
71945
- * The smallest element fully containing the range `[start, end]`. At a seam
71946
- * (and for empty ranges) the left-hand element is preferred, matching
71947
- * {@link containsOffset}'s inclusive span.
71948
- */
71949
- coveringElement(start, end) {
71950
- let result = this;
71951
- for (;;) {
71952
- if (result instanceof SyntaxToken) return result;
71953
- let next;
71954
- for (const child of result.children()) if (containsRange(child, start, end)) {
71955
- next = child;
71956
- break;
71957
- }
71958
- if (next === void 0) return result;
71959
- result = next;
71960
- }
71961
- }
71962
- };
71963
- function elementTextLength(el) {
71964
- return el.type === "token" ? el.text.length : el.textLength;
71965
- }
71966
- function elementLength(el) {
71967
- return el instanceof SyntaxToken ? el.text.length : el.textLength;
71968
- }
71969
- /**
71970
- * Whether `el` contains `offset`. The span is inclusive on both ends so a seam
71971
- * offset touches both neighbours.
71972
- */
71973
- function containsOffset(el, offset) {
71974
- const start = el.offset;
71975
- const len = elementLength(el);
71976
- return offset >= start && offset <= start + len;
71977
- }
71978
- function containsRange(el, start, end) {
71979
- const elStart = el.offset;
71980
- const len = elementLength(el);
71981
- return elStart <= start && end <= elStart + len;
71982
- }
71983
- function tokenAtOffsetOf(el, offset) {
71984
- if (el instanceof SyntaxToken) return TokenAtOffset.single(el);
71985
- let left;
71986
- let right;
71987
- for (const child of el.children()) {
71988
- if (!containsOffset(child, offset)) continue;
71989
- if (left === void 0) left = child;
71990
- else {
71991
- right = child;
71992
- break;
71993
- }
71994
- }
71995
- if (left === void 0) return TokenAtOffset.none();
71996
- if (right === void 0) return tokenAtOffsetOf(left, offset);
71997
- const leftToken = tokenAtOffsetOf(left, offset).rightBiased();
71998
- const rightToken = tokenAtOffsetOf(right, offset).leftBiased();
71999
- if (leftToken !== void 0 && rightToken !== void 0) return TokenAtOffset.between(leftToken, rightToken);
72000
- if (leftToken !== void 0) return TokenAtOffset.single(leftToken);
72001
- if (rightToken !== void 0) return TokenAtOffset.single(rightToken);
72002
- return TokenAtOffset.none();
72003
- }
72004
- function firstToken(el) {
72005
- if (el instanceof SyntaxToken) return el;
72006
- for (const child of el.children()) {
72007
- const token = firstToken(child);
72008
- if (token !== void 0) return token;
72009
- }
72010
- }
72011
- function lastToken(el) {
72012
- if (el instanceof SyntaxToken) return el;
72013
- const children = Array.from(el.children());
72014
- for (let i = children.length - 1; i >= 0; i--) {
72015
- const child = children[i];
72016
- if (child !== void 0) {
72017
- const token = lastToken(child);
72018
- if (token !== void 0) return token;
72019
- }
72020
- }
72021
- }
72022
- function climbingNext(el) {
72023
- let current = el;
72024
- for (;;) {
72025
- const parent = current.parent;
72026
- if (parent === void 0) return void 0;
72027
- const sibling = childAt(parent, current.index + 1);
72028
- if (sibling !== void 0) return sibling;
72029
- current = parent;
72030
- }
72031
- }
72032
- function climbingPrev(el) {
72033
- let current = el;
72034
- for (;;) {
72035
- const parent = current.parent;
72036
- if (parent === void 0) return void 0;
72037
- const sibling = childAt(parent, current.index - 1);
72038
- if (sibling !== void 0) return sibling;
72039
- current = parent;
72040
- }
72041
- }
72042
- function wrapElement(green, offset, parent, index) {
72043
- if (green.type === "token") return new SyntaxToken(green, offset, parent, index);
72044
- return new SyntaxNode(green, offset, parent, index);
72045
- }
72046
- function childAt(node, index) {
72047
- const children = node.green.children;
72048
- const target = children[index];
72049
- if (target === void 0) return void 0;
72050
- let offset = node.offset;
72051
- for (let i = 0; i < index; i++) {
72052
- const child = children[i];
72053
- if (child !== void 0) offset += elementTextLength(child);
72054
- }
72055
- return wrapElement(target, offset, node, index);
72056
- }
72057
- function findChildToken(node, kind) {
72058
- for (const child of node.children()) if (!(child instanceof SyntaxNode) && child.kind === kind) return child;
72059
- }
72060
- const HEX = /^[0-9a-fA-F]+$/;
72061
- function decodeFixedHex(raw, start, width) {
72062
- if (start + width > raw.length) return void 0;
72063
- const hex = raw.slice(start, start + width);
72064
- if (!HEX.test(hex)) return void 0;
72065
- return String.fromCharCode(Number.parseInt(hex, 16));
72066
- }
72067
- function decodeStringLiteral(raw) {
72068
- let out = "";
72069
- let i = 0;
72070
- while (i < raw.length) {
72071
- const ch = raw.charAt(i);
72072
- if (ch !== "\\" || i + 1 >= raw.length) {
72073
- out += ch;
72074
- i++;
72075
- continue;
72076
- }
72077
- const next = raw.charAt(i + 1);
72078
- switch (next) {
72079
- case "n":
72080
- out += "\n";
72081
- i += 2;
72082
- continue;
72083
- case "r":
72084
- out += "\r";
72085
- i += 2;
72086
- continue;
72087
- case "t":
72088
- out += " ";
72089
- i += 2;
72090
- continue;
72091
- case "\"":
72092
- out += "\"";
72093
- i += 2;
72094
- continue;
72095
- case "'":
72096
- out += "'";
72097
- i += 2;
72098
- continue;
72099
- case "\\":
72100
- out += "\\";
72101
- i += 2;
72102
- continue;
72103
- case "x": {
72104
- const decoded = decodeFixedHex(raw, i + 2, 2);
72105
- if (decoded === void 0) {
72106
- out += "\\x";
72107
- i += 2;
72108
- continue;
72109
- }
72110
- out += decoded;
72111
- i += 4;
72112
- continue;
72113
- }
72114
- case "u": {
72115
- const decoded = decodeFixedHex(raw, i + 2, 4);
72116
- if (decoded === void 0) {
72117
- out += "\\u";
72118
- i += 2;
72119
- continue;
72120
- }
72121
- out += decoded;
72122
- i += 6;
72123
- continue;
72124
- }
72125
- default:
72126
- out += `\\${next}`;
72127
- i += 2;
72128
- continue;
72129
- }
72130
- }
72131
- return out;
72132
- }
72133
- var StringLiteralExprAst = class StringLiteralExprAst {
72134
- syntax;
72135
- constructor(syntax) {
72136
- this.syntax = syntax;
72137
- }
72138
- token() {
72139
- return findChildToken(this.syntax, "StringLiteral");
72140
- }
72141
- value() {
72142
- const tok = this.token();
72143
- if (!tok) return void 0;
72144
- return decodeStringLiteral(tok.text.slice(1, -1));
72145
- }
72146
- static cast(node) {
72147
- return node.kind === "StringLiteralExpr" ? new StringLiteralExprAst(node) : void 0;
72148
- }
72149
- };
72150
- var NumberLiteralExprAst = class NumberLiteralExprAst {
72151
- syntax;
72152
- constructor(syntax) {
72153
- this.syntax = syntax;
72154
- }
72155
- token() {
72156
- return findChildToken(this.syntax, "NumberLiteral");
72157
- }
72158
- value() {
72159
- const tok = this.token();
72160
- if (!tok) return void 0;
72161
- return Number(tok.text);
72162
- }
72163
- static cast(node) {
72164
- return node.kind === "NumberLiteralExpr" ? new NumberLiteralExprAst(node) : void 0;
72165
- }
72166
- };
72167
- function nodePslSpan(node, sourceFile) {
72168
- const start = node.offset;
72169
- const end = start + node.green.textLength;
72170
- return {
72171
- start: offsetToPslPosition(start, sourceFile),
72172
- end: offsetToPslPosition(end, sourceFile)
72173
- };
72174
- }
72175
- function offsetToPslPosition(offset, sourceFile) {
72176
- const position = sourceFile.positionAt(offset);
72177
- return {
72178
- offset,
72179
- line: position.line + 1,
72180
- column: position.character + 1
72181
- };
72182
- }
72183
- const ATTRIBUTE_DIAGNOSTIC_CODE = "PSL_INVALID_ATTRIBUTE_SYNTAX";
72184
- function leafDiagnostic(ctx, node, message, code = ATTRIBUTE_DIAGNOSTIC_CODE) {
72185
- return {
72186
- code,
72187
- message,
72188
- sourceId: ctx.sourceId,
72189
- span: nodePslSpan(node.syntax, ctx.sourceFile)
72190
- };
72191
- }
72192
- function int(opts) {
72193
- const min = opts?.min;
72194
- const max = opts?.max;
72195
- return {
72196
- kind: "int",
72197
- label: "integer",
72198
- parse: (arg, ctx) => {
72199
- if (arg instanceof NumberLiteralExprAst) {
72200
- const value = arg.value();
72201
- if (value !== void 0 && Number.isInteger(value)) {
72202
- if ((min === void 0 || value >= min) && (max === void 0 || value <= max)) return ok$1(value);
72203
- return notOk([leafDiagnostic(ctx, arg, rangeMessage(min, max))]);
72204
- }
72205
- }
72206
- return notOk([leafDiagnostic(ctx, arg, "Expected an integer literal")]);
72207
- }
72208
- };
72209
- }
72210
- function rangeMessage(min, max) {
72211
- if (min !== void 0 && max !== void 0) return `Expected an integer between ${min} and ${max}`;
72212
- if (min !== void 0) return `Expected an integer greater than or equal to ${min}`;
72213
- return `Expected an integer less than or equal to ${max}`;
72214
- }
72215
- function num(value) {
72216
- return {
72217
- kind: "num",
72218
- label: value === void 0 ? "number" : String(value),
72219
- parse: (arg, ctx) => {
72220
- if (arg instanceof NumberLiteralExprAst) {
72221
- const parsed = arg.value();
72222
- if (parsed !== void 0 && (value === void 0 || parsed === value)) return ok$1(parsed);
72223
- }
72224
- return notOk([leafDiagnostic(ctx, arg, value === void 0 ? "Expected a number literal" : `Expected ${value}`)]);
72225
- }
72226
- };
72227
- }
72228
- function oneOf(...alts) {
72229
- const label = alts.map((alt) => alt.label).join(" | ");
72230
- return {
72231
- kind: "oneOf",
72232
- label,
72233
- parse: (arg, ctx) => {
72234
- for (const alt of alts) {
72235
- const result = alt.parse(arg, ctx);
72236
- if (result.ok) return ok$1(blindCast(result.value));
72237
- }
72238
- return notOk([leafDiagnostic(ctx, arg, `Expected one of: ${label}`)]);
72239
- }
72240
- };
72241
- }
72242
- function str() {
72243
- return {
72244
- kind: "str",
72245
- label: "string",
72246
- parse: (arg, ctx) => {
72247
- if (arg instanceof StringLiteralExprAst) {
72248
- const value = arg.value();
72249
- if (value !== void 0) return ok$1(value);
72250
- }
72251
- return notOk([leafDiagnostic(ctx, arg, "Expected a string literal")]);
72252
- }
72253
- };
72254
- }
72255
- function modelAttribute(name, config) {
72256
- return {
72257
- level: "model",
72258
- name,
72259
- positional: config.positional ?? [],
72260
- named: config.named ?? {},
72261
- ...config.refine !== void 0 ? { refine: config.refine } : {}
72262
- };
72263
- }
72264
- function optional(type, ...rest) {
72265
- if (rest.length === 0) return {
72266
- ...type,
72267
- optional: true,
72268
- hasDefault: false
72269
- };
72270
- return {
72271
- ...type,
72272
- optional: true,
72273
- hasDefault: true,
72274
- defaultValue: rest[0]
72275
- };
72276
- }
72277
73359
  const INSTANT_NOW_GENERATOR_ID = "instantNow";
72278
73360
  function instantNowControlDescriptor() {
72279
73361
  return {
@@ -72292,7 +73374,6 @@ function instantNowControlDescriptor() {
72292
73374
  }
72293
73375
  const PSL_RLS_PREDICATE_NOT_FOR_OPERATION = "PSL_RLS_PREDICATE_NOT_FOR_OPERATION";
72294
73376
  const PSL_POLICY_INVALID_MAP = "PSL_POLICY_INVALID_MAP";
72295
- const PSL_NATIVE_ENUM_INVALID_MAP = "PSL_NATIVE_ENUM_INVALID_MAP";
72296
73377
  const PSL_NATIVE_ENUM_BARE_MEMBER = "PSL_NATIVE_ENUM_BARE_MEMBER";
72297
73378
  const PSL_EXTENSION_INVALID_VALUE = "PSL_EXTENSION_INVALID_VALUE";
72298
73379
  const PSL_NATIVE_ENUM_DUPLICATE_MEMBER_VALUE = "PSL_NATIVE_ENUM_DUPLICATE_MEMBER_VALUE";
@@ -72441,19 +73522,10 @@ function lowerRlsPolicyFromBlock(block, ctx) {
72441
73522
  return;
72442
73523
  }
72443
73524
  const permissive = permissiveRaw !== "false";
72444
- const mapAttr = block.blockAttributes.find((a) => a.name === "map");
72445
- if (mapAttr) {
72446
- const rawArg = mapAttr.args[0]?.value;
72447
- const exactName = rawArg?.startsWith("\"") && rawArg.endsWith("\"") && rawArg.length >= 2 ? unwrapQuotedString(rawArg) : void 0;
72448
- if (exactName === void 0 || exactName === "") {
72449
- ctx.diagnostics?.push({
72450
- code: PSL_POLICY_INVALID_MAP,
72451
- message: `\`${block.keyword}\` policy "${block.name}" @@map attribute must have a quoted, non-empty policy-name argument`,
72452
- sourceId: ctx.sourceId ?? "unknown",
72453
- span: mapAttr.span
72454
- });
72455
- return;
72456
- }
73525
+ const mapAttr = block.attributes["map"];
73526
+ if (mapAttr !== void 0) {
73527
+ const exactName = mapAttr.args["name"];
73528
+ invariant(typeof exactName === "string", "@@map on a policy block parses one string argument");
72457
73529
  ctx.warnings?.push(exactNameBodyWarning("policy", exactName));
72458
73530
  return new PostgresRlsPolicy({
72459
73531
  naming: {
@@ -72493,20 +73565,11 @@ function lowerRlsPolicyFromBlock(block, ctx) {
72493
73565
  function lowerNativeEnumFromBlock(block, ctx) {
72494
73566
  const sourceId = ctx.sourceId ?? "unknown";
72495
73567
  const diagnostics = ctx.diagnostics;
72496
- const mapAttr = block.blockAttributes.find((a) => a.name === "map");
73568
+ const mapAttr = block.attributes["map"];
72497
73569
  let typeName = block.name;
72498
- if (mapAttr) {
72499
- const rawArg = mapAttr.args[0]?.value;
72500
- const mapped = rawArg !== void 0 ? unwrapQuotedString(rawArg) : void 0;
72501
- if (mapped === void 0) {
72502
- diagnostics?.push({
72503
- code: PSL_NATIVE_ENUM_INVALID_MAP,
72504
- message: `native_enum "${block.name}" @@map attribute must have a quoted type-name argument`,
72505
- sourceId,
72506
- span: mapAttr.span
72507
- });
72508
- return;
72509
- }
73570
+ if (mapAttr !== void 0) {
73571
+ const mapped = mapAttr.args["name"];
73572
+ invariant(typeof mapped === "string", "@@map on a native_enum block parses one string argument");
72510
73573
  typeName = mapped;
72511
73574
  }
72512
73575
  let memberError = false;
@@ -72692,6 +73755,18 @@ const policyRequiresRls = {
72692
73755
  parameter: "target",
72693
73756
  attribute: "rls"
72694
73757
  };
73758
+ const policyMapAttribute = blockAttribute("map", {
73759
+ positional: [{
73760
+ key: "name",
73761
+ type: str()
73762
+ }],
73763
+ refine: (parsed, ctx, attributeNode) => parsed.name === "" ? [leafDiagnostic(ctx, attributeNode, "@@map policy name must be a non-empty string", PSL_POLICY_INVALID_MAP)] : []
73764
+ });
73765
+ const policyBlockAttributes = { map: () => policyMapAttribute };
73766
+ const nativeEnumMapAttribute = blockAttribute("map", { positional: [{
73767
+ key: "name",
73768
+ type: str()
73769
+ }] });
72695
73770
  const postgresAuthoringPslBlockDescriptors = {
72696
73771
  policy_select: {
72697
73772
  kind: "pslBlock",
@@ -72704,7 +73779,8 @@ const postgresAuthoringPslBlockDescriptors = {
72704
73779
  using: policyPredicateParam,
72705
73780
  permissive: policyPermissiveParam
72706
73781
  },
72707
- requiresModelAttribute: policyRequiresRls
73782
+ requiresModelAttribute: policyRequiresRls,
73783
+ attributes: policyBlockAttributes
72708
73784
  },
72709
73785
  policy_delete: {
72710
73786
  kind: "pslBlock",
@@ -72717,7 +73793,8 @@ const postgresAuthoringPslBlockDescriptors = {
72717
73793
  using: policyPredicateParam,
72718
73794
  permissive: policyPermissiveParam
72719
73795
  },
72720
- requiresModelAttribute: policyRequiresRls
73796
+ requiresModelAttribute: policyRequiresRls,
73797
+ attributes: policyBlockAttributes
72721
73798
  },
72722
73799
  policy_insert: {
72723
73800
  kind: "pslBlock",
@@ -72730,7 +73807,8 @@ const postgresAuthoringPslBlockDescriptors = {
72730
73807
  withCheck: policyPredicateParam,
72731
73808
  permissive: policyPermissiveParam
72732
73809
  },
72733
- requiresModelAttribute: policyRequiresRls
73810
+ requiresModelAttribute: policyRequiresRls,
73811
+ attributes: policyBlockAttributes
72734
73812
  },
72735
73813
  policy_update: {
72736
73814
  kind: "pslBlock",
@@ -72744,7 +73822,8 @@ const postgresAuthoringPslBlockDescriptors = {
72744
73822
  withCheck: policyPredicateParam,
72745
73823
  permissive: policyPermissiveParam
72746
73824
  },
72747
- requiresModelAttribute: policyRequiresRls
73825
+ requiresModelAttribute: policyRequiresRls,
73826
+ attributes: policyBlockAttributes
72748
73827
  },
72749
73828
  policy_all: {
72750
73829
  kind: "pslBlock",
@@ -72758,7 +73837,8 @@ const postgresAuthoringPslBlockDescriptors = {
72758
73837
  withCheck: policyPredicateParam,
72759
73838
  permissive: policyPermissiveParam
72760
73839
  },
72761
- requiresModelAttribute: policyRequiresRls
73840
+ requiresModelAttribute: policyRequiresRls,
73841
+ attributes: policyBlockAttributes
72762
73842
  },
72763
73843
  /**
72764
73844
  * PSL block descriptor for `native_enum`.
@@ -72776,7 +73856,8 @@ const postgresAuthoringPslBlockDescriptors = {
72776
73856
  discriminator: "native_enum",
72777
73857
  name: { required: true },
72778
73858
  parameters: {},
72779
- variadicParameters: true
73859
+ variadicParameters: true,
73860
+ attributes: { map: () => nativeEnumMapAttribute }
72780
73861
  },
72781
73862
  /**
72782
73863
  * PSL block descriptor for `role` (e.g. `role anon {}`). Name-only, no
@@ -72792,6 +73873,8 @@ const postgresAuthoringPslBlockDescriptors = {
72792
73873
  parameters: {}
72793
73874
  }
72794
73875
  };
73876
+ const postgresRlsSpec = modelAttribute("rls", {});
73877
+ const postgresRlsSpecFactory = () => postgresRlsSpec;
72795
73878
  /**
72796
73879
  * `@@` model attributes contributed by the Postgres target pack.
72797
73880
  *
@@ -72804,7 +73887,7 @@ const postgresAuthoringPslBlockDescriptors = {
72804
73887
  const postgresAuthoringModelAttributes = { rls: {
72805
73888
  kind: "modelAttribute",
72806
73889
  attribute: "rls",
72807
- spec: modelAttribute("rls", {}),
73890
+ spec: postgresRlsSpecFactory,
72808
73891
  lower: (_parsed, ctx) => ({
72809
73892
  key: ctx.storageName,
72810
73893
  entity: new PostgresRlsEnablement({
@@ -76216,103 +77299,6 @@ var PostgresRoleSchemaNode = class PostgresRoleSchemaNode extends SqlSchemaIRNod
76216
77299
  assertNode(node, "PostgresRoleSchemaNode", PostgresRoleSchemaNode.is);
76217
77300
  }
76218
77301
  };
76219
- /**
76220
- * Stable code emitted by the runtime when an in-flight `execute()`
76221
- * is cancelled via the per-query `AbortSignal`. The envelope's
76222
- * `details.phase` distinguishes where the abort was observed:
76223
- *
76224
- * - `'encode'` — abort fired during `encodeParams` (SQL) or
76225
- * `resolveValue` (Mongo).
76226
- * - `'decode'` — abort fired during `decodeRow` / `decodeField`.
76227
- * - `'stream'` — abort fired between rows or before any codec call
76228
- * (already-aborted at entry).
76229
- * - `'beforeQuery'` / `'beforeExecute'` / `'afterQuery'` /
76230
- * `'afterExecute'` / `'onRow'` — abort fired on entry to or during
76231
- * the corresponding middleware phase
76232
- * (cooperative cancellation per the param-transform seam).
76233
- */
76234
- const RUNTIME_ABORTED = "RUNTIME.ABORTED";
76235
- /**
76236
- * Construct a `RUNTIME.ABORTED` envelope. Phase distinguishes where the
76237
- * abort was observed — codec call sites (`encode` / `decode` / `stream`)
76238
- * or operation-specific middleware seams, as
76239
- * enumerated on {@link RuntimeAbortedPhase}. Cause carries
76240
- * `signal.reason` verbatim from the platform — native abort produces a
76241
- * `DOMException`, explicit `controller.abort(reason)` produces whatever
76242
- * the caller passed. No synthesis happens here.
76243
- */
76244
- function runtimeAborted(phase, cause) {
76245
- const envelope = runtimeError(RUNTIME_ABORTED, `Operation aborted during ${phase}`, { phase });
76246
- return Object.assign(envelope, { cause });
76247
- }
76248
- /**
76249
- * Throw a phase-tagged `RUNTIME.ABORTED` envelope if the supplied
76250
- * context is already aborted at the precheck site. Centralises the
76251
- * `if (ctx.signal?.aborted) throw runtimeAborted(...)` pattern that
76252
- * every codec dispatch site (and the `beforeExecute` middleware phase)
76253
- * repeats. Accepts both the framework `CodecCallContext` and the
76254
- * `RuntimeMiddlewareContext`; both expose `signal?: AbortSignal`.
76255
- */
76256
- function checkAborted(ctx, phase) {
76257
- if (ctx.signal?.aborted) throw runtimeAborted(phase, ctx.signal.reason);
76258
- }
76259
- /**
76260
- * Race a per-cell `Promise.all` (or any other in-flight work promise) against
76261
- * the supplied abort signal so the runtime returns `RUNTIME.ABORTED` promptly
76262
- * even when codec bodies ignore the signal. In-flight bodies that ignore the
76263
- * signal are abandoned and run to completion in the background — the
76264
- * cooperative-cancellation contract documented in ADR 204.
76265
- *
76266
- * Call sites still SHOULD pre-check `signal.aborted` and short-circuit with
76267
- * a phase-tagged `RUNTIME.ABORTED` envelope before invoking this helper —
76268
- * that path is the canonical "aborted at entry" surface and avoids
76269
- * scheduling the work promise. As a defensive belt-and-braces, this helper
76270
- * also handles the already-aborted case internally: `AbortSignal` does not
76271
- * replay past abort events to listeners registered after the abort, so we
76272
- * inspect `signal.aborted` synchronously and reject with the sentinel
76273
- * before installing the listener. The rejection is still attributed to the
76274
- * abort path via the sentinel-identity check.
76275
- *
76276
- * Distinguishing the rejection source is load-bearing for AC-ERR4
76277
- * (`RUNTIME.ENCODE_FAILED` / `RUNTIME.DECODE_FAILED` pass through unchanged).
76278
- * The semantically equivalent `abortable(signal)` helper in
76279
- * `@internal/utils` rejects with `signal.reason ?? new DOMException(...)`,
76280
- * which is not stably distinguishable from a codec-thrown error by identity
76281
- * alone (a fresh fallback DOMException is allocated per call). We instead
76282
- * track abort attribution with a unique sentinel: only the `onAbort` listener
76283
- * installed here ever rejects with the sentinel, so an `error === sentinel`
76284
- * identity check after the race is unambiguous.
76285
- *
76286
- * Lives in `framework-components` (rather than the SQL family, where it
76287
- * originated in m2) so every family runtime that needs cooperative
76288
- * cancellation around a codec-dispatch `Promise.all` (SQL encode + decode
76289
- * today, Mongo encode in m3) shares the same attribution logic.
76290
- */
76291
- async function raceAgainstAbort(work, signal, phase) {
76292
- if (signal === void 0) return await work;
76293
- const sentinel = { reason: void 0 };
76294
- let onAbort;
76295
- const abortPromise = new Promise((_, reject) => {
76296
- if (signal.aborted) {
76297
- sentinel.reason = signal.reason;
76298
- reject(sentinel);
76299
- return;
76300
- }
76301
- onAbort = () => {
76302
- sentinel.reason = signal.reason;
76303
- reject(sentinel);
76304
- };
76305
- signal.addEventListener("abort", onAbort, { once: true });
76306
- });
76307
- try {
76308
- return await Promise.race([work, abortPromise]);
76309
- } catch (error) {
76310
- if (error === sentinel) throw runtimeAborted(phase, sentinel.reason);
76311
- throw error;
76312
- } finally {
76313
- if (onAbort) signal.removeEventListener("abort", onAbort);
76314
- }
76315
- }
76316
77302
  function adapterError(code, message, options) {
76317
77303
  return structuredError(code, message, options);
76318
77304
  }
@@ -76417,87 +77403,20 @@ function renderLimitOffset(keyword, value, contract, pim) {
76417
77403
  return `${keyword} ${renderExpr(value, contract, pim)}`;
76418
77404
  }
76419
77405
  function renderSelect(ast, contract, pim) {
76420
- const sourcesByRef = collectTableSources(ast);
76421
77406
  return [
76422
- `SELECT ${renderDistinctPrefix(ast.distinct, ast.distinctOn, sourcesByRef, contract, pim)}${renderProjection(ast.projection, contract, pim)}`,
77407
+ `SELECT ${renderDistinctPrefix(ast.distinct, ast.distinctOn, contract, pim)}${renderProjection(ast.projection, contract, pim)}`,
76423
77408
  ast.from !== void 0 ? `FROM ${renderSource(ast.from, contract, pim)}` : "",
76424
77409
  ast.joins?.length ? ast.joins.map((join) => renderJoin(join, contract, pim)).join(" ") : "",
76425
77410
  ast.where ? `WHERE ${renderWhere(ast.where, contract, pim)}` : "",
76426
77411
  ast.groupBy?.length ? `GROUP BY ${ast.groupBy.map((expr) => renderExpr(expr, contract, pim)).join(", ")}` : "",
76427
77412
  ast.having ? `HAVING ${renderWhere(ast.having, contract, pim)}` : "",
76428
77413
  ast.orderBy?.length ? `ORDER BY ${ast.orderBy.map((order) => {
76429
- return `${renderOrderByExpr(order.expr, sourcesByRef, contract, pim)} ${order.dir.toUpperCase()}`;
77414
+ return `${renderExpr(order.expr, contract, pim)} ${order.dir.toUpperCase()}`;
76430
77415
  }).join(", ")}` : "",
76431
77416
  renderLimitOffset("LIMIT", ast.limit, contract, pim),
76432
77417
  renderLimitOffset("OFFSET", ast.offset, contract, pim)
76433
77418
  ].filter((part) => part.length > 0).join(" ").trim();
76434
77419
  }
76435
- /**
76436
- * Map a SELECT's table references (the FROM source and any JOIN sources) to their storage coordinate, keyed by the name a `ColumnRef.table` would carry (the alias when present, otherwise the table name). Derived-table sources are skipped — their columns are projected through a sub-select, not a base storage column, so the enum hook does not apply.
76437
- */
76438
- function collectTableSources(ast) {
76439
- const sources = /* @__PURE__ */ new Map();
76440
- const add = (source) => {
76441
- if (source.kind !== "table-source") return;
76442
- const ref = source.alias ?? source.name;
76443
- sources.set(ref, {
76444
- name: source.name,
76445
- namespaceId: source.namespaceId
76446
- });
76447
- };
76448
- if (ast.from !== void 0) add(ast.from);
76449
- for (const join of ast.joins ?? []) add(join.source);
76450
- return sources;
76451
- }
76452
- /**
76453
- * 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`.
76454
- */
76455
- function allStrings(values) {
76456
- return values.every((value) => typeof value === "string");
76457
- }
76458
- function resolveEnumOrderValues(ref, sourcesByRef, contract) {
76459
- const source = sourcesByRef.get(ref.table);
76460
- if (source === void 0 || source.namespaceId === void 0) return;
76461
- const sourceNs = contract.storage.namespaces[source.namespaceId];
76462
- const valueSet = (sourceNs !== void 0 ? sourceNs.entries.table?.[source.name]?.columns[ref.column] : void 0)?.valueSet;
76463
- if (valueSet === void 0) return;
76464
- const valueSetNs = contract.storage.namespaces[valueSet.namespaceId];
76465
- return valueSetNs !== void 0 ? valueSetNs.entries.valueSet?.[valueSet.entityName]?.values : void 0;
76466
- }
76467
- /**
76468
- * Ordered values for an unqualified ORDER BY column (an `identifier-ref`, the shape the sql-builder emits for `.orderBy('col')`). Scans every FROM/JOIN source for a column of that name. Resolves only when exactly one source has a column of that name and it carries a value-set; if more than one source has such a column the bare identifier is ambiguous (regardless of which are enum-backed), so it falls through to the plain column rendering.
76469
- */
76470
- function resolveEnumOrderValuesForIdentifier(name, sourcesByRef, contract) {
76471
- let matchedColumns = 0;
76472
- let resolved;
76473
- for (const source of sourcesByRef.values()) {
76474
- if (source.namespaceId === void 0) continue;
76475
- const identNs = contract.storage.namespaces[source.namespaceId];
76476
- const column = identNs !== void 0 ? identNs.entries.table?.[source.name]?.columns[name] : void 0;
76477
- if (column === void 0) continue;
76478
- matchedColumns += 1;
76479
- if (matchedColumns > 1) return;
76480
- const valueSet = column.valueSet;
76481
- if (valueSet === void 0) return;
76482
- const valueSetNs = contract.storage.namespaces[valueSet.namespaceId];
76483
- resolved = valueSetNs !== void 0 ? valueSetNs.entries.valueSet?.[valueSet.entityName]?.values : void 0;
76484
- }
76485
- return resolved;
76486
- }
76487
- /**
76488
- * Render an ORDER BY expression. A column reference onto an enum-restricted column sorts by declaration order via `array_position(ARRAY[…]::text[], <col>)` over the value-set's ordered values (NULLs return `NULL` from `array_position`, sorting per the clause's default NULL handling). Both qualified `column-ref`s and the unqualified `identifier-ref`s the sql-builder emits for `.orderBy('col')` are intercepted. Every other expression renders unchanged.
76489
- */
76490
- function renderOrderByExpr(expr, sourcesByRef, contract, pim) {
76491
- if (expr.kind === "column-ref") {
76492
- const orderValues = resolveEnumOrderValues(expr, sourcesByRef, contract);
76493
- if (orderValues !== void 0 && allStrings(orderValues)) return `array_position(ARRAY[${orderValues.map((value) => `'${escapeLiteral(value)}'`).join(", ")}]::text[], ${renderColumn(expr)})`;
76494
- }
76495
- if (expr.kind === "identifier-ref") {
76496
- const orderValues = resolveEnumOrderValuesForIdentifier(expr.name, sourcesByRef, contract);
76497
- if (orderValues !== void 0 && allStrings(orderValues)) return `array_position(ARRAY[${orderValues.map((value) => `'${escapeLiteral(value)}'`).join(", ")}]::text[], ${quoteIdentifier(expr.name)})`;
76498
- }
76499
- return renderExpr(expr, contract, pim);
76500
- }
76501
77420
  function renderProjection(projection, contract, pim) {
76502
77421
  return projection.map((item) => {
76503
77422
  const alias = quoteIdentifier(item.alias);
@@ -76515,8 +77434,8 @@ function renderReturning(items, contract, pim) {
76515
77434
  return `${renderExpr(item.expr, contract, pim)} AS ${quoteIdentifier(item.alias)}`;
76516
77435
  }).join(", ");
76517
77436
  }
76518
- function renderDistinctPrefix(distinct, distinctOn, sourcesByRef, contract, pim) {
76519
- if (distinctOn && distinctOn.length > 0) return `DISTINCT ON (${distinctOn.map((expr) => renderOrderByExpr(expr, sourcesByRef, contract, pim)).join(", ")}) `;
77437
+ function renderDistinctPrefix(distinct, distinctOn, contract, pim) {
77438
+ if (distinctOn && distinctOn.length > 0) return `DISTINCT ON (${distinctOn.map((expr) => renderExpr(expr, contract, pim)).join(", ")}) `;
76520
77439
  if (distinct) return "DISTINCT ";
76521
77440
  return "";
76522
77441
  }
@@ -76920,7 +77839,7 @@ function isLegacyMarkerShapeReadError(message) {
76920
77839
  return normalized.includes("column \"space\" does not exist") || normalized.includes("no such column: space");
76921
77840
  }
76922
77841
  function errorLegacyMarkerShape(options) {
76923
- 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 \`{bin} db init\` to reinitialise from a clean baseline.`, {
77842
+ return errorRunnerFailed(`Legacy marker-table shape detected on ${options.markerLocation} (no \`space\` column). Prisma 8 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 \`{bin} db init\` to reinitialise from a clean baseline.`, {
76924
77843
  why: options.why,
76925
77844
  fix: "Legacy marker-table shape detected. Drop `prisma_contract.marker` (Postgres) or `_prisma_marker` (SQLite) and re-run `{bin} db init` to recreate it with the current per-space schema.",
76926
77845
  nextActions: [{
@@ -79586,28 +80505,31 @@ const postgresDriverDescriptor = {
79586
80505
  /**
79587
80506
  * Renders the checks a Postgres column needs, as opaque predicate text.
79588
80507
  *
79589
- * A text-backed domain enum has no type-level enforcement, so membership is a
80508
+ * A domain enum has no type-level enforcement, so membership is a
79590
80509
  * predicate: `IN` for a scalar, and `<@` containment for an array — an array
79591
80510
  * column cannot use `IN` at all (`operator does not exist: text[] = text`),
79592
80511
  * and containment additionally rejects NULL elements. Every list column also
79593
80512
  * gets an element-non-null check, which no Postgres column type can express.
79594
80513
  *
79595
- * The array side casts the COLUMN to `text[]` rather than assuming its element
79596
- * type already is: `<@` needs both operands in one type, so a `varchar[]` or
79597
- * `char[]` column meeting a bare `text[]` literal raises the same
79598
- * `operator does not exist` this project exists to eliminate. The scalar `IN`
79599
- * form needs no cast — `varchar = text` resolves on its own.
80514
+ * Array containment casts both operands to `numeric[]` for numeric members or
80515
+ * `text[]` for string members, so different storage types share an operator
80516
+ * without comparing numbers as text. The scalar `IN` form needs no cast.
79600
80517
  */
79601
80518
  function postgresRenderCheckExpressions(input) {
79602
80519
  const candidates = [];
79603
80520
  const column = quoteIdentifier(input.columnName);
79604
80521
  if (input.memberValues !== void 0) {
79605
80522
  invariant(input.memberValues.length > 0, `check for "${input.tableName}"."${input.columnName}": empty member set; both authoring surfaces reject a member-less enum before rendering`);
79606
- const members = input.memberValues.map((value) => `'${escapeLiteral(value)}'`).join(", ");
80523
+ const members = input.memberValues.map((value) => {
80524
+ if (typeof value === "string") return `'${escapeLiteral(value)}'`;
80525
+ invariant(Number.isFinite(value), `check for "${input.tableName}"."${input.columnName}": non-finite numeric member`);
80526
+ return String(value);
80527
+ }).join(", ");
80528
+ const arrayType = input.memberValues.every((value) => typeof value === "number") ? "numeric[]" : "text[]";
79607
80529
  candidates.push({
79608
80530
  kind: "membership",
79609
80531
  columnName: input.columnName,
79610
- expression: input.many ? `${column}::text[] <@ ARRAY[${members}]::text[]` : `${column} IN (${members})`
80532
+ expression: input.many ? `${column}::${arrayType} <@ ARRAY[${members}]::${arrayType}` : `${column} IN (${members})`
79611
80533
  });
79612
80534
  }
79613
80535
  if (input.many) candidates.push({
@@ -79631,6 +80553,7 @@ const postgresIndexTypes = defineIndexTypes().add("btree", { options: type("obje
79631
80553
  const postgresTargetDescriptorMeta = {
79632
80554
  ...postgresTargetDescriptorMetaRuntime,
79633
80555
  defaultNamespaceId: DEFAULT_NAMESPACE_ID,
80556
+ supportsNamespaces: true,
79634
80557
  indexTypes: postgresIndexTypes,
79635
80558
  authoring: {
79636
80559
  type: postgresAuthoringTypes$1,
@@ -82719,7 +83642,7 @@ function isNativeEnumSuffixAppend(actualMembers, expectedMembers) {
82719
83642
  }
82720
83643
  /** Operator-worded refusal for a native-enum member change beyond a suffix append (design ruling — tests match this verbatim). */
82721
83644
  function nativeEnumMemberChangeRefusal(options) {
82722
- return `Native enum type "${options.ddlSchemaName}"."${options.typeName}" changed beyond appending new values (contract declares [${options.expectedMembers.join(", ")}], database has [${options.actualMembers.join(", ")}]). Prisma Next does not modify a native enum's existing values (rename, removal, reorder) — see https://pris.ly/d/postgres-native-enums. Author the change manually with \`migration new\`.`;
83645
+ return `Native enum type "${options.ddlSchemaName}"."${options.typeName}" changed beyond appending new values (contract declares [${options.expectedMembers.join(", ")}], database has [${options.actualMembers.join(", ")}]). Prisma 8 does not modify a native enum's existing values (rename, removal, reorder) — see https://pris.ly/d/postgres-native-enums. Author the change manually with \`migration new\`.`;
82723
83646
  }
82724
83647
  /**
82725
83648
  * Managed native-enum issue -> op lowering. A missing declared type creates
@@ -216768,7 +217691,7 @@ function addRelationField(map, tableName, field) {
216768
217691
  if (existing) existing.push(field);
216769
217692
  else map.set(tableName, [field]);
216770
217693
  }
216771
- const LOCK_DOMAIN = "prisma_next.contract.marker";
217694
+ const LOCK_DOMAIN = "prisma_8.contract.marker";
216772
217695
  /**
216773
217696
  * Deep clones and freezes a record object to prevent mutation.
216774
217697
  * Recursively clones nested objects and arrays to ensure complete isolation.
@@ -216945,7 +217868,7 @@ var PostgresMigrationRunner = class {
216945
217868
  if (result.rows.length === 0) return okVoid();
216946
217869
  const columns = new Set(result.rows.map((row) => row.column_name));
216947
217870
  if (columns.has("space")) return okVoid();
216948
- return runnerFailure("MIGRATION.LEGACY_MARKER_SHAPE", "Legacy marker-table shape detected on prisma_contract.marker (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 `prisma_contract.marker` and re-run `dbInit` to reinitialise from a clean baseline.", { meta: {
217871
+ return runnerFailure("MIGRATION.LEGACY_MARKER_SHAPE", "Legacy marker-table shape detected on prisma_contract.marker (no `space` column). Prisma 8 is in pre-1.0; the previous transitional auto-migration to the per-space-row schema has been removed. Drop `prisma_contract.marker` and re-run `dbInit` to reinitialise from a clean baseline.", { meta: {
216949
217872
  table: "prisma_contract.marker",
216950
217873
  columns: [...columns].sort()
216951
217874
  } });
@@ -217394,6 +218317,10 @@ function buildNativeEnumBlock(name, typeName, values) {
217394
218317
  }],
217395
218318
  span: SYNTHETIC_SPAN
217396
218319
  }],
218320
+ attributes: name === typeName ? {} : { map: {
218321
+ args: { name: typeName },
218322
+ span: SYNTHETIC_SPAN
218323
+ } },
217397
218324
  span: SYNTHETIC_SPAN
217398
218325
  };
217399
218326
  }
@@ -217799,7 +218726,7 @@ function buildPolicyBlocks(policiesByTable, modelNameMap, reservedHeads = /* @__
217799
218726
  const badRole = policy.roles.find((role) => !PSL_IDENTIFIER.test(role));
217800
218727
  if (badRole !== void 0) {
217801
218728
  const notes = skipNotesByTable.get(tableName) ?? [];
217802
- notes.push(`// prisma-next: skipped policy "${policy.name}": role "${badRole}" is not a valid PSL identifier and role references cannot be escaped`);
218729
+ notes.push(`// prisma: skipped policy "${policy.name}": role "${badRole}" is not a valid PSL identifier and role references cannot be escaped`);
217803
218730
  skipNotesByTable.set(tableName, notes);
217804
218731
  continue;
217805
218732
  }
@@ -217854,6 +218781,10 @@ function buildPolicyBlocks(policiesByTable, modelNameMap, reservedHeads = /* @__
217854
218781
  }],
217855
218782
  span: SYNTHETIC_SPAN
217856
218783
  }],
218784
+ attributes: { map: {
218785
+ args: { name: policy.name },
218786
+ span: SYNTHETIC_SPAN
218787
+ } },
217857
218788
  span: SYNTHETIC_SPAN
217858
218789
  });
217859
218790
  }
@@ -218208,6 +219139,214 @@ function getEmittedArtifactPaths(outputJsonPath) {
218208
219139
  dtsPath: `${outputJsonPath.slice(0, -5)}.d.ts`
218209
219140
  };
218210
219141
  }
219142
+ const TYPESCRIPT_IDENTIFIER = /^[$A-Z_a-z][$\w]*$/;
219143
+ function namespacedMemberName(namespaceId, modelName) {
219144
+ return `${namespaceId === "__unbound__" ? "unbound" : namespaceId}_${modelName}`;
219145
+ }
219146
+ function bareMemberName(_namespaceId, modelName) {
219147
+ return modelName;
219148
+ }
219149
+ function claimMemberName(claims, memberName, source) {
219150
+ if (!TYPESCRIPT_IDENTIFIER.test(memberName)) throw emitterError("CONTRACT.MODEL_TYPE_NAME_INVALID", `Emitted model type name "${memberName}" (from ${source}) is not a TypeScript identifier`, {
219151
+ why: "Every entry in the emitted Models namespace is declared as `export type <name>`, so the name must be a TypeScript identifier.",
219152
+ fix: "Rename the namespace or model so that <namespace>_<Model> contains only letters, digits, `$`, and `_`, and does not start with a digit.",
219153
+ meta: {
219154
+ memberName,
219155
+ source
219156
+ }
219157
+ });
219158
+ const existing = claims.get(memberName);
219159
+ if (existing !== void 0) throw emitterError("CONTRACT.MODEL_TYPE_NAME_COLLISION", `Emitted model type name "${memberName}" is produced by both ${existing} and ${source}`, {
219160
+ why: "Every entry in the emitted Models namespace needs a distinct name, formed as <namespace>_<Model>.",
219161
+ fix: "Rename one of the models or namespaces so the two names differ.",
219162
+ meta: {
219163
+ memberName,
219164
+ sources: [existing, source]
219165
+ }
219166
+ });
219167
+ claims.set(memberName, source);
219168
+ }
219169
+ function isPolymorphicBase(model) {
219170
+ return model.discriminator !== void 0 && model.variants !== void 0;
219171
+ }
219172
+ function findModelByName(namespaces, namespaceId, modelName) {
219173
+ return namespaces.find((ns) => ns.namespaceId === namespaceId)?.models.find((m) => m.modelName === modelName);
219174
+ }
219175
+ function findModel(namespaces, ref) {
219176
+ return findModelByName(namespaces, ref.namespace, ref.model);
219177
+ }
219178
+ function requireRelationTarget(namespaces, owner, relationName, ref) {
219179
+ const target = findModel(namespaces, ref);
219180
+ if (target !== void 0) return target;
219181
+ const ownerSource = `${owner.namespaceId}.${owner.modelName}`;
219182
+ throw emitterError("CONTRACT.MODEL_RELATION_TARGET_MISSING", `Relation "${relationName}" on ${ownerSource} targets ${ref.namespace}.${ref.model}, which is not in the contract`, {
219183
+ why: "A same-space relation must point at a model the contract declares; only cross-space relations may reference models outside it.",
219184
+ fix: "Declare the target model in the contract, or mark the relation as cross-space by giving its target a `space`.",
219185
+ meta: {
219186
+ owner: ownerSource,
219187
+ relationName,
219188
+ target: {
219189
+ namespaceId: ref.namespace,
219190
+ modelName: ref.model
219191
+ }
219192
+ }
219193
+ });
219194
+ }
219195
+ function requireBase(namespaces, variant, base) {
219196
+ const found = findModel(namespaces, base);
219197
+ if (found !== void 0) return found;
219198
+ const variantSource = `${variant.namespaceId}.${variant.modelName}`;
219199
+ const baseSource = `${base.namespace}.${base.model}`;
219200
+ throw emitterError("CONTRACT.MODEL_BASE_MISSING", `Model ${variantSource} names base ${baseSource}, which is not in the contract`, {
219201
+ why: "A variant's type is its base's fields plus its own, so the base must be a model the contract declares.",
219202
+ fix: "Declare the base model in the contract, or remove `base` from the variant.",
219203
+ meta: {
219204
+ variant: variantSource,
219205
+ base: baseSource
219206
+ }
219207
+ });
219208
+ }
219209
+ function requireVariant(namespaces, base, variantName) {
219210
+ const variant = findModelByName(namespaces, base.namespaceId, variantName);
219211
+ if (variant !== void 0) return variant;
219212
+ const baseSource = `${base.namespaceId}.${base.modelName}`;
219213
+ throw emitterError("CONTRACT.MODEL_VARIANT_MISSING", `Polymorphic base ${baseSource} names variant "${variantName}", which is not in the contract`, {
219214
+ why: "The Any<Base> union is the union of the variant model types, so every variant a base declares must be a model in the same namespace.",
219215
+ fix: "Declare the variant model in the same namespace as the base, or remove it from the base's variants.",
219216
+ meta: {
219217
+ base: baseSource,
219218
+ variantName
219219
+ }
219220
+ });
219221
+ }
219222
+ function collectFieldLines(ref, resolvers, discriminatorType) {
219223
+ const lines = /* @__PURE__ */ new Map();
219224
+ for (const [fieldName, field] of Object.entries(ref.model.fields)) {
219225
+ const type = discriminatorType !== void 0 && fieldName === discriminatorType.field ? discriminatorType.type : resolveModelFieldType(ref.modelName, fieldName, field, ref.model, resolvers).output;
219226
+ lines.set(fieldName, `${serializeObjectKey(fieldName)}: ${type};`);
219227
+ }
219228
+ return lines;
219229
+ }
219230
+ function hasJoin(relation) {
219231
+ return "on" in relation && relation.on !== void 0;
219232
+ }
219233
+ function relationLine(owner, relationName, relation, index) {
219234
+ if (relation.to.space !== void 0) return void 0;
219235
+ const target = requireRelationTarget(index.namespaces, owner, relationName, relation.to);
219236
+ const targetMember = index.memberNameOf(target.namespaceId, isPolymorphicBase(target.model) ? `Any${target.modelName}` : target.modelName);
219237
+ const key = serializeObjectKey(relationName);
219238
+ if (!hasJoin(relation)) return {
219239
+ line: `${key}: ${relation.cardinality === "1:N" ? `${targetMember}[]` : targetMember};`,
219240
+ hasJoin: false
219241
+ };
219242
+ if (relation.cardinality === "1:N" || relation.cardinality === "N:M") return {
219243
+ line: `${key}: ${targetMember}[];`,
219244
+ hasJoin: true
219245
+ };
219246
+ return {
219247
+ line: `${key}: ${relation.nullable ? `${targetMember} | null` : targetMember};`,
219248
+ hasJoin: true
219249
+ };
219250
+ }
219251
+ function collectRelationLines(ref, index) {
219252
+ const lines = /* @__PURE__ */ new Map();
219253
+ for (const [relationName, relation] of Object.entries(ref.model.relations)) {
219254
+ const rendered = relationLine(ref, relationName, relation, index);
219255
+ if (rendered !== void 0) lines.set(relationName, rendered);
219256
+ }
219257
+ return lines;
219258
+ }
219259
+ function discriminatorUnion(base) {
219260
+ const values = Object.values(base.variants ?? {}).map((v) => serializeValue(v.value));
219261
+ return values.length > 0 ? values.join(" | ") : "never";
219262
+ }
219263
+ function memberLines(ref, index, resolvers) {
219264
+ const base = ref.model.base !== void 0 ? requireBase(index.namespaces, ref, ref.model.base) : void 0;
219265
+ if (base !== void 0 && isPolymorphicBase(base.model)) {
219266
+ const discriminatorField = base.model.discriminator?.field ?? "";
219267
+ const variantValue = base.model.variants?.[ref.modelName]?.value;
219268
+ const discriminatorType = {
219269
+ field: discriminatorField,
219270
+ type: variantValue !== void 0 ? serializeValue(variantValue) : discriminatorUnion(base.model)
219271
+ };
219272
+ return {
219273
+ fieldsByName: new Map([...collectFieldLines(base, resolvers, discriminatorType), ...collectFieldLines(ref, resolvers, void 0)]),
219274
+ relationsByName: new Map([...collectRelationLines(base, index), ...collectRelationLines(ref, index)])
219275
+ };
219276
+ }
219277
+ return {
219278
+ fieldsByName: collectFieldLines(ref, resolvers, isPolymorphicBase(ref.model) ? {
219279
+ field: ref.model.discriminator?.field ?? "",
219280
+ type: discriminatorUnion(ref.model)
219281
+ } : void 0),
219282
+ relationsByName: collectRelationLines(ref, index)
219283
+ };
219284
+ }
219285
+ function renderMember(memberName, lines, hasOwner) {
219286
+ const entries = [...lines.relationsByName];
219287
+ const joinlessLines = entries.filter(([, r]) => !r.hasJoin).map(([, r]) => r.line);
219288
+ const joinedLines = entries.filter(([, r]) => r.hasJoin).map(([, r]) => r.line);
219289
+ const relationNames = entries.filter(([, r]) => r.hasJoin).map(([name]) => name);
219290
+ const phantom = relationNames.length > 0 ? relationNames.map((name) => serializeValue(name)).join(" | ") : "never";
219291
+ return ` export type ${memberName} = {\n${[
219292
+ ...lines.fieldsByName.values(),
219293
+ ...joinlessLines,
219294
+ ...joinedLines,
219295
+ ...hasOwner ? [] : [`readonly [RelationKeys]?: ${phantom};`]
219296
+ ].map((line) => ` ${line}`).join("\n")}\n };`;
219297
+ }
219298
+ function namespaceModelsOf(contract) {
219299
+ return Object.entries(contract.domain.namespaces).map(([namespaceId, ns]) => ({
219300
+ namespaceId,
219301
+ models: Object.entries(ns.models).map(([modelName, model]) => ({
219302
+ namespaceId,
219303
+ modelName,
219304
+ model
219305
+ }))
219306
+ }));
219307
+ }
219308
+ function generateModelTypesBlock(contract, resolvers, supportsNamespaces) {
219309
+ const memberNameOf = supportsNamespaces ? namespacedMemberName : bareMemberName;
219310
+ const namespaces = namespaceModelsOf(contract);
219311
+ const index = {
219312
+ namespaces,
219313
+ memberNameOf
219314
+ };
219315
+ const claims = /* @__PURE__ */ new Map();
219316
+ for (const ns of namespaces) for (const ref of ns.models) claimMemberName(claims, memberNameOf(ns.namespaceId, ref.modelName), `${ns.namespaceId}.${ref.modelName}`);
219317
+ for (const ns of namespaces) for (const ref of ns.models) {
219318
+ if (!isPolymorphicBase(ref.model)) continue;
219319
+ claimMemberName(claims, memberNameOf(ns.namespaceId, `Any${ref.modelName}`), `${ns.namespaceId}.Any<${ref.modelName}>`);
219320
+ }
219321
+ const members = [];
219322
+ const constantEntries = [];
219323
+ for (const ns of namespaces) {
219324
+ const keys = [];
219325
+ for (const ref of ns.models) {
219326
+ const memberName = memberNameOf(ns.namespaceId, ref.modelName);
219327
+ members.push(renderMember(memberName, memberLines(ref, index, resolvers), ref.model.owner !== void 0));
219328
+ keys.push(`${serializeObjectKey(ref.modelName)}: Models.${memberName};`);
219329
+ }
219330
+ for (const ref of ns.models) {
219331
+ if (!isPolymorphicBase(ref.model)) continue;
219332
+ const unionName = memberNameOf(ns.namespaceId, `Any${ref.modelName}`);
219333
+ const variantMembers = Object.keys(ref.model.variants ?? {}).map((variantName) => {
219334
+ const variant = requireVariant(namespaces, ref, variantName);
219335
+ return memberNameOf(variant.namespaceId, variant.modelName);
219336
+ });
219337
+ members.push(` export type ${unionName} = ${variantMembers.length > 0 ? variantMembers.join(" | ") : "never"};`);
219338
+ keys.push(`${serializeObjectKey(`Any${ref.modelName}`)}: Models.${unionName};`);
219339
+ }
219340
+ if (!supportsNamespaces) {
219341
+ constantEntries.push(...keys.map((key) => ` ${key}`));
219342
+ continue;
219343
+ }
219344
+ const nsKey = serializeObjectKey(ns.namespaceId);
219345
+ const nested = keys.map((key) => ` ${key}`).join("\n");
219346
+ constantEntries.push(keys.length > 0 ? ` ${nsKey}: {\n${nested}\n };` : ` ${nsKey}: {};`);
219347
+ }
219348
+ return `${members.length > 0 ? `export namespace Models {\n${members.join("\n")}\n}` : "export namespace Models {}"}\n\n${`export declare const models: {\n${constantEntries.join("\n")}\n};`}`;
219349
+ }
218211
219350
  function generateEnumBlockType(enums) {
218212
219351
  return `{ ${Object.entries(enums).map(([name, entry]) => {
218213
219352
  const membersType = `readonly [${entry.members.map((m) => `{ readonly name: ${serializeValue(m.name)}; readonly value: ${serializeValue(m.value)} }`).join(", ")}]`;
@@ -218256,6 +219395,11 @@ function generateContractDts(contract, emitter, codecTypeImports, hashes, option
218256
219395
  const fieldTypesMaps = generateFieldTypesMapsByNamespace(namespaceEntries.map(([nsId, ns]) => [nsId, ns.models]), codecLookup, resolveFieldTypeParams, resolveFieldValueSet);
218257
219396
  const extraTypeExports = emitter.getStorageTypeExports?.(contract, codecLookup);
218258
219397
  const contractWrapper = emitter.getContractWrapper("ContractBase", "TypeMaps");
219398
+ const modelTypesBlock = generateModelTypesBlock(contract, {
219399
+ codecLookup,
219400
+ resolveFieldTypeParams,
219401
+ resolveFieldValueSet
219402
+ }, options?.supportsNamespaces ?? true);
218259
219403
  return `// ⚠️ GENERATED FILE - DO NOT EDIT
218260
219404
  // This file is automatically generated by 'prisma contract emit'.
218261
219405
  // To regenerate, run: prisma contract emit
@@ -218277,7 +219421,10 @@ ${familyTypeAliases}
218277
219421
  ${valueObjectTypeAliases}
218278
219422
  export type FieldOutputTypes = ${fieldTypesMaps.output};
218279
219423
  export type FieldInputTypes = ${fieldTypesMaps.input};
218280
- ${extraTypeExports ? `${extraTypeExports}\n` : ""}export type TypeMaps = ${typeMapsExpr};
219424
+ ${extraTypeExports ? `${extraTypeExports}\n` : ""}
219425
+ ${modelTypesBlock}
219426
+
219427
+ export type TypeMaps = ${typeMapsExpr};
218281
219428
 
218282
219429
  type ContractBase = Omit<
218283
219430
  ContractType<${storageType}>,
@@ -218301,9 +219448,29 @@ ${domainNamespacesType};
218301
219448
  ${contractWrapper}
218302
219449
  `;
218303
219450
  }
219451
+ /**
219452
+ * The emitter only ever consumes a freshly authored contract, so every same-space to-one relation
219453
+ * must already state whether it is nullable. Hydration of an on-disk contract derives a missing
219454
+ * flag instead; that path never reaches here.
219455
+ */
219456
+ function requireToOneRelationNullability(contract) {
219457
+ for (const [namespaceId, namespace] of Object.entries(contract.domain.namespaces)) for (const [modelName, model] of Object.entries(namespace.models)) for (const [relationName, relation] of Object.entries(model.relations ?? {})) {
219458
+ if (!("on" in relation && (relation.cardinality === "1:1" || relation.cardinality === "N:1") && relation.to.space === void 0) || typeof relation.nullable === "boolean") continue;
219459
+ throw emitterError("CONTRACT.RELATION_INVALID", `Relation "${relationName}" on model "${namespaceId}:${modelName}" is a ${relation.cardinality} relation and must carry a boolean "nullable"`, {
219460
+ why: "contract.d.ts types a to-one relation as nullable or required from this flag, and the authoring surfaces always set it.",
219461
+ fix: "Author the contract through PSL or the contract builder, which derive the flag from the local fields the relation joins on.",
219462
+ meta: {
219463
+ modelName,
219464
+ relationName,
219465
+ reason: "to-one-nullability-missing"
219466
+ }
219467
+ });
219468
+ }
219469
+ }
218304
219470
  const SCHEMA_VERSION = "1";
218305
219471
  async function emit(contract, stack, targetFamily, options) {
218306
219472
  if (options.outputJsonPath !== void 0) getEmittedArtifactPaths(options.outputJsonPath);
219473
+ requireToOneRelationNullability(contract);
218307
219474
  const { codecTypeImports, queryOperationTypeImports, aggregateDescriptors, codecDescriptors } = stack;
218308
219475
  const { storageHash } = contract.storage;
218309
219476
  const executionHash = contract.execution?.executionHash;
@@ -218325,7 +219492,8 @@ async function emit(contract, stack, targetFamily, options) {
218325
219492
  const generateOptions = {
218326
219493
  ...ifDefined("queryOperationTypeImports", queryOperationTypeImports),
218327
219494
  ...ifDefined("aggregateDescriptors", aggregateDescriptors),
218328
- ...ifDefined("codecDescriptors", codecDescriptors)
219495
+ ...ifDefined("codecDescriptors", codecDescriptors),
219496
+ ...ifDefined("supportsNamespaces", options.supportsNamespaces)
218329
219497
  };
218330
219498
  const contractTypeHashes = {
218331
219499
  storageHash,
@@ -218689,7 +219857,7 @@ function isControlPolicy(value) {
218689
219857
  * This is the precondition for advancing a contract space's marker without
218690
219858
  * any migrations (the declared-state resolution the db-init aggregate
218691
219859
  * planner and `migrate` share): only when nothing in the space is
218692
- * Prisma-Next-managed can the storage structure be correct without a
219860
+ * Prisma 8-managed can the storage structure be correct without a
218693
219861
  * migration having produced it. Any space that declares a managed element
218694
219862
  * but ships no migration graph is an authoring bug and must fail loudly.
218695
219863
  */
@@ -220867,7 +222035,7 @@ function buildPathNotFoundFailure(spaceId, marker, targetHash) {
220867
222035
  };
220868
222036
  }
220869
222037
  /**
220870
- * Creates a programmatic control client for Prisma Next operations.
222038
+ * Creates a programmatic control client for Prisma ORM operations.
220871
222039
  *
220872
222040
  * The client accepts framework component descriptors at creation time,
220873
222041
  * manages driver lifecycle via connect()/close(), and exposes domain
@@ -221355,7 +222523,10 @@ var ControlClientImpl = class {
221355
222523
  meta: void 0
221356
222524
  });
221357
222525
  }
221358
- const result = await emit(deserializedContract, this.stack, this.options.family.emission, { serializeContract: (contract) => this.options.target.contractSerializer.serializeContract(contract) });
222526
+ const result = await emit(deserializedContract, this.stack, this.options.family.emission, {
222527
+ serializeContract: (contract) => this.options.target.contractSerializer.serializeContract(contract),
222528
+ ...ifDefined("supportsNamespaces", this.options.target.supportsNamespaces)
222529
+ });
221359
222530
  onProgress?.({
221360
222531
  action: "emit",
221361
222532
  kind: "spanEnd",
@@ -221403,7 +222574,7 @@ function createPostgresControlClient(options = {}) {
221403
222574
  ...ifDefined("extensions", options.extensions)
221404
222575
  });
221405
222576
  }
221406
- var version = "0.18.0-dev.1";
222577
+ var version = "0.18.0-dev.2";
221407
222578
  var migration_default = {
221408
222579
  from: null,
221409
222580
  to: "9e4dbceec6522a4ffb997dfe82c437de70264962803f6a2c63eb196281232b32",