@plasius/schema 1.4.1 → 1.4.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.
@@ -1570,45 +1570,113 @@ function getShape(def) {
1570
1570
  var MAX_STRICT_VALIDATION_NODES = 1e4;
1571
1571
  var MAX_STRICT_VALIDATION_DEPTH = 256;
1572
1572
  var MAX_STRICT_VALIDATION_OBJECTS = MAX_STRICT_VALIDATION_NODES;
1573
- function strictInputIsWithinComplexityLimit(input) {
1574
- const pending = [
1575
- { value: input, depth: 0 }
1576
- ];
1573
+ function snapshotStrictInput(input) {
1574
+ const snapshot = Array.isArray(input) ? [] : {};
1575
+ const pending = [{ source: input, target: snapshot, depth: 0 }];
1577
1576
  const seen = /* @__PURE__ */ new WeakSet();
1578
- let visitedNodes = 0;
1577
+ let visitedNodes = 1;
1579
1578
  try {
1580
1579
  while (pending.length > 0) {
1581
1580
  const current = pending.pop();
1582
1581
  if (!current) {
1583
1582
  continue;
1584
1583
  }
1585
- visitedNodes += 1;
1586
1584
  if (visitedNodes > MAX_STRICT_VALIDATION_NODES || current.depth > MAX_STRICT_VALIDATION_DEPTH) {
1587
- return false;
1585
+ return { valid: false };
1588
1586
  }
1589
- if (typeof current.value !== "object" || current.value === null) {
1590
- continue;
1587
+ if (seen.has(current.source)) {
1588
+ return { valid: false };
1589
+ }
1590
+ seen.add(current.source);
1591
+ const isArray = Array.isArray(current.source);
1592
+ const prototype = Object.getPrototypeOf(current.source);
1593
+ if (isArray && prototype !== Array.prototype || !isArray && prototype !== Object.prototype && prototype !== null) {
1594
+ return { valid: false };
1595
+ }
1596
+ const ownKeys = Reflect.ownKeys(current.source);
1597
+ if (visitedNodes + ownKeys.length > MAX_STRICT_VALIDATION_NODES) {
1598
+ return { valid: false };
1591
1599
  }
1592
- if (seen.has(current.value)) {
1593
- return false;
1600
+ const descriptors = /* @__PURE__ */ new Map();
1601
+ for (const key of ownKeys) {
1602
+ const descriptor = Object.getOwnPropertyDescriptor(
1603
+ current.source,
1604
+ key
1605
+ );
1606
+ if (descriptor === void 0) {
1607
+ return { valid: false };
1608
+ }
1609
+ descriptors.set(key, descriptor);
1594
1610
  }
1595
- seen.add(current.value);
1596
- const keys = Object.keys(current.value);
1597
- if (visitedNodes + pending.length + keys.length > MAX_STRICT_VALIDATION_NODES) {
1598
- return false;
1611
+ if (isArray) {
1612
+ const lengthDescriptor = descriptors.get("length");
1613
+ if (lengthDescriptor === void 0 || !("value" in lengthDescriptor) || !Number.isSafeInteger(lengthDescriptor.value) || lengthDescriptor.value < 0 || lengthDescriptor.value > MAX_STRICT_VALIDATION_NODES) {
1614
+ return { valid: false };
1615
+ }
1616
+ let elementCount = 0;
1617
+ for (const key of ownKeys) {
1618
+ if (key === "length") {
1619
+ continue;
1620
+ }
1621
+ if (typeof key !== "string" || !/^(?:0|[1-9]\d*)$/.test(key)) {
1622
+ return { valid: false };
1623
+ }
1624
+ const descriptor = descriptors.get(key);
1625
+ if (descriptor === void 0 || descriptor.enumerable !== true || Number(key) >= lengthDescriptor.value) {
1626
+ return { valid: false };
1627
+ }
1628
+ elementCount += 1;
1629
+ }
1630
+ if (elementCount !== lengthDescriptor.value) {
1631
+ return { valid: false };
1632
+ }
1599
1633
  }
1600
- const record = current.value;
1634
+ visitedNodes += ownKeys.length;
1635
+ const keys = ownKeys.filter(
1636
+ (key) => descriptors.get(key)?.enumerable
1637
+ );
1601
1638
  for (const key of keys) {
1602
- pending.push({
1603
- value: record[key],
1604
- depth: current.depth + 1
1639
+ if (typeof key !== "string") {
1640
+ return { valid: false };
1641
+ }
1642
+ if (isArray && !/^(?:0|[1-9]\d*)$/.test(key)) {
1643
+ return { valid: false };
1644
+ }
1645
+ const descriptor = descriptors.get(key);
1646
+ if (descriptor === void 0 || !("value" in descriptor) || descriptor.get !== void 0 || descriptor.set !== void 0) {
1647
+ return { valid: false };
1648
+ }
1649
+ const child = descriptor.value;
1650
+ if (typeof child === "function") {
1651
+ return { valid: false };
1652
+ }
1653
+ if (typeof child === "object" && child !== null) {
1654
+ const childSnapshot = Array.isArray(child) ? [] : {};
1655
+ Object.defineProperty(current.target, key, {
1656
+ value: childSnapshot,
1657
+ enumerable: true,
1658
+ configurable: true,
1659
+ writable: true
1660
+ });
1661
+ pending.push({
1662
+ source: child,
1663
+ target: childSnapshot,
1664
+ depth: current.depth + 1
1665
+ });
1666
+ continue;
1667
+ }
1668
+ Object.defineProperty(current.target, key, {
1669
+ value: child,
1670
+ enumerable: true,
1671
+ configurable: true,
1672
+ writable: true
1605
1673
  });
1606
1674
  }
1607
1675
  }
1608
1676
  } catch {
1609
- return false;
1677
+ return { valid: false };
1610
1678
  }
1611
- return true;
1679
+ return { valid: true, value: snapshot };
1612
1680
  }
1613
1681
  function strictReferenceShape(def) {
1614
1682
  return {
@@ -2175,8 +2243,10 @@ function createSchema(_shape, entityType, options = {
2175
2243
  if (typeof input !== "object" || input === null) {
2176
2244
  return { valid: false, errors: ["Input must be an object"] };
2177
2245
  }
2246
+ let strictInputSnapshot;
2178
2247
  if (options.unknownFields === "reject") {
2179
- if (!strictInputIsWithinComplexityLimit(input)) {
2248
+ const snapshot = snapshotStrictInput(input);
2249
+ if (!snapshot.valid) {
2180
2250
  return {
2181
2251
  valid: false,
2182
2252
  errors: ["Strict validation complexity limit exceeded."],
@@ -2189,16 +2259,32 @@ function createSchema(_shape, entityType, options = {
2189
2259
  ]
2190
2260
  };
2191
2261
  }
2262
+ strictInputSnapshot = snapshot.value;
2192
2263
  const scanState = {
2193
2264
  remainingObjects: MAX_STRICT_VALIDATION_OBJECTS,
2194
2265
  limitExceeded: false
2195
2266
  };
2196
- const locations = unknownFieldLocations(
2197
- input,
2198
- schema._shape,
2199
- "root",
2200
- scanState
2201
- );
2267
+ let locations;
2268
+ try {
2269
+ locations = unknownFieldLocations(
2270
+ strictInputSnapshot,
2271
+ schema._shape,
2272
+ "root",
2273
+ scanState
2274
+ );
2275
+ } catch {
2276
+ return {
2277
+ valid: false,
2278
+ errors: ["Strict validation complexity limit exceeded."],
2279
+ issues: [
2280
+ {
2281
+ path: "root",
2282
+ code: "validation_complexity_limit",
2283
+ message: "Strict validation complexity limit exceeded."
2284
+ }
2285
+ ]
2286
+ };
2287
+ }
2202
2288
  if (scanState.limitExceeded) {
2203
2289
  return {
2204
2290
  valid: false,
@@ -2226,7 +2312,23 @@ function createSchema(_shape, entityType, options = {
2226
2312
  };
2227
2313
  }
2228
2314
  }
2229
- const working = typeof input === "object" && input !== null ? deepClone(input) : { ...input };
2315
+ let working;
2316
+ try {
2317
+ working = strictInputSnapshot ?? (typeof input === "object" && input !== null ? deepClone(input) : { ...input });
2318
+ } catch {
2319
+ return {
2320
+ valid: false,
2321
+ errors: ["Input could not be safely cloned."],
2322
+ issues: [
2323
+ {
2324
+ path: "root",
2325
+ code: "unsafe_input",
2326
+ message: "Input could not be safely cloned."
2327
+ }
2328
+ ]
2329
+ };
2330
+ }
2331
+ const providedFieldNames = new Set(Object.keys(working));
2230
2332
  if (working.type == null) working.type = entityType;
2231
2333
  if (working.version == null) working.version = version;
2232
2334
  const fromVersion = String(working.version ?? "0.0.0");
@@ -2343,9 +2445,8 @@ function createSchema(_shape, entityType, options = {
2343
2445
  }
2344
2446
  if (errors.length === 0 && options.schemaValidator) {
2345
2447
  const castValue = result;
2346
- const source = input;
2347
2448
  const validationContext = Object.freeze({
2348
- wasProvided: (fieldName) => Object.prototype.hasOwnProperty.call(source, fieldName)
2449
+ wasProvided: (fieldName) => providedFieldNames.has(fieldName)
2349
2450
  });
2350
2451
  if (!options.schemaValidator(castValue, validationContext)) {
2351
2452
  errors.push("Schema-level validation failed.");