@nullix/zod-mongoose-studio 3.3.0 → 3.3.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.
Files changed (118) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/_fonts/57NSSoFy1VLVs2gqly8Ls9awBnZMFyXGrefpmqvdqmc-zJfbBtpgM4cDmcXBsqZNW79_kFnlpPd62b48glgdydA.woff2 +0 -0
  3. package/.output/public/_fonts/8VR2wSMN-3U4NbWAVYXlkRV6hA0jFBXP-0RtL3X7fko-x2gYI4qfmkRdxyQQUPaBZdZdgl1TeVrquF_TxHeM4lM.woff2 +0 -0
  4. package/.output/public/_fonts/GsKUclqeNLJ96g5AU593ug6yanivOiwjW_7zESNPChw-jHA4tBeM1bjF7LATGUpfBuSTyomIFrWBTzjF7txVYfg.woff2 +0 -0
  5. package/.output/public/_fonts/Ld1FnTo3yTIwDyGfTQ5-Fws9AWsCbKfMvgxduXr7JcY-W25bL8NF1fjpLRSOgJb7RoZPHqGQNwMTM7S9tHVoxx8.woff2 +0 -0
  6. package/.output/public/_fonts/NdzqRASp2bovDUhQT1IRE_EMqKJ2KYQdTCfFcBvL8yw-KhwZiS86o3fErOe5GGMExHUemmI_dBfaEFxjISZrBd0.woff2 +0 -0
  7. package/.output/public/_fonts/iTkrULNFJJkTvihIg1Vqi5IODRH_9btXCioVF5l98I8-AndUyau2HR2felA_ra8V2mutQgschhasE5FD1dXGJX8.woff2 +0 -0
  8. package/.output/public/_nuxt/{qQyvCkbV.js → 5Tu2WUJz.js} +1 -1
  9. package/.output/public/_nuxt/B0N6xv5E.js +1 -0
  10. package/.output/public/_nuxt/{DjPT-NCE.js → B0cUlOSM.js} +1 -1
  11. package/.output/public/_nuxt/B9paGgN0.js +33 -0
  12. package/.output/public/_nuxt/{IxYCG8hB.js → BCIlnd0g.js} +1 -1
  13. package/.output/public/_nuxt/{ikxafTHA.js → BNDnV2op.js} +180 -184
  14. package/.output/public/_nuxt/{Ce-T_1aD.js → BO4hqv6q.js} +1 -1
  15. package/.output/public/_nuxt/{Bd32GOUy.js → BOsJJ_ZU.js} +1 -1
  16. package/.output/public/_nuxt/{BzhSDy30.js → C2BHp-MG.js} +1 -1
  17. package/.output/public/_nuxt/{Cs8GXJCB.js → CKULsFUz.js} +1 -1
  18. package/.output/public/_nuxt/CMH9iX_E.js +6 -0
  19. package/.output/public/_nuxt/{tzj4nvDE.js → CzbCpNnc.js} +2 -2
  20. package/.output/public/_nuxt/{CC3n3Aga.js → D87QMS6j.js} +1 -1
  21. package/.output/public/_nuxt/DA0pQuyP.js +27 -0
  22. package/.output/public/_nuxt/{B7P0wQ35.js → DcJ7oPvZ.js} +1 -1
  23. package/.output/public/_nuxt/{Ick_23I4.js → Dce9SnGa.js} +1 -1
  24. package/.output/public/_nuxt/{CAd-qHfI.js → DpKrXpkK.js} +1 -1
  25. package/.output/public/_nuxt/DsnIpnT9.js +1 -0
  26. package/.output/public/_nuxt/{CNZorjDf.js → I3Ucam2s.js} +1 -1
  27. package/.output/public/_nuxt/builds/latest.json +1 -1
  28. package/.output/public/_nuxt/builds/meta/51f1351c-0667-4235-9ddc-16582a51ce03.json +1 -0
  29. package/.output/public/_nuxt/{entry.J_CbC0oY.css → entry.B-vs1tRH.css} +1 -1
  30. package/.output/public/_nuxt/error-404.CTSXlFYa.css +1 -0
  31. package/.output/public/_nuxt/error-500.DqEfQnVZ.css +1 -0
  32. package/.output/public/_nuxt/{nDZOJ7rN.js → o-NCh2rp.js} +2 -2
  33. package/.output/public/_nuxt/{qwxNOyg7.js → sKEJiAHO.js} +1 -1
  34. package/.output/public/_nuxt/{81vqh61j.js → tqQNlhT9.js} +1 -1
  35. package/.output/public/_nuxt/ypRHVLFO.js +1 -0
  36. package/.output/server/chunks/_/error-500.mjs.map +1 -1
  37. package/.output/server/chunks/build/client.precomputed.mjs +1 -1
  38. package/.output/server/chunks/build/{error-404-BN-7rNE4.mjs → error-404-KRkA0DPI.mjs} +10 -4
  39. package/.output/server/chunks/build/error-404-KRkA0DPI.mjs.map +1 -0
  40. package/.output/server/chunks/build/error-404-styles.I0NYw-Bn.mjs +8 -0
  41. package/.output/server/chunks/build/error-404-styles.I0NYw-Bn.mjs.map +1 -0
  42. package/.output/server/chunks/build/{error-500-DhIQ-2yt.mjs → error-500-DIIFf55p.mjs} +10 -4
  43. package/.output/server/chunks/build/error-500-DIIFf55p.mjs.map +1 -0
  44. package/.output/server/chunks/build/error-500-styles.D1cs9hQy.mjs +8 -0
  45. package/.output/server/chunks/build/error-500-styles.D1cs9hQy.mjs.map +1 -0
  46. package/.output/server/chunks/build/index-CB1N4gax.mjs +557 -0
  47. package/.output/server/chunks/build/index-CB1N4gax.mjs.map +1 -0
  48. package/.output/server/chunks/build/server.mjs +326 -248
  49. package/.output/server/chunks/build/server.mjs.map +1 -1
  50. package/.output/server/chunks/build/styles.mjs +4 -4
  51. package/.output/server/chunks/nitro/nitro.mjs +2328 -861
  52. package/.output/server/chunks/nitro/nitro.mjs.map +1 -1
  53. package/.output/server/chunks/routes/api/editor-types.get.mjs +44 -0
  54. package/.output/server/chunks/routes/api/editor-types.get.mjs.map +1 -0
  55. package/.output/server/chunks/routes/api/parse.post.mjs +26 -1448
  56. package/.output/server/chunks/routes/api/parse.post.mjs.map +1 -1
  57. package/.output/server/chunks/routes/api/resolve.get.mjs +6 -0
  58. package/.output/server/chunks/routes/api/resolve.get.mjs.map +1 -1
  59. package/.output/server/chunks/routes/api/studio/run.post.mjs +35 -0
  60. package/.output/server/chunks/routes/api/studio/run.post.mjs.map +1 -0
  61. package/.output/server/chunks/routes/renderer.mjs +1 -1
  62. package/.output/server/chunks/routes/renderer.mjs.map +1 -1
  63. package/.output/server/index.mjs +7 -1
  64. package/.output/server/index.mjs.map +1 -1
  65. package/.output/server/node_modules/acorn/dist/acorn.mjs +6266 -0
  66. package/.output/server/node_modules/acorn/package.json +50 -0
  67. package/.output/server/node_modules/ip-address/dist/common.js +112 -4
  68. package/.output/server/node_modules/ip-address/dist/ipv4.js +322 -87
  69. package/.output/server/node_modules/ip-address/dist/ipv6.js +654 -199
  70. package/.output/server/node_modules/ip-address/dist/v4/constants.js +45 -2
  71. package/.output/server/node_modules/ip-address/dist/v6/constants.js +55 -3
  72. package/.output/server/node_modules/ip-address/dist/v6/helpers.js +12 -3
  73. package/.output/server/node_modules/ip-address/package.json +49 -37
  74. package/.output/server/node_modules/ufo/dist/index.mjs +2 -2
  75. package/.output/server/node_modules/ufo/package.json +9 -9
  76. package/.output/server/package.json +4 -3
  77. package/README.md +62 -19
  78. package/app/assets/css/main.css +1 -0
  79. package/app/assets/css/studio.css +131 -0
  80. package/app/components/StudioConversion.vue +41 -0
  81. package/app/components/StudioDataPanel.vue +21 -0
  82. package/app/components/StudioEditor.vue +78 -102
  83. package/app/components/StudioExpandButton.vue +11 -0
  84. package/app/components/StudioOutput.vue +7 -1
  85. package/app/components/StudioSourcePanel.vue +16 -0
  86. package/app/components/StudioValidation.vue +47 -0
  87. package/app/components/ZodMongooseStudio.vue +216 -198
  88. package/app/composables/useStudioRunner.ts +142 -0
  89. package/app/pages/index.vue +1 -1
  90. package/app/plugins/monaco.client.ts +2 -0
  91. package/bin/index.mjs +5 -0
  92. package/nuxt.config.ts +4 -3
  93. package/package.json +4 -2
  94. package/server/api/editor-types.get.ts +28 -0
  95. package/server/api/parse.post.ts +17 -175
  96. package/server/api/studio/run.post.ts +17 -0
  97. package/server/middleware/security.ts +29 -7
  98. package/server/utils/example-data.ts +80 -0
  99. package/server/utils/parse-request.ts +28 -0
  100. package/server/utils/runner-client.ts +40 -0
  101. package/server/utils/studio-execution.ts +176 -0
  102. package/.output/public/_nuxt/BD40YYqZ.js +0 -33
  103. package/.output/public/_nuxt/BlQmLjV4.js +0 -1
  104. package/.output/public/_nuxt/CJ4Cv9fY.js +0 -61
  105. package/.output/public/_nuxt/builds/meta/495a8ebb-444d-4414-9b98-c181aa84d817.json +0 -1
  106. package/.output/public/_nuxt/error-404.64pZEiDn.css +0 -1
  107. package/.output/public/_nuxt/error-500.DHOpI0Ir.css +0 -1
  108. package/.output/public/_nuxt/rH_O4qXT.js +0 -1
  109. package/.output/server/chunks/build/error-404-BN-7rNE4.mjs.map +0 -1
  110. package/.output/server/chunks/build/error-404-styles.Byx46oLR.mjs +0 -8
  111. package/.output/server/chunks/build/error-404-styles.Byx46oLR.mjs.map +0 -1
  112. package/.output/server/chunks/build/error-500-DhIQ-2yt.mjs.map +0 -1
  113. package/.output/server/chunks/build/error-500-styles.BL3UT0Wa.mjs +0 -8
  114. package/.output/server/chunks/build/error-500-styles.BL3UT0Wa.mjs.map +0 -1
  115. package/.output/server/chunks/build/index-B4T6zHp0.mjs +0 -1904
  116. package/.output/server/chunks/build/index-B4T6zHp0.mjs.map +0 -1
  117. package/.output/server/node_modules/zod/index.js +0 -4
  118. /package/.output/public/_nuxt/{editor.CdBKkuhR.css → monaco.CdBKkuhR.css} +0 -0
