@wildo-ai/zod-decorators 1.1.11 → 1.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/dist/esm/commons.d.ts.map +1 -1
  2. package/dist/esm/commons.js.map +1 -1
  3. package/dist/esm/currencies.shared.schemas.d.ts.map +1 -1
  4. package/dist/esm/currencies.shared.schemas.js.map +1 -1
  5. package/dist/esm/files/agent-file-formats.d.ts.map +1 -1
  6. package/dist/esm/files/agent-file-formats.js.map +1 -1
  7. package/dist/esm/files/extension-nature-map.d.ts.map +1 -1
  8. package/dist/esm/files/extension-nature-map.js.map +1 -1
  9. package/dist/esm/files/file-extensions.enum.d.ts.map +1 -1
  10. package/dist/esm/files/file-extensions.enum.js.map +1 -1
  11. package/dist/esm/files/mime-registry.d.ts.map +1 -1
  12. package/dist/esm/files/mime-registry.js.map +1 -1
  13. package/dist/esm/files/unified-registry.d.ts.map +1 -1
  14. package/dist/esm/files/unified-registry.js.map +1 -1
  15. package/dist/esm/index.d.ts +2 -0
  16. package/dist/esm/index.d.ts.map +1 -1
  17. package/dist/esm/index.js +2 -0
  18. package/dist/esm/index.js.map +1 -1
  19. package/dist/esm/install-bigint-json-encoding.d.ts +1 -1
  20. package/dist/esm/install-bigint-json-encoding.d.ts.map +1 -1
  21. package/dist/esm/install-bigint-json-encoding.js +1 -1
  22. package/dist/esm/install-bigint-json-encoding.js.map +1 -1
  23. package/dist/esm/testing/decorated-test-schemas.d.ts +7 -7
  24. package/dist/esm/testing/decorated-test-schemas.d.ts.map +1 -1
  25. package/dist/esm/testing/decorated-test-schemas.js.map +1 -1
  26. package/dist/esm/testing.d.ts.map +1 -1
  27. package/dist/esm/testing.js.map +1 -1
  28. package/dist/esm/zod-address.d.ts.map +1 -1
  29. package/dist/esm/zod-address.js.map +1 -1
  30. package/dist/esm/zod-bigdecimal.d.ts +4 -4
  31. package/dist/esm/zod-bigdecimal.d.ts.map +1 -1
  32. package/dist/esm/zod-bigdecimal.js.map +1 -1
  33. package/dist/esm/zod-code.d.ts +4 -4
  34. package/dist/esm/zod-code.d.ts.map +1 -1
  35. package/dist/esm/zod-code.js.map +1 -1
  36. package/dist/esm/zod-color.d.ts.map +1 -1
  37. package/dist/esm/zod-color.js.map +1 -1
  38. package/dist/esm/zod-decorators.types.d.ts +116 -9
  39. package/dist/esm/zod-decorators.types.d.ts.map +1 -1
  40. package/dist/esm/zod-decorators.types.js +40 -1
  41. package/dist/esm/zod-decorators.types.js.map +1 -1
  42. package/dist/esm/zod-document-sequence.d.ts.map +1 -1
  43. package/dist/esm/zod-document-sequence.js.map +1 -1
  44. package/dist/esm/zod-duration.d.ts +6 -6
  45. package/dist/esm/zod-duration.d.ts.map +1 -1
  46. package/dist/esm/zod-duration.js.map +1 -1
  47. package/dist/esm/zod-file.d.ts +5 -4
  48. package/dist/esm/zod-file.d.ts.map +1 -1
  49. package/dist/esm/zod-file.js +1 -1
  50. package/dist/esm/zod-file.js.map +1 -1
  51. package/dist/esm/zod-money.d.ts +4 -4
  52. package/dist/esm/zod-money.d.ts.map +1 -1
  53. package/dist/esm/zod-money.js.map +1 -1
  54. package/dist/esm/zod-phone.d.ts +4 -4
  55. package/dist/esm/zod-phone.d.ts.map +1 -1
  56. package/dist/esm/zod-phone.js.map +1 -1
  57. package/dist/esm/zod-range.d.ts.map +1 -1
  58. package/dist/esm/zod-range.js.map +1 -1
  59. package/dist/esm/zod-utils.shared.d.ts +47 -12
  60. package/dist/esm/zod-utils.shared.d.ts.map +1 -1
  61. package/dist/esm/zod-utils.shared.js +143 -40
  62. package/dist/esm/zod-utils.shared.js.map +1 -1
  63. package/dist/esm/zod-versioned.d.ts.map +1 -1
  64. package/dist/esm/zod-versioned.js.map +1 -1
  65. package/dist/esm/zod-wire-date.d.ts +107 -0
  66. package/dist/esm/zod-wire-date.d.ts.map +1 -0
  67. package/dist/esm/zod-wire-date.js +162 -0
  68. package/dist/esm/zod-wire-date.js.map +1 -0
  69. package/dist/esm/zod-year-month.d.ts +76 -0
  70. package/dist/esm/zod-year-month.d.ts.map +1 -0
  71. package/dist/esm/zod-year-month.js +115 -0
  72. package/dist/esm/zod-year-month.js.map +1 -0
  73. package/dist/esm/zod.module-override.d.ts +139 -156
  74. package/dist/esm/zod.module-override.d.ts.map +1 -1
  75. package/dist/esm/zod.module-override.js +176 -6
  76. package/dist/esm/zod.module-override.js.map +1 -1
  77. package/dist/tsconfig.build.tsbuildinfo +1 -1
  78. package/package.json +5 -5
