@warlock.js/seal 4.16.0 → 5.0.1

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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,13 @@ All notable changes to `@warlock.js/seal` are documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). `@warlock.js/*` packages are released in lockstep — every package shares the same version number, so a version below may list only the changes that affected this package.
6
6
 
7
+ ## 5.0.0 - 2026-08-25
8
+
9
+ ### Changed
10
+
11
+ - IP validation no longer imports Node's `net` module, so the same IPv4 and IPv6 rules can run in browser bundles.
12
+ - Optional validators now skip value rules only for absent values; present empty values such as `""` are validated instead of passing through with the wrong output type.
13
+
7
14
  ## 4.16.0 - 2026-08-18
8
15
 
9
16
  ### Security
package/cjs/index.cjs CHANGED
@@ -30,7 +30,6 @@ let _mongez_reinforcements = require("@mongez/reinforcements");
30
30
  let _mongez_supportive_is = require("@mongez/supportive-is");
31
31
  let dayjs = require("dayjs");
32
32
  dayjs = __toESM(dayjs, 1);
33
- let net = require("net");
34
33
 
35
34
  //#region ../seal/src/standard-schema/json-schema.ts
36
35
  /**
@@ -935,9 +934,10 @@ var BaseValidator = class {
935
934
  let isValid = true;
936
935
  const isFirstErrorOnly = context.configurations?.firstErrorOnly ?? true;
937
936
  const isEmpty = isEmptyValue(valueForRules);
937
+ const skipEmptyRules = this.isOptional ? valueForRules === void 0 : isEmpty;
938
938
  const rulesToRun = this.requiredRule ? [this.requiredRule, ...this.rules] : this.rules;
939
939
  for (const rule of rulesToRun) {
940
- if ((rule.requiresValue ?? true) && isEmpty) continue;
940
+ if ((rule.requiresValue ?? true) && skipEmptyRules) continue;
941
941
  this.setRuleAttributesList(rule);
942
942
  const result = await rule.validate(mutatedData, context);
943
943
  if (result.isValid === false) {
@@ -1769,13 +1769,38 @@ const nanoidRule = {
1769
1769
  //#endregion
1770
1770
  //#region ../seal/src/rules/string/ip.ts
1771
1771
  /**
1772
+ * Pure, dependency-free re-implementation of Node's `net.isIP`/`isIPv4`/`isIPv6`.
1773
+ * Mirrors the exact regex Node uses internally (lib/internal/net.js) so that
1774
+ * behavior stays identical while remaining runnable in the browser (no `net` import).
1775
+ */
1776
+ const v4Seg = "(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])";
1777
+ const v4Str = `(${v4Seg}[.]){3}${v4Seg}`;
1778
+ const IPv4Reg = new RegExp(`^${v4Str}$`);
1779
+ const v6Seg = "(?:[0-9a-fA-F]{1,4})";
1780
+ const IPv6Reg = new RegExp(`^((?:${v6Seg}:){7}(?:${v6Seg}|:)|(?:${v6Seg}:){6}(?:${v4Str}|:${v6Seg}|:)|(?:${v6Seg}:){5}(?::${v4Str}|(:${v6Seg}){1,2}|:)|(?:${v6Seg}:){4}(?:(:${v6Seg}){0,1}:${v4Str}|(:${v6Seg}){1,3}|:)|(?:${v6Seg}:){3}(?:(:${v6Seg}){0,2}:${v4Str}|(:${v6Seg}){1,4}|:)|(?:${v6Seg}:){2}(?:(:${v6Seg}){0,3}:${v4Str}|(:${v6Seg}){1,5}|:)|(?:${v6Seg}:){1}(?:(:${v6Seg}){0,4}:${v4Str}|(:${v6Seg}){1,6}|:)|(?::((?::${v6Seg}){0,5}:${v4Str}|(?::${v6Seg}){1,7}|:)))(%[0-9a-zA-Z-.:]{1,})?\$`);
1781
+ function isIPv4(value) {
1782
+ return IPv4Reg.test(value);
1783
+ }
1784
+ function isIPv6(value) {
1785
+ return IPv6Reg.test(value);
1786
+ }
1787
+ /**
1788
+ * Returns 4 or 6 when `value` is a valid IPv4/IPv6 address, otherwise 0.
1789
+ * Signature mirrors Node's `net.isIP` for drop-in behavior parity.
1790
+ */
1791
+ function isIP(value) {
1792
+ if (isIPv4(value)) return 4;
1793
+ if (isIPv6(value)) return 6;
1794
+ return 0;
1795
+ }
1796
+ /**
1772
1797
  * IP rule - validates IP address (v4 or v6)
1773
1798
  */
1774
1799
  const ipRule = {
1775
1800
  name: "ip",
1776
1801
  defaultErrorMessage: "The :input must be a valid IP address",
1777
1802
  async validate(value, context) {
1778
- if ((0, net.isIP)(value)) return VALID_RULE;
1803
+ if (isIP(value)) return VALID_RULE;
1779
1804
  return invalidRule(this, context);
1780
1805
  }
1781
1806
  };
@@ -1786,7 +1811,7 @@ const ip4Rule = {
1786
1811
  name: "ip4",
1787
1812
  defaultErrorMessage: "The :input must be a valid IPv4 address",
1788
1813
  async validate(value, context) {
1789
- if ((0, net.isIP)(value) === 4) return VALID_RULE;
1814
+ if (isIP(value) === 4) return VALID_RULE;
1790
1815
  return invalidRule(this, context);
1791
1816
  }
1792
1817
  };
@@ -1797,7 +1822,7 @@ const ip6Rule = {
1797
1822
  name: "ip6",
1798
1823
  defaultErrorMessage: "The :input must be a valid IPv6 address",
1799
1824
  async validate(value, context) {
1800
- if ((0, net.isIP)(value) === 6) return VALID_RULE;
1825
+ if (isIP(value) === 6) return VALID_RULE;
1801
1826
  return invalidRule(this, context);
1802
1827
  }
1803
1828
  };
@@ -8811,6 +8836,9 @@ exports.ip6Rule = ip6Rule;
8811
8836
  exports.ipRule = ipRule;
8812
8837
  exports.isCreditCardRule = isCreditCardRule;
8813
8838
  exports.isDateValue = isDateValue;
8839
+ exports.isIP = isIP;
8840
+ exports.isIPv4 = isIPv4;
8841
+ exports.isIPv6 = isIPv6;
8814
8842
  exports.isNumericRule = isNumericRule;
8815
8843
  exports.jsonMutator = jsonMutator;
8816
8844
  exports.kebabCaseMutator = kebabCaseMutator;