@@ -1,8 +1,51 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RE_SUBNET_STRING = exports.RE_ADDRESS = exports.GROUPS = exports.BITS = void 0;
3
+ exports.SPECIAL_PURPOSE = exports.RE_SUBNET_STRING = exports.RE_ADDRESS = exports.GROUPS = exports.BITS = void 0;
4
4
  exports.BITS = 32;
5
5
  exports.GROUPS = 4;
6
- exports.RE_ADDRESS = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/g;
6
+ // Each octet is 0-255 written without a leading zero. A leading zero is
7
+ // octal to the WHATWG URL parser, inet_aton, and getaddrinfo, but decimal to
8
+ // parseInt(part, 10), so accepting the notation would make this library
9
+ // disagree with the network stack about which host a string names.
10
+ exports.RE_ADDRESS = /^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])$/g;
7
11
  exports.RE_SUBNET_STRING = /\/\d{1,2}$/;
12
+ /**
13
+ * The IANA IPv4 Special-Purpose Address Registry
14
+ * (https://www.iana.org/assignments/iana-ipv4-special-registry/), one entry
15
+ * per block: `[cidr, name, globallyReachable]`. A `null` reachability means
16
+ * the registry leaves the column blank and the block inherits the answer of
17
+ * the block containing it (or is global when nothing contains it).
18
+ *
19
+ * `Address4.isGlobal()` answers from the most specific entry containing the
20
+ * address. `test/data/iana-corpus.json` is generated from the registry's CSV
21
+ * and pins this table to it.
22
+ */
23
+ exports.SPECIAL_PURPOSE = [
24
+ ['0.0.0.0/8', 'This network', false],
25
+ ['0.0.0.0/32', 'This host on this network', false],
26
+ ['10.0.0.0/8', 'Private-Use', false],
27
+ ['100.64.0.0/10', 'Shared Address Space', false],
28
+ ['127.0.0.0/8', 'Loopback', false],
29
+ ['169.254.0.0/16', 'Link Local', false],
30
+ ['172.16.0.0/12', 'Private-Use', false],
31
+ ['192.0.0.0/24', 'IETF Protocol Assignments', false],
32
+ ['192.0.0.0/29', 'IPv4 Service Continuity Prefix', false],
33
+ ['192.0.0.8/32', 'IPv4 dummy address', false],
34
+ ['192.0.0.9/32', 'Port Control Protocol Anycast', true],
35
+ ['192.0.0.10/32', 'Traversal Using Relays around NAT Anycast', true],
36
+ ['192.0.0.170/32', 'NAT64/DNS64 Discovery', false],
37
+ ['192.0.0.171/32', 'NAT64/DNS64 Discovery', false],
38
+ ['192.0.2.0/24', 'Documentation (TEST-NET-1)', false],
39
+ ['192.31.196.0/24', 'AS112-v4', true],
40
+ ['192.52.193.0/24', 'AMT', true],
41
+ ['192.88.99.0/24', 'Deprecated (6to4 Relay Anycast)', null],
42
+ ['192.88.99.2/32', '6a44-relay anycast address', false],
43
+ ['192.168.0.0/16', 'Private-Use', false],
44
+ ['192.175.48.0/24', 'Direct Delegation AS112 Service', true],
45
+ ['198.18.0.0/15', 'Benchmarking', false],
46
+ ['198.51.100.0/24', 'Documentation (TEST-NET-2)', false],
47
+ ['203.0.113.0/24', 'Documentation (TEST-NET-3)', false],
48
+ ['240.0.0.0/4', 'Reserved', false],
49
+ ['255.255.255.255/32', 'Limited Broadcast', false],
50
+ ];
8
51
  //# sourceMappingURL=constants.js.map
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RE_URL_WITH_PORT = exports.RE_URL = exports.RE_ZONE_STRING = exports.RE_SUBNET_STRING = exports.RE_BAD_ADDRESS = exports.RE_BAD_CHARACTERS = exports.TYPES = exports.SCOPES = exports.GROUPS = exports.BITS = void 0;
3
+ exports.SPECIAL_PURPOSE = exports.RE_URL_WITH_PORT = exports.RE_URL = exports.RE_ZONE_STRING = exports.RE_SUBNET_STRING = exports.RE_BAD_ADDRESS = exports.RE_BAD_CHARACTERS = exports.TYPES = exports.SCOPES = exports.GROUPS = exports.BITS = void 0;
4
4
  exports.BITS = 128;