@@ -77,7 +77,8 @@ export const ZodDecorator_ApplyableType = {
77
77
  // • ZodBigInt × 16 — see its prototype block; every other layer already treats bigint as a leaf.
78
78
  // • ZodObject `isDBIndexed`/`isHidden`/`isNotEditable` — a composite field is indexable,
79
79
  // hideable and non-editable. The TS2320 clash with `z_file()`'s mixin was the only obstacle
80
- // and it cost nothing to remove, because `DecoratedPrimitiveZodType<T>` is `T & {…}`.
80
+ // and it cost nothing to remove: a decorator returns `this`, which for `z_file()` is its own
81
+ // interface, so the members it adds are kept.
81
82
  // • `isBusinessKey` on ZodBoolean/ZodDate — the map says it mirrors IS_DB_INDEXED's primitive
82
83
  // set, and that IS on both. A date is a legitimate natural-key component.
83
84
  // • ZodOptional `ttl`/`isPassword`/`isOtp`/`isColor`/`businessKeySet` — natural authoring
@@ -129,6 +130,7 @@ export const ZodDecorator_ApplyableType = {
129
130
  // The list/FunctionType/prototype-install/`declare module` augmentations are ONE unit here too.
130
131
  [ZodDecorator.IS_LAST_ACTION_RECORD]: ApplyableTypeAllTypes,
131
132
  [ZodDecorator.IS_DECIDER]: ApplyableTypeAllTypes,
133
+ [ZodDecorator.IS_ROLE_GRANT]: ApplyableTypeAllTypes,
132
134
  // RAG source — deliberately NOT all-types: only TEXT can be a retrieval-corpus source, so the
133
135
  // fluent surface is string-backed (plus the wrappers a string field routinely lives under; the
134
136
  // string-FORMAT types get the method from the `ZodStringFormat.prototype` install, which — per the
@@ -170,6 +172,9 @@ export const ZodDecorator_ApplyableType = {
170
172
  // Every wrapper that can hold an object and whose inner shape `findObjectShape` can reach —
171
173
  // Optional, Nullable and Default all already carry the method at runtime via the wrapper loop.
172
174
  [ZodDecorator.OBJECT_BUSINESS_KEY_SET]: ['ZodObject', 'ZodOptional', 'ZodNullable', 'ZodDefault'],
175
+ // A compound index names fields of the object it decorates, so it applies to an object with a shape, and only to
176
+ // one: an index belongs to a stored row, and a resource's main schema is always a plain object.
177
+ [ZodDecorator.OBJECT_COMPOUND_INDEX]: ['ZodObject'],
173
178
  // A resource reference names its two members, so it applies to an object with a shape, and only to one.
174
179
  [ZodDecorator.RESOURCE_REFERENCE]: ['ZodObject'],
175
180
  // TTL (Time To Live) - only for Date fields (MongoDB TTL indexes work on Date fields)
@@ -277,6 +282,7 @@ const STRING_SCHEMA_DECORATOR_SURFACE = [
277
282
  ZodDecorator.IS_AUDIT_EVIDENCE,
278
283
  ZodDecorator.IS_LAST_ACTION_RECORD,
279
284
  ZodDecorator.IS_DECIDER,
285
+ ZodDecorator.IS_ROLE_GRANT,
280
286
  // RAG source — string-backed by nature (only text can be a corpus source), and a format validator
281
287
  // is a legitimate carrier: markdown/documentation fields are routinely `z.string()`, but a
282
288
  // `z.url()` pointing at authored content is not excluded from being chunked as text.
@@ -487,6 +493,25 @@ export const ZodDecorator_FunctionType = {
487
493
  },
488
494
  ]);
489
495
  },
496
+ // compoundIndex (#3142): one more NON-unique index over several fields of this object. Validated at decoration time,
497
+ // like businessKeySet, so an index cannot name a field the row does not carry; storage would otherwise build an index
498
+ // over a path that is always empty, or the SQL plan would refuse at migration time, far from the declaration.
499
+ compoundIndex: function (fields) {
500
+ if (!Array.isArray(fields) || fields.length < 2) {
501
+ throw new Error(`compoundIndex([...]) needs at least two field names (received ${JSON.stringify(fields)}); a one-field index is .isDBIndexed() on the field.`);
502
+ }
503
+ const repeated = fields.filter((field, index) => fields.indexOf(field) !== index);
504
+ if (repeated.length > 0) {
505
+ throw new Error(`compoundIndex([...]) names a field more than once: ${[...new Set(repeated)].join(', ')}.`);
506
+ }
507
+ const node = this;
508
+ const shape = node.shape ?? node._zod?.def?.shape;
509
+ const missing = fields.filter((field) => !shape || !(field in shape));
510
+ if (missing.length > 0) {
511
+ throw new Error(`compoundIndex([...]) references field(s) not present in the schema shape: ${missing.join(', ')}.`);
512
+ }
513
+ return addDecorators(this, [{ ref: ZodDecorator.OBJECT_COMPOUND_INDEX, params: { fields: [...fields] } }]);
514
+ },
490
515
  // isResourceReference (#2471): the object names one row of a resource chosen at run time. Validated at decoration
491
516
  // time, like businessKeySet: the object must HAVE the two members the reference is read through, or a form would
492
517
  // offer a picker that writes into fields the schema does not carry.
@@ -526,6 +551,7 @@ export const ZodDecorator_FunctionType = {
526
551
  // Last-action record — a PURE parameterless marker, like isAuditEvidence: it implies no other decorator.
527
552
  isLastActionRecord: function () { return addDecorators(this, [ZodDecorator.IS_LAST_ACTION_RECORD]); },
528
553
  isDecider: function () { return addDecorators(this, [ZodDecorator.IS_DECIDER]); },
554
+ isRoleGrant: function () { return addDecorators(this, [ZodDecorator.IS_ROLE_GRANT]); },
529
555
  // RAG source (resource-native RAG capability). The config is OPTIONAL — a bare `.ragSource()` is a
530
556
  // complete declaration — so unlike impersonalizeWith there is no required-value door to guard;
531
557
  // what the shared `applySingleDecorator` chokepoint enforces instead is config validity
@@ -1238,6 +1264,48 @@ function assertCalendarDateNotDateTime(decorator, currentMetadata) {
1238
1264
  'Declare a day with isCalendarDate() (and dateUI() for its display), or a moment with dateTimeUI().');
1239
1265
  }
1240
1266
  }