5
5
  exports.GROUPS = 8;
6
6
  /**
@@ -44,8 +44,20 @@ exports.TYPES = {
44
44
  'ff05::1:3/128': 'Multicast (All DHCP servers in this site)',
45
45
  '::/128': 'Unspecified',
46
46
  '::1/128': 'Loopback',
47
+ '::ffff:0:0/96': 'IPv4-mapped',
47
48
  'ff00::/8': 'Multicast',
48
49
  'fe80::/10': 'Link-local unicast',
50
+ 'fc00::/7': 'Unique local',
51
+ '2001::/32': 'Teredo',
52
+ '2001:2::/48': 'Benchmarking',
53
+ '2002::/16': '6to4',
54
+ '2001:db8::/32': 'Documentation',
55
+ '3fff::/20': 'Documentation',
56
+ '100::/64': 'Discard-only',
57
+ 'fec0::/10': 'Site-local unicast (deprecated)',
58
+ '::/96': 'IPv4-compatible (deprecated)',
59
+ '64:ff9b::/96': 'NAT64 (well-known)',
60
+ '64:ff9b:1::/48': 'NAT64 (local-use)',
49
61
  };
50
62
  /**
51
63
  * A regular expression that matches bad characters in an IPv6 address
@@ -71,6 +83,46 @@ exports.RE_SUBNET_STRING = /\/\d{1,3}(?=%|$)/;
71
83
  * @static
72
84
  */
73
85
  exports.RE_ZONE_STRING = /%.*$/;
74
- exports.RE_URL = /^\[{0,1}([0-9a-f:]+)\]{0,1}/;
75
- exports.RE_URL_WITH_PORT = /\[([0-9a-f:]+)\]:([0-9]{1,5})/;
86
+ exports.RE_URL = /^(?:\[([0-9a-f:.]+)\]|([0-9a-f:.]+))(?:[/?#].*)?$/i;
87
+ exports.RE_URL_WITH_PORT = /^\[([0-9a-f:.]+)\]:([0-9]{1,5})(?:[/?#].*)?$/i;
88
+ /**
89
+ * The IANA IPv6 Special-Purpose Address Registry
90
+ * (https://www.iana.org/assignments/iana-ipv6-special-registry/), one entry
91
+ * per block: `[cidr, name, globallyReachable]`. A `null` reachability means
92
+ * the registry says N/A or leaves the column blank; N/A blocks (Teredo, 6to4)
93
+ * are treated as not globally reachable, since a packet to one needs a relay,
94
+ * and blank blocks inherit the answer of the block containing them.
95
+ *
96
+ * `Address6.isGlobal()` answers from the most specific entry containing the
97
+ * address, after delegating IPv4-mapped and NAT64 well-known addresses to the
98
+ * embedded IPv4 address. `test/data/iana-corpus.json` is generated from the
99
+ * registry's CSV and pins this table to it.
100
+ */
101
+ exports.SPECIAL_PURPOSE = [
102
+ ['::1/128', 'Loopback Address', false],
103
+ ['::/128', 'Unspecified Address', false],
104
+ ['::ffff:0:0/96', 'IPv4-mapped Address', false],
105
+ ['64:ff9b::/96', 'IPv4-IPv6 Translat.', true],
106
+ ['64:ff9b:1::/48', 'IPv4-IPv6 Translat.', false],
107
+ ['100::/64', 'Discard-Only Address Block', false],
108
+ ['100:0:0:1::/64', 'Dummy IPv6 Prefix', false],
109
+ ['2001::/23', 'IETF Protocol Assignments', false],
110
+ ['2001::/32', 'TEREDO', false],
111
+ ['2001:1::1/128', 'Port Control Protocol Anycast', true],
112
+ ['2001:1::2/128', 'Traversal Using Relays around NAT Anycast', true],
113
+ ['2001:1::3/128', 'DNS-SD Service Registration Protocol Anycast', true],
114
+ ['2001:2::/48', 'Benchmarking', false],
115
+ ['2001:3::/32', 'AMT', true],
116
+ ['2001:4:112::/48', 'AS112-v6', true],
117
+ ['2001:10::/28', 'Deprecated (previously ORCHID)', null],
118
+ ['2001:20::/28', 'ORCHIDv2', true],
119
+ ['2001:30::/28', 'Drone Remote ID Protocol Entity Tags (DETs) Prefix', true],
120
+ ['2001:db8::/32', 'Documentation', false],
121
+ ['2002::/16', '6to4', false],
122
+ ['2620:4f:8000::/48', 'Direct Delegation AS112 Service', true],
123
+ ['3fff::/20', 'Documentation', false],
124
+ ['5f00::/16', 'Segment Routing (SRv6) SIDs', false],
125
+ ['fc00::/7', 'Unique-Local', false],
126
+ ['fe80::/10', 'Link-Local Unicast', false],
127
+ ];
76
128
  //# sourceMappingURL=constants.js.map
@@ -1,14 +1,23 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.escapeHtml = escapeHtml;
3
4
  exports.spanAllZeroes = spanAllZeroes;
4
5
  exports.spanAll = spanAll;
5
6
  exports.spanLeadingZeroes = spanLeadingZeroes;
6
7
  exports.simpleGroup = simpleGroup;
8
+ function escapeHtml(s) {
9
+ return s
10
+ .replace(/&/g, '&')
11
+ .replace(/</g, '&lt;')
12
+ .replace(/>/g, '&gt;')
13
+ .replace(/"/g, '&quot;')
14
+ .replace(/'/g, '&#39;');
15
+ }
7
16
  /**
8
17
  * @returns {String} the string with all zeroes contained in a <span>
9
18
  */
10
19
  function spanAllZeroes(s) {
11
- return s.replace(/(0+)/g, '<span class="zero">$1</span>');
20
+ return escapeHtml(s).replace(/(0+)/g, '<span class="zero">$1</span>');
12
21
  }
13
22
  /**
14
23
  * @returns {String} the string with each character contained in a <span>
@@ -16,11 +25,11 @@ function spanAllZeroes(s) {
16
25
  function spanAll(s, offset = 0) {
17
26
  const letters = s.split('');
18
27
  return letters
19
- .map((n, i) => `<span class="digit value-${n} position-${i + offset}">${spanAllZeroes(n)}</span>`)
28
+ .map((n, i) => `<span class="digit value-${escapeHtml(n)} position-${i + offset}">${spanAllZeroes(n)}</span>`)
20
29
  .join('');
21
30
  }
22
31
  function spanLeadingZeroesSimple(group) {
23
- return group.replace(/^(0+)/, '<span class="zero">$1</span>');
32
+ return escapeHtml(group).replace(/^(0+)/, '<span class="zero">$1</span>');
24
33
  }
25
34
  /**
26
35
  * @returns {String} the string with leading zeroes contained in a <span>
@@ -2,77 +2,89 @@
2
2
  "name": "ip-address",
3
3
  "description": "A library for parsing IPv4 and IPv6 IP addresses in node and the browser.",
4
4
  "keywords": [
5
- "ipv6",
5
+ "ip",
6
6
  "ipv4",
7
- "browser",
8
- "validation"
7
+ "ipv6",
8
+ "address",
9
+ "cidr",
10
+ "subnet",
11
+ "netmask",
12
+ "validate",
13
+ "validation",
14
+ "parse",
15
+ "arpa",
16
+ "bigint",
17
+ "browser"
9
18
  ],
10
- "version": "10.1.0",
19
+ "version": "10.7.2",
11
20
  "author": "Beau Gunderson <beau@beaugunderson.com> (https://beaugunderson.com/)",
12
21
  "license": "MIT",
13
22
  "main": "dist/ip-address.js",
14
23
  "types": "dist/ip-address.d.ts",
15
24
  "scripts": {
16
- "docs": "documentation build --github --output docs --format html ./ip-address.js",
25
+ "docs": "tsx scripts/build-readme.ts",
17
26
  "build": "rm -rf dist; mkdir dist; tsc",
18
- "prepack": "npm run build",
19
- "release": "release-it",
20
- "test-ci": "nyc mocha",
27
+ "prepack": "npm run docs && npm run build",
28
+ "prepare": "git config core.hooksPath hooks || true",
29
+ "lint": "prettier --check . && eslint . --ext .ts,.js --max-warnings 0",
30
+ "lint:fix": "prettier --write . && eslint . --ext .ts,.js --max-warnings 0 --fix",
31
+ "test-ci": "c8 --experimental-monocart mocha",
21
32
  "test": "mocha",
22
33
  "watch": "mocha --watch"
23
34
  },
24
- "nyc": {
25
- "extension": [
26
- ".ts"
35
+ "c8": {
36
+ "include": [
37
+ "src/**/*.ts"
27
38
  ],
28
39
  "exclude": [
29
40
  "**/*.d.ts",
30
- ".eslintrc.js",
31
- "coverage/",
32
- "dist/",
33
- "test/",
34
- "tmp/"
41
+ "src/ip-address.ts",
42
+ "src/v4/constants.ts",
43
+ "src/v6/constants.ts"
35
44
  ],
36
45
  "reporter": [
37
46
  "html",
38
47
  "lcov",
39
48
  "text"
40
- ],
41
- "all": true
49
+ ]
42
50
  },
43
51
  "engines": {
44
52
  "node": ">= 12"
45
53
  },
54
+ "sideEffects": false,
46
55
  "files": [
47
- "src",
48
56
  "dist"
49
57
  ],
50
58
  "repository": {
51
59
  "type": "git",
52
- "url": "git://github.com/beaugunderson/ip-address.git"
60
+ "url": "https://github.com/beaugunderson/ip-address.git"
61
+ },
62
+ "overrides": {
63
+ "diff": "^8.0.3",
64
+ "serialize-javascript": "^7.0.5",
65
+ "@eslint/plugin-kit": "^0.7.1"
53
66
  },
54
67
  "devDependencies": {
55
- "@types/chai": "^5.0.0",
56
- "@types/mocha": "^10.0.8",
57
- "@typescript-eslint/eslint-plugin": "^8.8.0",
58
- "@typescript-eslint/parser": "^8.8.0",
59
- "chai": "^5.1.1",
60
- "documentation": "^14.0.3",
61
- "eslint": "^8.50.0",
68
+ "@types/chai": "^5.2.3",
69
+ "@types/mocha": "^10.0.10",
70
+ "@typescript-eslint/eslint-plugin": "^8.59.1",
71
+ "@typescript-eslint/parser": "^8.59.1",
72
+ "c8": "^11.0.0",
73
+ "chai": "^6.2.2",
74
+ "eslint": "^8.57.1",
62
75
  "eslint_d": "^14.0.4",
63
- "eslint-config-airbnb": "^19.0.4",
64
- "eslint-config-prettier": "^9.1.0",
76
+ "eslint-config-airbnb-base": "^15.0.0",
77
+ "eslint-config-prettier": "^10.1.8",
65
78
  "eslint-plugin-filenames": "^1.3.2",
66
- "eslint-plugin-import": "^2.30.0",
67
- "eslint-plugin-jsx-a11y": "^6.10.0",
68
- "eslint-plugin-prettier": "^5.2.1",
79
+ "eslint-plugin-import": "^2.32.0",
80
+ "eslint-plugin-prettier": "^5.5.5",
69
81
  "eslint-plugin-sort-imports-es6-autofix": "^0.6.0",
70
- "mocha": "^10.7.3",
71
- "nyc": "^17.1.0",
72
- "prettier": "^3.3.3",
73
- "release-it": "^17.6.0",
82
+ "mocha": "^11.7.5",
83
+ "monocart-coverage-reports": "^2.12.11",
84
+ "prettier": "^3.8.3",
74
85
  "source-map-support": "^0.5.21",
75
- "tsx": "^4.19.1",
86
+ "tsx": "^4.21.0",
87
+ "typedoc": "^0.28.19",
76
88
  "typescript": "<5.6.0"
77
89
  }
78
90
  }
@@ -286,8 +286,8 @@ function withoutBase(input, base) {
286
286
  if (nextChar && nextChar !== "/" && nextChar !== "?") {
287
287
  return input;
288
288
  }
289
- const trimmed = input.slice(_base.length);
290
- return trimmed[0] === "/" ? trimmed : "/" + trimmed;
289
+ const trimmed = input.slice(_base.length).replace(/^\/+/, "");
290
+ return "/" + trimmed;
291
291
  }
292
292
  function withQuery(input, query) {
293
293
  const parsed = parseURL(input);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ufo",
3
- "version": "1.6.3",
3
+ "version": "1.6.4",
4
4
  "description": "URL utils for humans",
5
5
  "repository": "unjs/ufo",
6
6
  "license": "MIT",
@@ -31,18 +31,18 @@
31
31
  "test": "pnpm lint && vitest run --typecheck"
32
32
  },
33
33
  "devDependencies": {
34
- "@types/node": "^25.0.8",
35
- "@vitest/coverage-v8": "^4.0.17",
36
- "automd": "^0.4.2",
34
+ "@types/node": "^25.6.0",
35
+ "@vitest/coverage-v8": "^4.1.5",
36
+ "automd": "^0.4.3",
37
37
  "changelogen": "^0.6.2",
38
- "eslint": "^9.39.2",
38
+ "eslint": "^10.2.1",
39
39
  "eslint-config-unjs": "^0.6.2",
40
40
  "jiti": "^2.6.1",
41
- "prettier": "^3.7.4",
42
- "typescript": "^5.9.3",
41
+ "prettier": "^3.8.3",
42
+ "typescript": "^6.0.3",
43
43
  "unbuild": "^3.6.1",
44
44
  "untyped": "^2.0.0",
45
- "vitest": "^4.0.17"
45
+ "vitest": "^4.1.5"
46
46
  },
47
- "packageManager": "pnpm@10.28.0"
47
+ "packageManager": "pnpm@10.33.2"
48
48
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nullix/zod-mongoose-studio-prod",
3
- "version": "3.3.0",
3
+ "version": "3.3.1",
4
4
  "type": "module",
5
5
  "private": true,
6
6
  "dependencies": {
@@ -16,6 +16,7 @@
16
16
  "@vue/runtime-dom": "3.5.32",
17
17
  "@vue/server-renderer": "3.5.32",
18
18
  "@vue/shared": "3.5.32",
19
+ "acorn": "8.16.0",
19
20
  "bson": "7.2.0",
20
21
  "consola": "3.4.2",
21
22
  "devalue": "5.6.4",
@@ -23,7 +24,7 @@
23
24
  "esbuild": "0.28.0",
24
25
  "estree-walker": "2.0.2",
25
26
  "hookable": "6.1.0",
26
- "ip-address": "10.1.0",
27
+ "ip-address": "10.7.2",
27
28
  "kareem": "3.3.0",
28
29
  "memory-pager": "1.5.0",
29
30
  "mongodb": "7.2.0",
@@ -41,7 +42,7 @@
41
42
  "sparse-bitfield": "3.0.3",
42
43
  "tailwindcss": "4.2.2",
43
44
  "tr46": "5.1.1",
44
- "ufo": "1.6.3",
45
+ "ufo": "1.6.4",
45
46
  "unhead": "2.1.12",
46
47
  "vue": "3.5.32",
47
48
  "vue-bundle-renderer": "2.2.0",
package/README.md CHANGED
@@ -1,23 +1,51 @@
1
- <img src="https://raw.githubusercontent.com/Harm-Nullix/zod-mongoose/HEAD/logo.svg" width="200" alt="Logo">
1
+ <div align="center">
2
+ <img src="https://raw.githubusercontent.com/Harm-Nullix/zod-mongoose/HEAD/logo.svg" width="200" alt="Logo">
3
+ </div>
4
+ <div align="center">
2
5
 
3
6
  [![Release](https://github.com/Harm-Nullix/zod-mongoose/actions/workflows/release.yml/badge.svg)](https://github.com/Harm-Nullix/zod-mongoose/actions/workflows/release.yml)
4
- [![NPM Version](https://img.shields.io/npm/v/@nullix/zod-mongoose.svg)](https://www.npmjs.com/package/@nullix/zod-mongoose-studio)
5
- [![License](https://img.shields.io/npm/l/@nullix/zod-mongoose.svg)](https://github.com/Harm-Nullix/zod-mongoose/blob/main/packages/core/LICENSE.md)
7
+ [![NPM Version](https://img.shields.io/npm/v/@nullix/zod-mongoose-studio.svg)](https://www.npmjs.com/package/@nullix/zod-mongoose-studio)
8
+ [![NPM Downloads](https://img.shields.io/npm/dm/@nullix/zod-mongoose-studio.svg)](https://www.npmjs.com/package/@nullix/zod-mongoose-studio)
9
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Strict-blue.svg)](https://www.typescriptlang.org/)
10
+ [![Node.js Version](https://img.shields.io/node/v/@nullix/zod-mongoose-studio.svg)](https://www.npmjs.com/package/@nullix/zod-mongoose-studio)
11
+ [![License](https://img.shields.io/npm/l/@nullix/zod-mongoose.svg)](https://github.com/Harm-Nullix/zod-mongoose/blob/main/packages/studio/LICENSE.md)
12
+
13
+ </div>
6
14
 
7
15
 
8
16
  # @nullix/zod-mongoose-studio
9
17
 
10
18
  A Monaco-powered TypeScript playground for [@nullix/zod-mongoose](https://github.com/Harm-Nullix/zod-mongoose).
11
19
 
12
- The Studio provides a powerful web-integrated interface to experiment with Zod-to-Mongoose transformations. It supports local development via a CLI with full filesystem access and a sandboxed mode for documentation and live demos.
20
+ The Studio provides a web-integrated interface to experiment with Zod validation and Zod-to-Mongoose transformations. It supports local development via a CLI and an embedded documentation mode.
13
21
 
14
22
  ## Goal
15
23
 
16
24
  Create a CLI tool and web-integrated "Studio" that provides:
17
- - A Monaco-powered TypeScript editor for Zod schemas.
18
- - Real-time transformation to Mongoose schema definitions and POJOs.
25
+ - A Monaco-powered TypeScript editor for Zod schemas and a separate JSON data editor.
26
+ - Parsed Zod output or field-level validation issues next to Mongoose conversion output.
27
+ - Schema discovery, valid example data, and Run shortcuts.
19
28
  - **Local Mode**: Runs via `npx` with full filesystem bridge for IntelliSense in your project.
20
- - **Docs Mode**: A secure, sandboxed environment for embedding in documentation or static deployments.
29
+ - **Docs Mode**: An embeddable playground that sends Run requests to a separate container runner through a Unix socket.
30
+
31
+ ## Studio workflow
32
+
33
+ Define one or more Zod schemas in the TypeScript editor. `z` from `zod/v4` and the runtime exports of `@nullix/zod-mongoose` are available without import lines:
34
+
35
+ ```ts
36
+ const UserSchema = z.object({
37
+ name: z.string().trim().min(2),
38
+ role: z.enum(['reader', 'admin']).default('reader'),
39
+ });
40
+ ```
41
+
42
+ Studio discovers top-level schemas automatically. When there are several, choose one from **Active schema**. Existing snippets using explicit imports and `export default` still work.
43
+
44
+ Use the expand button in any panel header for a full Studio workspace, then press Escape or the button again to restore the grid. The schema code, JSON input, and selected schema survive reloads in the same browser tab through `sessionStorage`; they are not saved on the server.
45
+
46
+ Enter JSON in **Try some data** and select **Run studio**. The validation result shows parsed data, including defaults and transforms, or Zod issues with their paths. Mongoose output remains available under **Definition**, **.obj**, **.tree**, and **.paths**. Use `⌘/Ctrl+S` or `⌘/Ctrl+R` to run while Studio has focus. Local mode also reruns after a short pause when schema code changes.
47
+
48
+ **Load valid example** generates JSON input and checks it against the selected schema before inserting it. For a custom refinement that cannot be generated automatically, provide a top-level `const exampleInput = { ... }` in the code editor; Studio checks that value too.
21
49
 
22
50
  ## Technical Stack
23
51
 
@@ -79,22 +107,21 @@ export default defineNuxtConfig({
79
107
  <UContainer>
80
108
  <h1 class="text-2xl font-bold my-4">Try it live!</h1>
81
109
 
82
- <!-- Automatically connects to the injected /api/parse route -->
83
- <ZodMongooseStudio class="h-[600px] border rounded-lg shadow-sm" />
110
+ <!-- Run uses the isolated runner configured on the docs host. -->
111
+ <ZodMongooseStudio class="border rounded-lg shadow-sm" style="--studio-height: 600px" />
84
112
  </UContainer>
85
113
  </template>
86
114
  ```
87
115
 
88
116
  ## Features & Configuration
89
117
 
90
- ### Transformation Engine (`/api/parse`)
118
+ ### Transformation Engine (`/api/parse` locally, `/api/studio/run` in docs)
91
119
 
92
- The core logic executes Zod schemas in a controlled environment. It automatically injects the necessary imports for `zod/v4` and `@nullix/zod-mongoose`:
120
+ The runner exposes `z` and the public runtime helpers from `@nullix/zod-mongoose` as editor globals. Explicit imports of `zod/v4`, `@nullix/zod-mongoose`, and `mongoose` are also supported. The API accepts schema code, selected schema name, and JSON input; it returns validation and conversion results separately.
93
121
 
94
122
  ```ts
95
- import * as zod from 'zod/v4';
96
- const z = zod.z;
97
- import { toMongooseScheme, extractMongooseDefinition } from '@nullix/zod-mongoose';
123
+ const UserSchema = z.object({ name: z.string() });
124
+ const exampleInput = { name: 'Ada' }; // Optional for custom validation rules
98
125
  ```
99
126
 
100
127
  ### Filesystem Bridge (`/api/resolve`)
@@ -103,12 +130,28 @@ Available only in **Local Mode** (`LOCAL_MODE=true`). It uses Node's `fs` or `ts
103
130
 
104
131
  ### Sandboxing & Security
105
132
 
106
- When running in **Docs Mode** (`DOCS_MODE=true`), several security layers are enforced:
133
+ Node's `vm` is **not a security boundary for untrusted code**. In Docs Mode, `/api/studio/run` forwards requests to a warm container through `STUDIO_RUNNER_SOCKET`; `/api/parse` remains restricted to the local CLI. Without the socket, the docs route returns 503. The docs process never evaluates visitor code. The runner container has no network and is read-only with CPU, memory, and process limits in `docker/compose.yaml`. Its small root supervisor accepts requests over the socket and starts a **new process with a fresh, unprivileged UID for every run**. No session retains a worker; at most two requests execute at once and eight wait in the queue. The three-second deadline kills the worker process group. The socket is owned by UID/GID 1000 and cannot be opened by workers. The supervisor needs only CHOWN, SETUID, SETGID and KILL capabilities. This reduces cross-request exposure, but does not make arbitrary code execution risk-free: malicious code could still try to exhaust the runner container or escape a process group. Keep Docker and the VPS patched and retain edge-level rate limits. Do not mount the Docker daemon socket into the docs server or runner.
134
+
135
+ To run this on a VPS, create `/run/zod-studio` owned by root and group 1000. The root supervisor creates the socket, then gives socket access to UID/GID 1000. Put the docs service in group 1000. Then build and start the runner from the repository root:
136
+
137
+ ```shell
138
+ sudo install -d -m 0770 -o 0 -g 1000 /run/zod-studio
139
+ docker compose -f packages/studio/docker/compose.yaml up -d --build
140
+ ```
141
+
142
+ Set `STUDIO_RUNNER_SOCKET=/run/zod-studio/runner.sock` in the docs server environment, make that socket path visible to its process, and restart the docs server. If the docs server itself runs in a container, mount only `/run/zod-studio`, never the Docker socket. The docs UI enables Run through its Nuxt configuration. The runner has no TCP listener; only the docs server's H3 route is exposed publicly. Keep the existing public rate limit or add an edge-level limit when running multiple docs instances.
143
+
144
+ After deployment, verify the process boundary from the repository root:
145
+
146
+ ```shell
147
+ docker compose -f packages/studio/docker/compose.yaml exec -T --user 1000:1000 studio-runner node - < packages/studio/docker/smoke-test.cjs
148
+ ```
149
+
150
+ This checks separate UIDs for concurrent runs, worker denial of socket access, timeout handling, and a successful request after timeout. A fresh process adds startup time to each Run request; no process or server-side session remains allocated between requests.
151
+
152
+ Local CLI mode continues to run directly, binds to `127.0.0.1`, and checks API hosts and origins. Browser session data stays in `sessionStorage` and is not kept by the runner.
107
153
 
108
- - **Isolated Execution**: Code transformations occur in a virtual machine context (using `isolated-vm` or equivalent workers) to prevent access to the host `process.env`, `window`, or `document`.
109
- - **Disabled Resolvers**: The `/api/resolve` endpoint is completely disabled.
110
- - **Rate Limiting**: Built-in Nitro middleware tracks IP addresses and limits requests (default: 2 per second) to prevent abuse.
111
- - **UI Hardening**: Elements related to the local filesystem are automatically hidden.
154
+ Running `pnpm --filter @nullix/zod-mongoose-studio dev` also uses the local parse endpoint, without Docker. In docs mode the editors remain usable without a runner, but Run reports that the runner is unavailable until the container and `STUDIO_RUNNER_SOCKET` are configured.
112
155
 
113
156
  ## Project Structure
114
157
 
@@ -1,2 +1,3 @@
1
1
  @import "tailwindcss";
2
2
  @import "@nuxt/ui";
3
+ @import "./studio.css";