1267
+ /**
1268
+ * The decorators that mark a value as a SECRET, each with the reason a subject-disclosed backend-only field
1269
+ * (`isBackendOnly({ disclosedToSubject: true })`, #2958) may never carry it. One table, consulted in both application
1270
+ * orders by {@link assertSubjectDisclosureAdmissible}, at the same chokepoint as the RAG-source pairs, so no door into the
1271
+ * metadata bypasses it.
1272
+ */
1273
+ const SUBJECT_DISCLOSURE_REFUSED_COMPANIONS = new Map([
1274
+ [ZodDecorator.IS_PASSWORD, 'a password never leaves the backend, not even to the person it belongs to.'],
1275
+ [ZodDecorator.IS_OTP, 'a one-time code never leaves the backend once it was sent.'],
1276
+ [ZodDecorator.IS_WRITE_ONLY_SECRET, 'a write-only secret is masked on every response, so it is not disclosed to anyone.'],
1277
+ [ZodDecorator.IS_EPHEMERAL, 'an ephemeral value is shown once, when it is minted, and never again.'],
1278
+ ]);
1279
+ /** Whether a stored `IS_BACKEND_ONLY` value declares the subject-disclosure opt-in. */
1280
+ function declaresDisclosedToSubject(value) {
1281
+ return typeof value === 'object' && value !== null && value.disclosedToSubject === true;
1282
+ }
1283
+ /**
1284
+ * Refuse `isBackendOnly({ disclosedToSubject: true })` on a field that holds a secret, in either order (#2958): applied to
1285
+ * a field already marked a secret, applied with `isReturnedAtCreation` (a server-minted secret shown once), or a secret
1286
+ * marker applied to a field already opted in. Run after an updater is resolved, so an updater that adds the opt-in is
1287
+ * checked too, and before anything is written.
1288
+ */
1289
+ function assertSubjectDisclosureAdmissible(decorator, params, currentMetadata) {
1290
+ if (decorator === ZodDecorator.IS_BACKEND_ONLY) {
1291
+ if (!declaresDisclosedToSubject(params))
1292
+ return;
1293
+ if (params.isReturnedAtCreation) {
1294
+ throw new Error('isBackendOnly() cannot declare both disclosedToSubject and isReturnedAtCreation: a value returned once at creation is a '
1295
+ + 'server-minted secret, and a subject export never discloses a secret.');
1296
+ }
1297
+ for (const [companion, reason] of SUBJECT_DISCLOSURE_REFUSED_COMPANIONS) {
1298
+ if (currentMetadata[companion] !== undefined) {
1299
+ throw new Error(`isBackendOnly({ disclosedToSubject: true }) cannot be combined with ${companion}(): ${reason}`);
1300
+ }
1301
+ }
1302
+ return;
1303
+ }
1304
+ const reason = SUBJECT_DISCLOSURE_REFUSED_COMPANIONS.get(decorator);
1305
+ if (reason !== undefined && declaresDisclosedToSubject(currentMetadata[ZodDecorator.IS_BACKEND_ONLY])) {
1306
+ throw new Error(`${decorator}() cannot be combined with isBackendOnly({ disclosedToSubject: true }): ${reason}`);
1307
+ }
1308
+ }
1241
1309
  function applySingleDecorator(schema, decorator, params) {
1242
1310
  // Ensure schema exists before accessing Symbol property
1243
1311
  if (!schema) {
@@ -1260,6 +1328,8 @@ function applySingleDecorator(schema, decorator, params) {
1260
1328
  params = params(currentValue);
1261
1329
  resolvedFromUpdater = true;
1262
1330
  }
1331
+ // A subject-disclosed backend-only field never holds a secret (#2958). Checked on the RESOLVED params, before any write.
1332
+ assertSubjectDisclosureAdmissible(decorator, params, currentMetadata);
1263
1333
  // After function resolution, params is a concrete value (never a function).
1264
1334
  // TypeScript can't narrow this from control flow. Use `rp<D>()` for typed
1265
1335
  // access in cases that read properties; use `p` for simple assignments.
@@ -1405,6 +1475,9 @@ function applySingleDecorator(schema, decorator, params) {
1405
1475
  case ZodDecorator.IS_DECIDER:
1406
1476
  currentMetadata[ZodDecorator.IS_DECIDER] = true;
1407
1477
  break;
1478
+ case ZodDecorator.IS_ROLE_GRANT:
1479
+ currentMetadata[ZodDecorator.IS_ROLE_GRANT] = true;
1480
+ break;
1408
1481
  case ZodDecorator.RAG_SOURCE: {
1409
1482
  // NORMALIZE HERE, not in the doors — the impersonalizeWith discipline. A bare `.ragSource()`
1410
1483
  // (the common case) stores `{}` rather than `true`/`undefined`, so every reader sees ONE
@@ -1478,6 +1551,17 @@ function applySingleDecorator(schema, decorator, params) {
1478
1551
  case ZodDecorator.OBJECT_BUSINESS_KEY_SET:
1479
1552
  currentMetadata[ZodDecorator.OBJECT_BUSINESS_KEY_SET] = p;
1480
1553
  break;
1554
+ case ZodDecorator.OBJECT_COMPOUND_INDEX: {
1555
+ // ACCUMULATES: each call declares one more index. A fresh array, never a push, so the schema this one was
1556
+ // derived from keeps its own list (decorators are builders, #1308). The same field list twice is one index.
1557
+ const existing = (currentMetadata[ZodDecorator.OBJECT_COMPOUND_INDEX] ?? []);
1558
+ const declared = p;
1559
+ const key = declared.fields.join('\u0000');
1560
+ currentMetadata[ZodDecorator.OBJECT_COMPOUND_INDEX] = existing.some((index) => index.fields.join('\u0000') === key)
1561
+ ? existing
1562
+ : [...existing, { fields: [...declared.fields] }];
1563
+ break;
1564
+ }
1481
1565
  case ZodDecorator.RESOURCE_REFERENCE:
1482
1566
  currentMetadata[ZodDecorator.RESOURCE_REFERENCE] = p;
1483
1567
  break;
@@ -2042,16 +2126,86 @@ function wrapMethodToPreserveMetadata(originalMethod, methodName) {
2042
2126
  * moves methods back onto prototypes — at which point the guard below stops being theoretical, since
2043
2127
  * `ZodString.prototype` is reached by both the STEP 1 pass and `installStringDecoratorSurface`.
2044
2128
  * Do NOT cite this function as the reason a decorator survives a chain; it is not.
2129
+ *
2130
+ * ⚠️ zod@4.6 DID move them (2026-11-09), as binding ACCESSORS installed lazily on the first instance. So
2131
+ * this function is now live whenever a schema was built before this module ran, and inert otherwise
2132
+ * (zod's own install then lands after it). It reads and writes through `readPrototypeMethod` /
2133
+ * `installBoundPrototypeMethod`, because a plain `prototype[name]` read binds the method to the
2134
+ * PROTOTYPE — see `readPrototypeMethod` for what that broke.
2045
2135
  */
2046
2136
  function patchPrototypeMethodsForMetadataPreservation(prototype, methodNames) {
2047
2137
  for (const methodName of methodNames) {
2048
- const originalMethod = prototype[methodName];
2138
+ const originalMethod = readPrototypeMethod(prototype, methodName);
2049
2139
  if (typeof originalMethod !== 'function')
2050
2140
  continue;
2051
2141
  if (originalMethod.__prototypeMetadataWrapped)
2052
2142
  continue;
2053
- prototype[methodName] = wrapMethodToPreserveMetadata(originalMethod, methodName);
2143
+ installBoundPrototypeMethod(prototype, methodName, wrapMethodToPreserveMetadata(originalMethod, methodName));
2144
+ }
2145
+ }
2146
+ /**
2147
+ * Reads a schema method off a PROTOTYPE without binding it to the prototype.
2148
+ *
2149
+ * zod 4.6 moved schema methods onto prototypes, as ACCESSORS: a trait's members are installed lazily on the
2150
+ * constructor's prototype when its first instance is built (`util.members` → `defineBound`), and the getter binds the
2151
+ * method to its receiver and memoizes it there — `own(this, key, fn.bind(this))`. So a plain `prototype[name]` runs
2152
+ * that getter with the PROTOTYPE as `this` and permanently shadows the prototype with a method bound to itself. Every
2153
+ * schema then inherited a `refine` whose `this` was the prototype, and zod's `check` read `this.def` off it: measured
2154
+ * 2026-11-09 under vitest as `Cannot read properties of undefined (reading 'checks')` at `z.string().refine(…)`, which
2155
+ * failed 13 suites of `saas-specifications` at import. It reproduced only when a schema had been built before this
2156
+ * module ran (so the members were already installed), which is why `zod-decorators`' own suite stayed green.
2157
+ *
2158
+ * zod's getter answers the RAW method for a nullish receiver ("vitest's spyOn calls a prototype getter bare"), which is
2159
+ * the read this needs. A data property (zod ≤ 4.3, or our own decorator) is returned as it is.
2160
+ */
2161
+ function readPrototypeMethod(prototype, methodName) {
2162
+ for (let at = prototype; at && at !== Object.prototype; at = Object.getPrototypeOf(at)) {
2163
+ const descriptor = Object.getOwnPropertyDescriptor(at, methodName);
2164
+ if (!descriptor)
2165
+ continue;
2166
+ if ('value' in descriptor)
2167
+ return descriptor.value;
2168
+ if (!descriptor.get)
2169
+ return undefined;
2170
+ try {
2171
+ return descriptor.get.call(undefined);
2172
+ }
2173
+ catch {
2174
+ // A getter that derives a value from its instance is not a method; there is nothing to wrap.
2175
+ return undefined;
2176
+ }
2054
2177
  }
2178
+ return undefined;
2179
+ }
2180
+ /**
2181
+ * Installs a method on a prototype with zod 4.6's own member semantics: bound to the instance on first read and
2182
+ * memoized there, so a detached member (`const opt = schema.optional; opt()`) keeps working as it does for zod's own,
2183
+ * and assignment shadows on the instance.
2184
+ *
2185
+ * Only a receiver that INHERITS from `prototype` is an instance read. Every other receiver gets the unbound method and
2186
+ * nothing is memoized, which is what zod's own getter answers for a nullish one. The test is deliberately not
2187
+ * `this == null`: in sloppy-mode code a getter called with an `undefined` receiver sees `globalThis`, and this module
2188
+ * runs sloppy whenever tsx transforms it to CommonJS (every `wildo.saas.config.ts` imported through tsx — see
2189
+ * `prototype-member-binding.zod46.test.ts`). Measured 2026-11-09: `readPrototypeMethod`'s bare read then memoized
2190
+ * eleven zod methods on `globalThis` and returned a copy bound to it without the wrap marker, the next patch pass wrapped
2191
+ * that copy, and `z.string().refine(…)` threw `this.check is not a function` while `@wildo-ai/zod-decorators` loaded.
2192
+ * The same predicate keeps a plain `prototype[name]` read from binding the method to the prototype itself.
2193
+ */
2194
+ function installBoundPrototypeMethod(prototype, methodName, method) {
2195
+ Object.defineProperty(prototype, methodName, {
2196
+ configurable: true,
2197
+ enumerable: false,
2198
+ get() {
2199
+ if (!Object.prototype.isPrototypeOf.call(prototype, this))
2200
+ return method;
2201
+ const bound = method.bind(this);
2202
+ Object.defineProperty(this, methodName, { configurable: true, enumerable: true, writable: true, value: bound });
2203
+ return bound;
2204
+ },
2205
+ set(value) {
2206
+ Object.defineProperty(this, methodName, { configurable: true, enumerable: true, writable: true, value });
2207
+ },
2208
+ });
2055
2209
  }
2056
2210
  /**
2057
2211
  * Install the WHOLE string decorator surface on one string-backed prototype.
@@ -2063,8 +2217,9 @@ function patchPrototypeMethodsForMetadataPreservation(prototype, methodNames) {
2063
2217
  * the method while the other is not.
2064
2218
  *
2065
2219
  * Also calls the metadata-preservation patch, matching what each of the three install sites did
2066
- * before. Note that this call is INERT on zod@4.3.6 — see that function's own docblock; schema
2067
- * methods live on instances, and `addChainableMethods` is what preserves metadata through a chain.
2220
+ * before. Note that this call was INERT on zod@4.3.6 and is live on 4.6 only when a schema was built
2221
+ * first — see that function's own docblock; `addChainableMethods` is what preserves metadata through a
2222
+ * chain.
2068
2223
  * It is passed through rather than dropped so the two stay coupled if Zod's method placement changes.
2069
2224
  *
2070
2225
  * @param prototype - a Zod string-schema prototype (`ZodString.prototype`, `ZodUUID.prototype`, …)
@@ -2173,6 +2328,7 @@ export function ensureZodDecoratorsLoaded(zodInstance = z) {
2173
2328
  zodInstance.ZodNumber.prototype[ZodDecorator.IS_AUDIT_EVIDENCE] = ZodDecorator_FunctionType[ZodDecorator.IS_AUDIT_EVIDENCE];
2174
2329
  zodInstance.ZodNumber.prototype[ZodDecorator.IS_LAST_ACTION_RECORD] = ZodDecorator_FunctionType[ZodDecorator.IS_LAST_ACTION_RECORD];
2175
2330
  zodInstance.ZodNumber.prototype[ZodDecorator.IS_DECIDER] = ZodDecorator_FunctionType[ZodDecorator.IS_DECIDER];
2331
+ zodInstance.ZodNumber.prototype[ZodDecorator.IS_ROLE_GRANT] = ZodDecorator_FunctionType[ZodDecorator.IS_ROLE_GRANT];
2176
2332
  zodInstance.ZodNumber.prototype[ZodDecorator.IS_VIRTUAL] = ZodDecorator_FunctionType[ZodDecorator.IS_VIRTUAL];
2177
2333
  zodInstance.ZodNumber.prototype[ZodDecorator.IS_DISCRIMINATOR] = ZodDecorator_FunctionType[ZodDecorator.IS_DISCRIMINATOR];
2178
2334
  zodInstance.ZodNumber.prototype[ZodDecorator.EXCLUDE_FROM_CREATE] = ZodDecorator_FunctionType[ZodDecorator.EXCLUDE_FROM_CREATE];
@@ -2220,6 +2376,7 @@ export function ensureZodDecoratorsLoaded(zodInstance = z) {
2220
2376
  zodInstance.ZodBigInt.prototype[ZodDecorator.IS_AUDIT_EVIDENCE] = ZodDecorator_FunctionType[ZodDecorator.IS_AUDIT_EVIDENCE];
2221
2377
  zodInstance.ZodBigInt.prototype[ZodDecorator.IS_LAST_ACTION_RECORD] = ZodDecorator_FunctionType[ZodDecorator.IS_LAST_ACTION_RECORD];
2222
2378
  zodInstance.ZodBigInt.prototype[ZodDecorator.IS_DECIDER] = ZodDecorator_FunctionType[ZodDecorator.IS_DECIDER];
2379
+ zodInstance.ZodBigInt.prototype[ZodDecorator.IS_ROLE_GRANT] = ZodDecorator_FunctionType[ZodDecorator.IS_ROLE_GRANT];
2223
2380
  zodInstance.ZodBigInt.prototype[ZodDecorator.IS_VIRTUAL] = ZodDecorator_FunctionType[ZodDecorator.IS_VIRTUAL];
2224
2381
  zodInstance.ZodBigInt.prototype[ZodDecorator.EXCLUDE_FROM_CREATE] = ZodDecorator_FunctionType[ZodDecorator.EXCLUDE_FROM_CREATE];
2225
2382
  zodInstance.ZodBigInt.prototype[ZodDecorator.EXCLUDE_FROM_UPDATE] = ZodDecorator_FunctionType[ZodDecorator.EXCLUDE_FROM_UPDATE];
@@ -2243,6 +2400,7 @@ export function ensureZodDecoratorsLoaded(zodInstance = z) {
2243
2400
  zodInstance.ZodBoolean.prototype[ZodDecorator.IS_AUDIT_EVIDENCE] = ZodDecorator_FunctionType[ZodDecorator.IS_AUDIT_EVIDENCE];
2244
2401
  zodInstance.ZodBoolean.prototype[ZodDecorator.IS_LAST_ACTION_RECORD] = ZodDecorator_FunctionType[ZodDecorator.IS_LAST_ACTION_RECORD];
2245
2402
  zodInstance.ZodBoolean.prototype[ZodDecorator.IS_DECIDER] = ZodDecorator_FunctionType[ZodDecorator.IS_DECIDER];
2403
+ zodInstance.ZodBoolean.prototype[ZodDecorator.IS_ROLE_GRANT] = ZodDecorator_FunctionType[ZodDecorator.IS_ROLE_GRANT];
2246
2404
  zodInstance.ZodBoolean.prototype[ZodDecorator.IS_VIRTUAL] = ZodDecorator_FunctionType[ZodDecorator.IS_VIRTUAL];
2247
2405
  zodInstance.ZodBoolean.prototype[ZodDecorator.EXCLUDE_FROM_CREATE] = ZodDecorator_FunctionType[ZodDecorator.EXCLUDE_FROM_CREATE];
2248
2406
  zodInstance.ZodBoolean.prototype[ZodDecorator.EXCLUDE_FROM_UPDATE] = ZodDecorator_FunctionType[ZodDecorator.EXCLUDE_FROM_UPDATE];
@@ -2273,6 +2431,7 @@ export function ensureZodDecoratorsLoaded(zodInstance = z) {
2273
2431
  zodInstance.ZodDate.prototype[ZodDecorator.IS_AUDIT_EVIDENCE] = ZodDecorator_FunctionType[ZodDecorator.IS_AUDIT_EVIDENCE];
2274
2432
  zodInstance.ZodDate.prototype[ZodDecorator.IS_LAST_ACTION_RECORD] = ZodDecorator_FunctionType[ZodDecorator.IS_LAST_ACTION_RECORD];
2275
2433
  zodInstance.ZodDate.prototype[ZodDecorator.IS_DECIDER] = ZodDecorator_FunctionType[ZodDecorator.IS_DECIDER];
2434
+ zodInstance.ZodDate.prototype[ZodDecorator.IS_ROLE_GRANT] = ZodDecorator_FunctionType[ZodDecorator.IS_ROLE_GRANT];
2276
2435
  zodInstance.ZodDate.prototype[ZodDecorator.IS_VIRTUAL] = ZodDecorator_FunctionType[ZodDecorator.IS_VIRTUAL];
2277
2436
  zodInstance.ZodDate.prototype[ZodDecorator.EXCLUDE_FROM_CREATE] = ZodDecorator_FunctionType[ZodDecorator.EXCLUDE_FROM_CREATE];
2278
2437
  zodInstance.ZodDate.prototype[ZodDecorator.EXCLUDE_FROM_UPDATE] = ZodDecorator_FunctionType[ZodDecorator.EXCLUDE_FROM_UPDATE];
@@ -2310,6 +2469,7 @@ export function ensureZodDecoratorsLoaded(zodInstance = z) {
2310
2469
  zodInstance.ZodOptional.prototype[ZodDecorator.IS_AUDIT_EVIDENCE] = ZodDecorator_FunctionType[ZodDecorator.IS_AUDIT_EVIDENCE];
2311
2470
  zodInstance.ZodOptional.prototype[ZodDecorator.IS_LAST_ACTION_RECORD] = ZodDecorator_FunctionType[ZodDecorator.IS_LAST_ACTION_RECORD];
2312
2471
  zodInstance.ZodOptional.prototype[ZodDecorator.IS_DECIDER] = ZodDecorator_FunctionType[ZodDecorator.IS_DECIDER];
2472
+ zodInstance.ZodOptional.prototype[ZodDecorator.IS_ROLE_GRANT] = ZodDecorator_FunctionType[ZodDecorator.IS_ROLE_GRANT];
2313
2473
  // RAG source — ZodOptional is the ONE wrapper with a hand-enumerated block (its siblings get every
2314
2474
  // FunctionType entry from the blanket wrapper loop below), so this line is what keeps
2315
2475
  // `z.string().optional().ragSource()` from being the order-dependent half-live trap the
@@ -2402,6 +2562,7 @@ export function ensureZodDecoratorsLoaded(zodInstance = z) {
2402
2562
  zodInstance.ZodEnum.prototype[ZodDecorator.IS_AUDIT_EVIDENCE] = ZodDecorator_FunctionType[ZodDecorator.IS_AUDIT_EVIDENCE];
2403
2563
  zodInstance.ZodEnum.prototype[ZodDecorator.IS_LAST_ACTION_RECORD] = ZodDecorator_FunctionType[ZodDecorator.IS_LAST_ACTION_RECORD];
2404
2564
  zodInstance.ZodEnum.prototype[ZodDecorator.IS_DECIDER] = ZodDecorator_FunctionType[ZodDecorator.IS_DECIDER];
2565
+ zodInstance.ZodEnum.prototype[ZodDecorator.IS_ROLE_GRANT] = ZodDecorator_FunctionType[ZodDecorator.IS_ROLE_GRANT];
2405
2566
  zodInstance.ZodEnum.prototype[ZodDecorator.IS_VIRTUAL] = ZodDecorator_FunctionType[ZodDecorator.IS_VIRTUAL];
2406
2567
  zodInstance.ZodEnum.prototype[ZodDecorator.IS_DISCRIMINATOR] = ZodDecorator_FunctionType[ZodDecorator.IS_DISCRIMINATOR];
2407
2568
  zodInstance.ZodEnum.prototype[ZodDecorator.EXCLUDE_FROM_CREATE] = ZodDecorator_FunctionType[ZodDecorator.EXCLUDE_FROM_CREATE];
@@ -2438,6 +2599,7 @@ export function ensureZodDecoratorsLoaded(zodInstance = z) {
2438
2599
  zodInstance.ZodArray.prototype[ZodDecorator.IS_AUDIT_EVIDENCE] = ZodDecorator_FunctionType[ZodDecorator.IS_AUDIT_EVIDENCE];
2439
2600
  zodInstance.ZodArray.prototype[ZodDecorator.IS_LAST_ACTION_RECORD] = ZodDecorator_FunctionType[ZodDecorator.IS_LAST_ACTION_RECORD];
2440
2601
  zodInstance.ZodArray.prototype[ZodDecorator.IS_DECIDER] = ZodDecorator_FunctionType[ZodDecorator.IS_DECIDER];
2602
+ zodInstance.ZodArray.prototype[ZodDecorator.IS_ROLE_GRANT] = ZodDecorator_FunctionType[ZodDecorator.IS_ROLE_GRANT];
2441
2603
  zodInstance.ZodArray.prototype[ZodDecorator.IS_VIRTUAL] = ZodDecorator_FunctionType[ZodDecorator.IS_VIRTUAL];
2442
2604
  zodInstance.ZodArray.prototype[ZodDecorator.EXCLUDE_FROM_CREATE] = ZodDecorator_FunctionType[ZodDecorator.EXCLUDE_FROM_CREATE];
2443
2605
  zodInstance.ZodArray.prototype[ZodDecorator.EXCLUDE_FROM_UPDATE] = ZodDecorator_FunctionType[ZodDecorator.EXCLUDE_FROM_UPDATE];
@@ -2473,10 +2635,13 @@ export function ensureZodDecoratorsLoaded(zodInstance = z) {
2473
2635
  * before the object is wrapped (`WorkUnitRefSchema.optional()`), and read through any wrapper. `ZodOptional`,
2474
2636
  * whose list is written by hand, does not carry it either.
2475
2637
  *
2638
+ * `compoundIndex` (#3142) is excluded for the same reason: it names fields of the OBJECT it decorates, and an index
2639
+ * belongs to the stored row, whose schema is a plain object. It is read from the top-level object only.
2640
+ *
2476
2641
  * Keep this a SET with a reason per member, never a silent condition in the loop body. An excluded
2477
2642
  * decorator is a decision; a missing one is a bug, and the two must not look alike.
2478
2643
  */
2479
- const WRAPPER_INSTALL_EXCLUSIONS = new Set([ZodDecorator.IS_PRIMARY_KEY, ZodDecorator.DOCUMENT_SEQUENCE, ZodDecorator.RESOURCE_REFERENCE]);
2644
+ const WRAPPER_INSTALL_EXCLUSIONS = new Set([ZodDecorator.IS_PRIMARY_KEY, ZodDecorator.DOCUMENT_SEQUENCE, ZodDecorator.RESOURCE_REFERENCE, ZodDecorator.OBJECT_COMPOUND_INDEX]);
2480
2645
  // Wrapper types (ZodDefault, ZodNullable) need ALL decorators for chaining
2481
2646
  // e.g. z.date().default(...).excludeFromCreate().isNotEditable().showWhen(...)
2482
2647
  //
@@ -2514,6 +2679,7 @@ export function ensureZodDecoratorsLoaded(zodInstance = z) {
2514
2679
  zi.ZodUnion.prototype[ZodDecorator.IS_AUDIT_EVIDENCE] = ZodDecorator_FunctionType[ZodDecorator.IS_AUDIT_EVIDENCE];
2515
2680
  zi.ZodUnion.prototype[ZodDecorator.IS_LAST_ACTION_RECORD] = ZodDecorator_FunctionType[ZodDecorator.IS_LAST_ACTION_RECORD];
2516
2681
  zi.ZodUnion.prototype[ZodDecorator.IS_DECIDER] = ZodDecorator_FunctionType[ZodDecorator.IS_DECIDER];
2682
+ zi.ZodUnion.prototype[ZodDecorator.IS_ROLE_GRANT] = ZodDecorator_FunctionType[ZodDecorator.IS_ROLE_GRANT];
2517
2683
  zi.ZodUnion.prototype[ZodDecorator.IS_VIRTUAL] = ZodDecorator_FunctionType[ZodDecorator.IS_VIRTUAL];
2518
2684
  zi.ZodUnion.prototype[ZodDecorator.IS_DISCRIMINATOR] = ZodDecorator_FunctionType[ZodDecorator.IS_DISCRIMINATOR];
2519
2685
  zi.ZodUnion.prototype[ZodDecorator.EXCLUDE_FROM_CREATE] = ZodDecorator_FunctionType[ZodDecorator.EXCLUDE_FROM_CREATE];
@@ -2536,6 +2702,7 @@ export function ensureZodDecoratorsLoaded(zodInstance = z) {
2536
2702
  zi.ZodObject.prototype[ZodDecorator.IS_AUDIT_EVIDENCE] = ZodDecorator_FunctionType[ZodDecorator.IS_AUDIT_EVIDENCE];
2537
2703
  zi.ZodObject.prototype[ZodDecorator.IS_LAST_ACTION_RECORD] = ZodDecorator_FunctionType[ZodDecorator.IS_LAST_ACTION_RECORD];
2538
2704
  zi.ZodObject.prototype[ZodDecorator.IS_DECIDER] = ZodDecorator_FunctionType[ZodDecorator.IS_DECIDER];
2705
+ zi.ZodObject.prototype[ZodDecorator.IS_ROLE_GRANT] = ZodDecorator_FunctionType[ZodDecorator.IS_ROLE_GRANT];
2539
2706
  zi.ZodObject.prototype[ZodDecorator.IS_VIRTUAL] = ZodDecorator_FunctionType[ZodDecorator.IS_VIRTUAL];
2540
2707
  zi.ZodObject.prototype[ZodDecorator.EXCLUDE_FROM_CREATE] = ZodDecorator_FunctionType[ZodDecorator.EXCLUDE_FROM_CREATE];
2541
2708
  zi.ZodObject.prototype[ZodDecorator.EXCLUDE_FROM_UPDATE] = ZodDecorator_FunctionType[ZodDecorator.EXCLUDE_FROM_UPDATE];
@@ -2543,6 +2710,7 @@ export function ensureZodDecoratorsLoaded(zodInstance = z) {
2543
2710
  zi.ZodObject.prototype[ZodDecorator.IS_CRDT] = ZodDecorator_FunctionType[ZodDecorator.IS_CRDT];
2544
2711
  // Composite business key (data-seeding subsystem)
2545
2712
  zi.ZodObject.prototype[ZodDecorator.OBJECT_BUSINESS_KEY_SET] = ZodDecorator_FunctionType[ZodDecorator.OBJECT_BUSINESS_KEY_SET];
2713
+ zi.ZodObject.prototype[ZodDecorator.OBJECT_COMPOUND_INDEX] = ZodDecorator_FunctionType[ZodDecorator.OBJECT_COMPOUND_INDEX];
2546
2714
  zi.ZodObject.prototype[ZodDecorator.RESOURCE_REFERENCE] = ZodDecorator_FunctionType[ZodDecorator.RESOURCE_REFERENCE];
2547
2715
  // Generic form-field decorators (conditional visibility / draft relaxation).
2548
2716
  zi.ZodObject.prototype[ZodDecorator.SHOW_WHEN] = ZodDecorator_FunctionType[ZodDecorator.SHOW_WHEN];
@@ -2568,6 +2736,7 @@ export function ensureZodDecoratorsLoaded(zodInstance = z) {
2568
2736
  zi.ZodRecord.prototype[ZodDecorator.IS_AUDIT_EVIDENCE] = ZodDecorator_FunctionType[ZodDecorator.IS_AUDIT_EVIDENCE];
2569
2737
  zi.ZodRecord.prototype[ZodDecorator.IS_LAST_ACTION_RECORD] = ZodDecorator_FunctionType[ZodDecorator.IS_LAST_ACTION_RECORD];
2570
2738
  zi.ZodRecord.prototype[ZodDecorator.IS_DECIDER] = ZodDecorator_FunctionType[ZodDecorator.IS_DECIDER];
2739
+ zi.ZodRecord.prototype[ZodDecorator.IS_ROLE_GRANT] = ZodDecorator_FunctionType[ZodDecorator.IS_ROLE_GRANT];
2571
2740
  zi.ZodRecord.prototype[ZodDecorator.IS_VIRTUAL] = ZodDecorator_FunctionType[ZodDecorator.IS_VIRTUAL];
2572
2741
  zi.ZodRecord.prototype[ZodDecorator.EXCLUDE_FROM_CREATE] = ZodDecorator_FunctionType[ZodDecorator.EXCLUDE_FROM_CREATE];
2573
2742
  zi.ZodRecord.prototype[ZodDecorator.EXCLUDE_FROM_UPDATE] = ZodDecorator_FunctionType[ZodDecorator.EXCLUDE_FROM_UPDATE];
@@ -2598,6 +2767,7 @@ export function ensureZodDecoratorsLoaded(zodInstance = z) {
2598
2767
  zi.ZodMap.prototype[ZodDecorator.IS_AUDIT_EVIDENCE] = ZodDecorator_FunctionType[ZodDecorator.IS_AUDIT_EVIDENCE];
2599
2768
  zi.ZodMap.prototype[ZodDecorator.IS_LAST_ACTION_RECORD] = ZodDecorator_FunctionType[ZodDecorator.IS_LAST_ACTION_RECORD];
2600
2769
  zi.ZodMap.prototype[ZodDecorator.IS_DECIDER] = ZodDecorator_FunctionType[ZodDecorator.IS_DECIDER];
2770
+ zi.ZodMap.prototype[ZodDecorator.IS_ROLE_GRANT] = ZodDecorator_FunctionType[ZodDecorator.IS_ROLE_GRANT];
2601
2771
  zi.ZodMap.prototype[ZodDecorator.IS_VIRTUAL] = ZodDecorator_FunctionType[ZodDecorator.IS_VIRTUAL];
2602
2772
  zi.ZodMap.prototype[ZodDecorator.EXCLUDE_FROM_CREATE] = ZodDecorator_FunctionType[ZodDecorator.EXCLUDE_FROM_CREATE];
2603
2773
  zi.ZodMap.prototype[ZodDecorator.EXCLUDE_FROM_UPDATE] = ZodDecorator_FunctionType[ZodDecorator.EXCLUDE_FROM_UPDATE];