effect 4.0.2 → 4.0.3

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 (243) hide show
  1. package/dist/Context.js +3 -3
  2. package/dist/Context.js.map +1 -1
  3. package/dist/Crypto.d.ts +33 -5
  4. package/dist/Crypto.d.ts.map +1 -1
  5. package/dist/Crypto.js +8 -2
  6. package/dist/Crypto.js.map +1 -1
  7. package/dist/DateTime.d.ts +9 -6
  8. package/dist/DateTime.d.ts.map +1 -1
  9. package/dist/DateTime.js +9 -6
  10. package/dist/DateTime.js.map +1 -1
  11. package/dist/Duration.d.ts +6 -6
  12. package/dist/Duration.d.ts.map +1 -1
  13. package/dist/Duration.js +27 -8
  14. package/dist/Duration.js.map +1 -1
  15. package/dist/FileSystem.d.ts +44 -2
  16. package/dist/FileSystem.d.ts.map +1 -1
  17. package/dist/FileSystem.js.map +1 -1
  18. package/dist/Schema.d.ts +473 -1
  19. package/dist/Schema.d.ts.map +1 -1
  20. package/dist/Schema.js +355 -4
  21. package/dist/Schema.js.map +1 -1
  22. package/dist/Stdio.d.ts +7 -1
  23. package/dist/Stdio.d.ts.map +1 -1
  24. package/dist/Stdio.js +1 -0
  25. package/dist/Stdio.js.map +1 -1
  26. package/dist/Stream.d.ts +11 -11
  27. package/dist/Stream.js +5 -5
  28. package/dist/ai/McpServer.d.ts +6 -0
  29. package/dist/ai/McpServer.d.ts.map +1 -1
  30. package/dist/ai/McpServer.js +65 -23
  31. package/dist/ai/McpServer.js.map +1 -1
  32. package/dist/ai/internal/mcpProtocol/v2026_07_28.js +5 -0
  33. package/dist/ai/internal/mcpProtocol/v2026_07_28.js.map +1 -1
  34. package/dist/ai/internal/mcpProtocol.js.map +1 -1
  35. package/dist/ai/internal/mcpRuntime.js +1 -0
  36. package/dist/ai/internal/mcpRuntime.js.map +1 -1
  37. package/dist/cli/CliOutput.d.ts +27 -0
  38. package/dist/cli/CliOutput.d.ts.map +1 -1
  39. package/dist/cli/CliOutput.js +33 -10
  40. package/dist/cli/CliOutput.js.map +1 -1
  41. package/dist/cli/Command.d.ts.map +1 -1
  42. package/dist/cli/Command.js +6 -3
  43. package/dist/cli/Command.js.map +1 -1
  44. package/dist/cli/Completions.d.ts +3 -3
  45. package/dist/cli/Completions.d.ts.map +1 -1
  46. package/dist/cli/Completions.js +8 -5
  47. package/dist/cli/Completions.js.map +1 -1
  48. package/dist/cli/GlobalFlag.d.ts +5 -4
  49. package/dist/cli/GlobalFlag.d.ts.map +1 -1
  50. package/dist/cli/GlobalFlag.js +3 -3
  51. package/dist/cli/GlobalFlag.js.map +1 -1
  52. package/dist/cli/Prompt.d.ts +17 -1
  53. package/dist/cli/Prompt.d.ts.map +1 -1
  54. package/dist/cli/Prompt.js +119 -114
  55. package/dist/cli/Prompt.js.map +1 -1
  56. package/dist/cli/internal/ansi.d.ts +0 -1
  57. package/dist/cli/internal/ansi.d.ts.map +1 -1
  58. package/dist/cli/internal/ansi.js +20 -3
  59. package/dist/cli/internal/ansi.js.map +1 -1
  60. package/dist/cli/internal/completions/powershell.d.ts +2 -0
  61. package/dist/cli/internal/completions/powershell.d.ts.map +1 -0
  62. package/dist/cli/internal/completions/powershell.js +273 -0
  63. package/dist/cli/internal/completions/powershell.js.map +1 -0
  64. package/dist/cli/internal/completions/zsh.js +3 -2
  65. package/dist/cli/internal/completions/zsh.js.map +1 -1
  66. package/dist/cli/internal/wizard.d.ts +3 -3
  67. package/dist/cli/internal/wizard.d.ts.map +1 -1
  68. package/dist/cli/internal/wizard.js +21 -18
  69. package/dist/cli/internal/wizard.js.map +1 -1
  70. package/dist/cluster/ClusterSchema.d.ts +28 -0
  71. package/dist/cluster/ClusterSchema.d.ts.map +1 -1
  72. package/dist/cluster/ClusterSchema.js +30 -0
  73. package/dist/cluster/ClusterSchema.js.map +1 -1
  74. package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
  75. package/dist/cluster/ClusterWorkflowEngine.js +10 -18
  76. package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
  77. package/dist/cluster/MessageStorage.d.ts +18 -3
  78. package/dist/cluster/MessageStorage.d.ts.map +1 -1
  79. package/dist/cluster/MessageStorage.js +31 -11
  80. package/dist/cluster/MessageStorage.js.map +1 -1
  81. package/dist/cluster/Runners.d.ts.map +1 -1
  82. package/dist/cluster/Runners.js +8 -2
  83. package/dist/cluster/Runners.js.map +1 -1
  84. package/dist/cluster/Sharding.d.ts.map +1 -1
  85. package/dist/cluster/Sharding.js +181 -62
  86. package/dist/cluster/Sharding.js.map +1 -1
  87. package/dist/cluster/SqlMessageStorage.d.ts +59 -19
  88. package/dist/cluster/SqlMessageStorage.d.ts.map +1 -1
  89. package/dist/cluster/SqlMessageStorage.js +84 -55
  90. package/dist/cluster/SqlMessageStorage.js.map +1 -1
  91. package/dist/cluster/SqlRunnerStorage.d.ts +68 -19
  92. package/dist/cluster/SqlRunnerStorage.d.ts.map +1 -1
  93. package/dist/cluster/SqlRunnerStorage.js +191 -113
  94. package/dist/cluster/SqlRunnerStorage.js.map +1 -1
  95. package/dist/cluster/internal/entityManager.js +104 -37
  96. package/dist/cluster/internal/entityManager.js.map +1 -1
  97. package/dist/http/FindMyWay/internal/router.js +3 -6
  98. package/dist/http/FindMyWay/internal/router.js.map +1 -1
  99. package/dist/http/HttpClient.d.ts +6 -0
  100. package/dist/http/HttpClient.d.ts.map +1 -1
  101. package/dist/http/HttpClient.js +39 -2
  102. package/dist/http/HttpClient.js.map +1 -1
  103. package/dist/http/HttpTraceContext.d.ts.map +1 -1
  104. package/dist/http/HttpTraceContext.js +4 -2
  105. package/dist/http/HttpTraceContext.js.map +1 -1
  106. package/dist/internal/effect.js +12 -7
  107. package/dist/internal/effect.js.map +1 -1
  108. package/dist/internal/version.js +1 -1
  109. package/dist/net/AddressResolver.d.ts +145 -0
  110. package/dist/net/AddressResolver.d.ts.map +1 -0
  111. package/dist/net/AddressResolver.js +114 -0
  112. package/dist/net/AddressResolver.js.map +1 -0
  113. package/dist/net/Dns.d.ts +596 -0
  114. package/dist/net/Dns.d.ts.map +1 -0
  115. package/dist/net/Dns.js +549 -0
  116. package/dist/net/Dns.js.map +1 -0
  117. package/dist/net/Host.d.ts +320 -0
  118. package/dist/net/Host.d.ts.map +1 -0
  119. package/dist/net/Host.js +342 -0
  120. package/dist/net/Host.js.map +1 -0
  121. package/dist/net/IpInterface.d.ts +76 -3
  122. package/dist/net/IpInterface.d.ts.map +1 -1
  123. package/dist/net/IpInterface.js +53 -4
  124. package/dist/net/IpInterface.js.map +1 -1
  125. package/dist/net/IpNetwork.d.ts +82 -8
  126. package/dist/net/IpNetwork.d.ts.map +1 -1
  127. package/dist/net/IpNetwork.js +60 -4
  128. package/dist/net/IpNetwork.js.map +1 -1
  129. package/dist/net/NetAddress.d.ts +388 -35
  130. package/dist/net/NetAddress.d.ts.map +1 -1
  131. package/dist/net/NetAddress.js +350 -34
  132. package/dist/net/NetAddress.js.map +1 -1
  133. package/dist/net/index.d.ts +15 -0
  134. package/dist/net/index.d.ts.map +1 -1
  135. package/dist/net/index.js +15 -0
  136. package/dist/net/index.js.map +1 -1
  137. package/dist/observability/OtlpMetrics.d.ts.map +1 -1
  138. package/dist/observability/OtlpMetrics.js +15 -21
  139. package/dist/observability/OtlpMetrics.js.map +1 -1
  140. package/dist/observability/PrometheusMetrics.js +1 -0
  141. package/dist/observability/PrometheusMetrics.js.map +1 -1
  142. package/dist/persistence/PersistedQueue.d.ts +32 -3
  143. package/dist/persistence/PersistedQueue.d.ts.map +1 -1
  144. package/dist/persistence/PersistedQueue.js +75 -16
  145. package/dist/persistence/PersistedQueue.js.map +1 -1
  146. package/dist/rpc/RpcClient.d.ts +22 -6
  147. package/dist/rpc/RpcClient.d.ts.map +1 -1
  148. package/dist/rpc/RpcClient.js +12 -5
  149. package/dist/rpc/RpcClient.js.map +1 -1
  150. package/dist/rpc/RpcServer.d.ts +6 -0
  151. package/dist/rpc/RpcServer.d.ts.map +1 -1
  152. package/dist/rpc/RpcServer.js +42 -20
  153. package/dist/rpc/RpcServer.js.map +1 -1
  154. package/dist/socket/DatagramSocket.d.ts +456 -0
  155. package/dist/socket/DatagramSocket.d.ts.map +1 -0
  156. package/dist/socket/DatagramSocket.js +535 -0
  157. package/dist/socket/DatagramSocket.js.map +1 -0
  158. package/dist/socket/Socket.d.ts +14 -1
  159. package/dist/socket/Socket.d.ts.map +1 -1
  160. package/dist/socket/Socket.js +9 -1
  161. package/dist/socket/Socket.js.map +1 -1
  162. package/dist/socket/index.d.ts +5 -0
  163. package/dist/socket/index.d.ts.map +1 -1
  164. package/dist/socket/index.js +5 -0
  165. package/dist/socket/index.js.map +1 -1
  166. package/dist/sql/Migrator.d.ts.map +1 -1
  167. package/dist/sql/Migrator.js +7 -2
  168. package/dist/sql/Migrator.js.map +1 -1
  169. package/dist/sql/SqlClient.d.ts +7 -1
  170. package/dist/sql/SqlClient.d.ts.map +1 -1
  171. package/dist/sql/SqlClient.js +31 -6
  172. package/dist/sql/SqlClient.js.map +1 -1
  173. package/dist/testing/TestCrypto.d.ts +73 -0
  174. package/dist/testing/TestCrypto.d.ts.map +1 -0
  175. package/dist/testing/TestCrypto.js +87 -0
  176. package/dist/testing/TestCrypto.js.map +1 -0
  177. package/dist/testing/index.d.ts +5 -0
  178. package/dist/testing/index.d.ts.map +1 -1
  179. package/dist/testing/index.js +5 -0
  180. package/dist/testing/index.js.map +1 -1
  181. package/dist/workflow/DurableDeferred.d.ts +54 -0
  182. package/dist/workflow/DurableDeferred.d.ts.map +1 -1
  183. package/dist/workflow/DurableDeferred.js +78 -49
  184. package/dist/workflow/DurableDeferred.js.map +1 -1
  185. package/dist/workflow/WorkflowEngine.d.ts.map +1 -1
  186. package/dist/workflow/WorkflowEngine.js +2 -1
  187. package/dist/workflow/WorkflowEngine.js.map +1 -1
  188. package/package.json +1 -1
  189. package/src/Context.ts +3 -3
  190. package/src/Crypto.ts +43 -9
  191. package/src/DateTime.ts +9 -6
  192. package/src/Duration.ts +36 -16
  193. package/src/FileSystem.ts +48 -2
  194. package/src/Schema.ts +669 -5
  195. package/src/Stdio.ts +9 -2
  196. package/src/Stream.ts +11 -11
  197. package/src/ai/McpServer.ts +63 -23
  198. package/src/ai/internal/mcpProtocol/v2026_07_28.ts +5 -0
  199. package/src/ai/internal/mcpProtocol.ts +3 -0
  200. package/src/ai/internal/mcpRuntime.ts +2 -0
  201. package/src/cli/CliOutput.ts +33 -16
  202. package/src/cli/Command.ts +4 -3
  203. package/src/cli/Completions.ts +9 -6
  204. package/src/cli/GlobalFlag.ts +19 -11
  205. package/src/cli/Prompt.ts +159 -149
  206. package/src/cli/internal/ansi.ts +26 -3
  207. package/src/cli/internal/completions/powershell.ts +322 -0
  208. package/src/cli/internal/completions/zsh.ts +4 -2
  209. package/src/cli/internal/wizard.ts +34 -26
  210. package/src/cluster/ClusterSchema.ts +32 -0
  211. package/src/cluster/ClusterWorkflowEngine.ts +13 -24
  212. package/src/cluster/MessageStorage.ts +45 -14
  213. package/src/cluster/Runners.ts +8 -2
  214. package/src/cluster/Sharding.ts +207 -49
  215. package/src/cluster/SqlMessageStorage.ts +118 -84
  216. package/src/cluster/SqlRunnerStorage.ts +224 -128
  217. package/src/cluster/internal/entityManager.ts +151 -55
  218. package/src/http/FindMyWay/internal/router.ts +4 -7
  219. package/src/http/HttpClient.ts +56 -2
  220. package/src/http/HttpTraceContext.ts +8 -2
  221. package/src/internal/effect.ts +15 -13
  222. package/src/internal/version.ts +1 -1
  223. package/src/net/AddressResolver.ts +222 -0
  224. package/src/net/Dns.ts +1035 -0
  225. package/src/net/Host.ts +472 -0
  226. package/src/net/IpInterface.ts +117 -7
  227. package/src/net/IpNetwork.ts +116 -17
  228. package/src/net/NetAddress.ts +611 -76
  229. package/src/net/index.ts +18 -0
  230. package/src/observability/OtlpMetrics.ts +12 -23
  231. package/src/observability/PrometheusMetrics.ts +1 -0
  232. package/src/persistence/PersistedQueue.ts +146 -53
  233. package/src/rpc/RpcClient.ts +41 -19
  234. package/src/rpc/RpcServer.ts +60 -25
  235. package/src/socket/DatagramSocket.ts +919 -0
  236. package/src/socket/Socket.ts +22 -2
  237. package/src/socket/index.ts +6 -0
  238. package/src/sql/Migrator.ts +21 -5
  239. package/src/sql/SqlClient.ts +39 -15
  240. package/src/testing/TestCrypto.ts +94 -0
  241. package/src/testing/index.ts +6 -0
  242. package/src/workflow/DurableDeferred.ts +123 -48
  243. package/src/workflow/WorkflowEngine.ts +2 -1
@@ -2,9 +2,9 @@ import * as Data from "../Data.js";
2
2
  import * as Equal from "../Equal.js";
3
3
  import { dual } from "../Function.js";
4
4
  import * as Hash from "../Hash.js";
5
- import { NodeInspectSymbol } from "../Inspectable.js";
5
+ import * as Inspectable from "../Inspectable.js";
6
6
  import * as Option from "../Option.js";
7
- import { hasProperty } from "../Predicate.js";
7
+ import { hasProperty, isTupleOf } from "../Predicate.js";
8
8
  import * as Result from "../Result.js";
9
9
  const TypeId = "~effect/net/NetAddress";
10
10
  const MulticastTypeId = "~effect/net/NetAddress/MulticastAddress";
@@ -71,6 +71,32 @@ export const isIpAddress = u => isIpv4Address(u) || isIpv6Address(u);
71
71
  * @since 4.0.0
72
72
  */
73
73
  export const width = address => isIpv4Address(address) ? 32 : 128;
74
+ /**
75
+ * Returns the family of an IP address or internet address.
76
+ *
77
+ * **Example** (Reading address families)
78
+ *
79
+ * ```ts import.meta.vitest
80
+ * import { NetAddress } from "effect/net"
81
+ *
82
+ * NetAddress.familyOf(NetAddress.ipv4Loopback) // => "IPv4"
83
+ * NetAddress.familyOf(NetAddress.inetAddressFromStringUnsafe("[::1]:80")) // => "IPv6"
84
+ * ```
85
+ *
86
+ * @stability experimental
87
+ * @category getters
88
+ * @since 4.0.0
89
+ */
90
+ export const familyOf = self => isIpv4Address(self) || isInetAddressV4(self) ? "IPv4" : "IPv6";
91
+ /**
92
+ * Returns `true` when an IP address or internet address belongs to a family,
93
+ * narrowing it to that family.
94
+ *
95
+ * @stability experimental
96
+ * @category predicates
97
+ * @since 4.0.0
98
+ */
99
+ export const isFamily = /*#__PURE__*/dual(2, (self, family) => familyOf(self) === family);
74
100
  /**
75
101
  * Returns `true` when a value is a MAC address.
76
102
  *
@@ -120,6 +146,7 @@ export const isUnixPathAddress = u => isAddress(u) && u._tag === "UnixPathAddres
120
146
  */
121
147
  export const isSocketAddress = u => isInetAddress(u) || isUnixPathAddress(u);
122
148
  const Ipv4Proto = {
149
+ ...Inspectable.BaseProto,
123
150
  _tag: "Ipv4Address",
124
151
  [TypeId]: TypeId,
125
152
  [Equal.symbol](that) {
@@ -133,12 +160,10 @@ const Ipv4Proto = {
133
160
  },
134
161
  toJSON() {
135
162
  return this.toString();
136
- },
137
- [NodeInspectSymbol]() {
138
- return this.toJSON();
139
163
  }
140
164
  };
141
165
  const Ipv6Proto = {
166
+ ...Inspectable.BaseProto,
142
167
  _tag: "Ipv6Address",
143
168
  [TypeId]: TypeId,
144
169
  [Equal.symbol](that) {
@@ -159,12 +184,10 @@ const Ipv6Proto = {
159
184
  },
160
185
  toJSON() {
161
186
  return this.toString();
162
- },
163
- [NodeInspectSymbol]() {
164
- return this.toJSON();
165
187
  }
166
188
  };
167
189
  const MacProto = {
190
+ ...Inspectable.BaseProto,
168
191
  _tag: "MacAddress",
169
192
  [TypeId]: TypeId,
170
193
  [Equal.symbol](that) {
@@ -178,9 +201,6 @@ const MacProto = {
178
201
  },
179
202
  toJSON() {
180
203
  return this.toString();
181
- },
182
- [NodeInspectSymbol]() {
183
- return this.toJSON();
184
204
  }
185
205
  };
186
206
  const bytesEqual = (self, that) => {
@@ -275,6 +295,14 @@ const addressError = (input, message) => Result.fail(new NetAddressError({
275
295
  input,
276
296
  message
277
297
  }));
298
+ // Checks by index because `every` skips holes in sparse arrays.
299
+ const allIntegersInRange = (values, max) => {
300
+ for (let i = 0; i < values.length; i++) {
301
+ const n = values[i];
302
+ if (!Number.isInteger(n) || n < 0 || n > max) return false;
303
+ }
304
+ return true;
305
+ };
278
306
  /**
279
307
  * Creates an IPv4 address from four checked octets.
280
308
  *
@@ -283,7 +311,7 @@ const addressError = (input, message) => Result.fail(new NetAddressError({
283
311
  * @since 4.0.0
284
312
  */
285
313
  export const ipv4FromOctets = octets => {
286
- if (!octets.every(n => Number.isInteger(n) && n >= 0 && n <= 255)) {
314
+ if (!allIntegersInRange(octets, 255)) {
287
315
  return addressError(octets, "octets must be integers from 0 through 255");
288
316
  }
289
317
  return Result.succeed(makeIpv4(packOctets(octets[0], octets[1], octets[2], octets[3])));
@@ -296,7 +324,7 @@ export const ipv4FromOctets = octets => {
296
324
  * @since 4.0.0
297
325
  */
298
326
  export const ipv6FromSegments = segments => {
299
- if (!segments.every(n => Number.isInteger(n) && n >= 0 && n <= 0xffff)) {
327
+ if (!allIntegersInRange(segments, 0xffff)) {
300
328
  return addressError(segments, "segments must be integers from 0 through 65535");
301
329
  }
302
330
  return Result.succeed(makeIpv6(segments[0] * 0x10000 + segments[1], segments[2] * 0x10000 + segments[3], segments[4] * 0x10000 + segments[5], segments[6] * 0x10000 + segments[7]));
@@ -309,7 +337,7 @@ export const ipv6FromSegments = segments => {
309
337
  * @since 4.0.0
310
338
  */
311
339
  export const macAddressFromOctets = octets => {
312
- if (!octets.every(n => Number.isInteger(n) && n >= 0 && n <= 255)) {
340
+ if (!allIntegersInRange(octets, 255)) {
313
341
  return addressError(octets, "octets must be integers from 0 through 255");
314
342
  }
315
343
  return Result.succeed(makeMac(new Uint8Array(octets)));
@@ -335,6 +363,29 @@ export const macAddressFromString = input => {
335
363
  * @since 4.0.0
336
364
  */
337
365
  export const macAddressFromStringUnsafe = input => Result.getOrThrow(macAddressFromString(input));
366
+ /**
367
+ * Converts a `MacAddressInput` to a MAC address, parsing strings like
368
+ * `macAddressFromString`, checking octets like `macAddressFromOctets`, and
369
+ * returning MAC addresses unchanged.
370
+ *
371
+ * @stability unstable
372
+ * @category constructors
373
+ * @since 4.0.0
374
+ */
375
+ export const macAddressFromInput = input => {
376
+ if (isMacAddress(input)) return Result.succeed(input);
377
+ if (typeof input === "string") return macAddressFromString(input);
378
+ if (Array.isArray(input) && isTupleOf(input, 6)) return macAddressFromOctets(input);
379
+ return addressError(input, "expected a MAC address, string, or 6 octets");
380
+ };
381
+ /**
382
+ * Converts a trusted `MacAddressInput` to a MAC address, throwing on failure.
383
+ *
384
+ * @stability unstable
385
+ * @category unsafe
386
+ * @since 4.0.0
387
+ */
388
+ export const macAddressFromInputUnsafe = input => Result.getOrThrow(macAddressFromInput(input));
338
389
  /**
339
390
  * Parses a strict dotted-decimal IPv4 address.
340
391
  *
@@ -426,6 +477,127 @@ export const ipFromString = input => {
426
477
  * @since 4.0.0
427
478
  */
428
479
  export const ipFromStringUnsafe = input => Result.getOrThrow(ipFromString(input));
480
+ /**
481
+ * Converts an `IpAddressInput` to an IP address, returning IP addresses
482
+ * unchanged.
483
+ *
484
+ * **Details**
485
+ *
486
+ * Strings are parsed like `ipFromString`. Four octets or bytes make an IPv4
487
+ * address, and eight segments or sixteen bytes make an IPv6 address.
488
+ *
489
+ * **Example** (Converting IP address inputs)
490
+ *
491
+ * ```ts import.meta.vitest
492
+ * import { Result } from "effect"
493
+ * import { NetAddress } from "effect/net"
494
+ *
495
+ * const address = Result.getOrThrow(NetAddress.ipFromInput("192.0.2.1"))
496
+ * NetAddress.formatIp(address) // => "192.0.2.1"
497
+ * Result.getOrThrow(NetAddress.ipFromInput(address)) === address // => true
498
+ * NetAddress.formatIp(Result.getOrThrow(NetAddress.ipFromInput([192, 0, 2, 1]))) // => "192.0.2.1"
499
+ * Result.isFailure(NetAddress.ipFromInput("example.com")) // => true
500
+ * ```
501
+ *
502
+ * @stability unstable
503
+ * @category constructors
504
+ * @since 4.0.0
505
+ */
506
+ export const ipFromInput = input => {
507
+ if (isIpAddress(input)) return Result.succeed(input);
508
+ if (typeof input === "string") return ipFromString(input);
509
+ if (input instanceof Uint8Array && input.length === 4) return Result.succeed(ipv4FromBytesUnsafe(input));
510
+ if (input instanceof Uint8Array && input.length === 16) return Result.succeed(ipv6FromBytesUnsafe(input));
511
+ if (Array.isArray(input) && isTupleOf(input, 4)) return ipv4FromOctets(input);
512
+ if (Array.isArray(input) && isTupleOf(input, 8)) return ipv6FromSegments(input);
513
+ return addressError(input, "expected an IP address, string, 4 octets, 8 segments, or 4 or 16 bytes");
514
+ };
515
+ /**
516
+ * Converts a trusted `IpAddressInput` to an IP address, throwing on failure.
517
+ *
518
+ * @stability unstable
519
+ * @category unsafe
520
+ * @since 4.0.0
521
+ */
522
+ export const ipFromInputUnsafe = input => Result.getOrThrow(ipFromInput(input));
523
+ /**
524
+ * Converts an `Ipv4AddressInput` to an IPv4 address, parsing strings like
525
+ * `ipv4FromString`, checking octets like `ipv4FromOctets`, and returning IPv4
526
+ * addresses unchanged.
527
+ *
528
+ * @stability unstable
529
+ * @category constructors
530
+ * @since 4.0.0
531
+ */
532
+ export const ipv4FromInput = input => {
533
+ if (isIpv4Address(input)) return Result.succeed(input);
534
+ if (typeof input === "string") return ipv4FromString(input);
535
+ if (input instanceof Uint8Array && input.length === 4) return Result.succeed(ipv4FromBytesUnsafe(input));
536
+ if (Array.isArray(input) && isTupleOf(input, 4)) return ipv4FromOctets(input);
537
+ return addressError(input, "expected an IPv4 address, string, 4 octets, or 4 bytes");
538
+ };
539
+ /**
540
+ * Converts an `Ipv6AddressInput` to an IPv6 address, parsing strings like
541
+ * `ipv6FromString`, checking segments like `ipv6FromSegments`, and returning
542
+ * IPv6 addresses unchanged.
543
+ *
544
+ * @stability unstable
545
+ * @category constructors
546
+ * @since 4.0.0
547
+ */
548
+ export const ipv6FromInput = input => {
549
+ if (isIpv6Address(input)) return Result.succeed(input);
550
+ if (typeof input === "string") return ipv6FromString(input);
551
+ if (input instanceof Uint8Array && input.length === 16) return Result.succeed(ipv6FromBytesUnsafe(input));
552
+ if (Array.isArray(input) && isTupleOf(input, 8)) return ipv6FromSegments(input);
553
+ return addressError(input, "expected an IPv6 address, string, 8 segments, or 16 bytes");
554
+ };
555
+ /**
556
+ * Returns `true` when a value is a canonical scoped IPv6 literal.
557
+ *
558
+ * @stability experimental
559
+ * @category guards
560
+ * @since 4.0.0
561
+ */
562
+ export const isScopedIpv6Literal = u => {
563
+ if (typeof u !== "string" || !u.includes("%")) return false;
564
+ const result = scopedIpv6LiteralFromString(u);
565
+ return Result.isSuccess(result) && result.success === u;
566
+ };
567
+ /**
568
+ * Parses an IPv6 literal with a numeric or named zone, such as `fe80::1%eth0`.
569
+ *
570
+ * @stability experimental
571
+ * @category decoding
572
+ * @since 4.0.0
573
+ */
574
+ export const scopedIpv6LiteralFromString = input => {
575
+ const separator = input.indexOf("%");
576
+ if (separator === -1) return addressError(input, "expected an IPv6 zone");
577
+ let zone = input.slice(separator + 1);
578
+ if (zone.length === 0 || /[%[\]/\s\p{Cc}]/u.test(zone)) {
579
+ return addressError(input, "invalid IPv6 scope identifier");
580
+ }
581
+ if (/^\d+$/.test(zone)) {
582
+ const scopeId = Number(zone);
583
+ if (scopeId > 0xffffffff) return addressError(input, "scope identifier must be an unsigned 32-bit integer");
584
+ zone = String(scopeId);
585
+ }
586
+ return Result.map(ipv6FromString(input.slice(0, separator)), address => `${formatIp(address)}%${zone}`);
587
+ };
588
+ /**
589
+ * Converts a `ScopedIpv6LiteralInput` to a scoped IPv6 literal, parsing it
590
+ * like `scopedIpv6LiteralFromString`.
591
+ *
592
+ * **Details**
593
+ *
594
+ * Scoped IPv6 literals are strings, so every input is parsed.
595
+ *
596
+ * @stability experimental
597
+ * @category constructors
598
+ * @since 4.0.0
599
+ */
600
+ export const scopedIpv6LiteralFromInput = input => scopedIpv6LiteralFromString(input);
429
601
  /**
430
602
  * Returns the four numeric octets of an IPv4 address in a fresh tuple.
431
603
  *
@@ -738,6 +910,7 @@ export function toCanonical(self) {
738
910
  return isIpv6Address(self) ? Option.getOrElse(fromIpv4Mapped(self), () => self) : self;
739
911
  }
740
912
  const InetV4Proto = {
913
+ ...Inspectable.BaseProto,
741
914
  _tag: "InetAddressV4",
742
915
  [TypeId]: TypeId,
743
916
  [Equal.symbol](that) {
@@ -751,12 +924,10 @@ const InetV4Proto = {
751
924
  },
752
925
  toJSON() {
753
926
  return this.toString();
754
- },
755
- [NodeInspectSymbol]() {
756
- return this.toJSON();
757
927
  }
758
928
  };
759
929
  const InetV6Proto = {
930
+ ...Inspectable.BaseProto,
760
931
  _tag: "InetAddressV6",
761
932
  [TypeId]: TypeId,
762
933
  [Equal.symbol](that) {
@@ -770,9 +941,6 @@ const InetV6Proto = {
770
941
  },
771
942
  toJSON() {
772
943
  return this.toString();
773
- },
774
- [NodeInspectSymbol]() {
775
- return this.toJSON();
776
944
  }
777
945
  };
778
946
  const checkPort = port => Number.isInteger(port) && port >= 0 && port <= 0xffff;
@@ -857,6 +1025,103 @@ export const inetAddressFromIpString = (address, port) => {
857
1025
  * @since 4.0.0
858
1026
  */
859
1027
  export const inetAddressFromIpStringUnsafe = (address, port) => Result.getOrThrow(inetAddressFromIpString(address, port));
1028
+ /**
1029
+ * Creates an internet address from a trusted native numeric host and port.
1030
+ * Named IPv6 zones are resolved using the supplied interface-to-scope map.
1031
+ * Use only for runtime-supplied socket addresses: this skips input validation,
1032
+ * so malformed strings or ports may silently produce incorrect values. An
1033
+ * unknown named IPv6 zone throws rather than losing its scope.
1034
+ *
1035
+ * @stability unstable
1036
+ * @category unsafe
1037
+ * @since 4.0.0
1038
+ */
1039
+ export const inetAddressFromNativeUnsafe = (host, port, scopeIds) => {
1040
+ const zoneStart = host.indexOf("%");
1041
+ const end = zoneStart === -1 ? host.length : zoneStart;
1042
+ if (host.indexOf(":") === -1) {
1043
+ const self = Object.create(InetV4Proto);
1044
+ self.address = makeIpv4(parseNativeIpv4(host, 0, end));
1045
+ self.port = port;
1046
+ return Object.freeze(self);
1047
+ }
1048
+ let scopeId = 0;
1049
+ if (zoneStart !== -1) {
1050
+ const zone = host.slice(zoneStart + 1);
1051
+ const resolved = numericZone.test(zone) ? Number(zone) : scopeIds?.get(zone);
1052
+ if (resolved === undefined) throw new Error(`unknown IPv6 interface: ${zone}`);
1053
+ scopeId = resolved;
1054
+ }
1055
+ let w0 = 0;
1056
+ let w1 = 0;
1057
+ let w2 = 0;
1058
+ let w3 = 0;
1059
+ let segment = 0;
1060
+ let i = 0;
1061
+ while (i < end) {
1062
+ if (host.charCodeAt(i) === 58) {
1063
+ // The rest of a compressed address is anchored at the last segment.
1064
+ i += 2;
1065
+ if (i === end) break;
1066
+ let remaining = 1;
1067
+ for (let j = i; j < end; j++) {
1068
+ if (host.charCodeAt(j) === 58) remaining++;
1069
+ }
1070
+ const dot = host.indexOf(".", i);
1071
+ if (dot !== -1 && dot < end) remaining++;
1072
+ segment = 8 - remaining;
1073
+ }
1074
+ const start = i;
1075
+ let value = 0;
1076
+ while (i < end) {
1077
+ const ch = host.charCodeAt(i);
1078
+ if (ch === 58 || ch === 46) break;
1079
+ value = value << 4 | (ch <= 57 ? ch - 48 : (ch & 0x5f) - 55);
1080
+ i++;
1081
+ }
1082
+ if (i < end && host.charCodeAt(i) === 46) {
1083
+ w3 = parseNativeIpv4(host, start, end);
1084
+ break;
1085
+ }
1086
+ // even segments fill the high half of their 32-bit word
1087
+ const shifted = value << (1 - (segment & 1)) * 16;
1088
+ switch (segment >>> 1) {
1089
+ case 0:
1090
+ w0 |= shifted;
1091
+ break;
1092
+ case 1:
1093
+ w1 |= shifted;
1094
+ break;
1095
+ case 2:
1096
+ w2 |= shifted;
1097
+ break;
1098
+ default:
1099
+ w3 |= shifted;
1100
+ }
1101
+ segment++;
1102
+ if (i < end && host.charCodeAt(i + 1) !== 58) i++;
1103
+ }
1104
+ const self = Object.create(InetV6Proto);
1105
+ self.address = makeIpv6(w0, w1, w2, w3);
1106
+ self.port = port;
1107
+ self.scopeId = scopeId;
1108
+ return Object.freeze(self);
1109
+ };
1110
+ const numericZone = /^\d+$/;
1111
+ const parseNativeIpv4 = (host, start, end) => {
1112
+ let value = 0;
1113
+ let octet = 0;
1114
+ for (let i = start; i < end; i++) {
1115
+ const ch = host.charCodeAt(i);
1116
+ if (ch === 46) {
1117
+ value = value << 8 | octet;
1118
+ octet = 0;
1119
+ } else {
1120
+ octet = octet * 10 + ch - 48;
1121
+ }
1122
+ }
1123
+ return (value << 8 | octet) >>> 0;
1124
+ };
860
1125
  /**
861
1126
  * Parses an unbracketed numeric host and port, resolving named IPv6 zones using
862
1127
  * a supplied map of interface names to numeric scope IDs.
@@ -889,6 +1154,29 @@ export const inetAddressFromHostString = (host, port, scopeIds) => {
889
1154
  }
890
1155
  return inetAddressFromString(host.includes(":") ? `[${host}]:${port}` : `${host}:${port}`);
891
1156
  };
1157
+ /**
1158
+ * Returns the IPv6 scope ID of a network interface from its addresses.
1159
+ *
1160
+ * **Details**
1161
+ *
1162
+ * The first IPv6 address with a positive scope ID supplies the result. Accepts
1163
+ * the addresses of one interface, such as `os.networkInterfaces()[name]` or the
1164
+ * entries of `Deno.networkInterfaces()` with that name, without performing any
1165
+ * operating-system lookup itself.
1166
+ *
1167
+ * @see {@link scopeIdsFromInterfaces} for mapping every interface at once
1168
+ * @stability experimental
1169
+ * @category converting
1170
+ * @since 4.0.0
1171
+ */
1172
+ export const scopeIdFromInterface = addresses => {
1173
+ for (const address of addresses ?? []) {
1174
+ if (address.family === "IPv6" && typeof address.scopeid === "number" && address.scopeid > 0) {
1175
+ return Option.some(address.scopeid);
1176
+ }
1177
+ }
1178
+ return Option.none();
1179
+ };
892
1180
  /**
893
1181
  * Creates a map from interface names to IPv6 scope IDs using supplied interface
894
1182
  * entries.
@@ -909,8 +1197,8 @@ export const inetAddressFromHostString = (host, port, scopeIds) => {
909
1197
  export const scopeIdsFromInterfaces = interfaces => {
910
1198
  const scopeIds = new Map();
911
1199
  for (const [name, addresses] of interfaces) {
912
- const address = addresses?.find(address => address.family === "IPv6" && (address.scopeid ?? 0) > 0);
913
- if (address?.scopeid !== undefined) scopeIds.set(name, address.scopeid);
1200
+ const scopeId = scopeIdFromInterface(addresses);
1201
+ if (Option.isSome(scopeId)) scopeIds.set(name, scopeId.value);
914
1202
  }
915
1203
  return scopeIds;
916
1204
  };
@@ -976,6 +1264,40 @@ export const inetAddressFromString = input => {
976
1264
  * @since 4.0.0
977
1265
  */
978
1266
  export const inetAddressFromStringUnsafe = input => Result.getOrThrow(inetAddressFromString(input));
1267
+ /**
1268
+ * Converts an `InetAddressInput` to an internet address, parsing strings like
1269
+ * `inetAddressFromString`, converting parts like `inetAddressV4` and
1270
+ * `inetAddressV6`, and returning internet addresses unchanged.
1271
+ *
1272
+ * @stability unstable
1273
+ * @category constructors
1274
+ * @since 4.0.0
1275
+ */
1276
+ export const inetAddressFromInput = input => {
1277
+ if (isInetAddress(input)) return Result.succeed(input);
1278
+ if (typeof input === "string") return inetAddressFromString(input);
1279
+ if (!hasProperty(input, "address") || !hasProperty(input, "port")) {
1280
+ return addressError(input, "expected an address and port");
1281
+ }
1282
+ const {
1283
+ port,
1284
+ scopeId
1285
+ } = input;
1286
+ return Result.flatMap(ipFromInput(input.address), address => {
1287
+ if (isIpv6Address(address)) return inetAddressV6(address, port, {
1288
+ scopeId
1289
+ });
1290
+ return (scopeId ?? 0) === 0 ? inetAddressV4(address, port) : addressError(input, "scopeId requires an IPv6 address");
1291
+ });
1292
+ };
1293
+ /**
1294
+ * Converts a trusted `InetAddressInput` to an internet address, throwing on failure.
1295
+ *
1296
+ * @stability unstable
1297
+ * @category unsafe
1298
+ * @since 4.0.0
1299
+ */
1300
+ export const inetAddressFromInputUnsafe = input => Result.getOrThrow(inetAddressFromInput(input));
979
1301
  /**
980
1302
  * Formats the numeric host of an internet address without brackets or a port,
981
1303
  * preserving a nonzero IPv6 scope ID as a `%` suffix.
@@ -1137,6 +1459,7 @@ export const formatUrlUnsafe = (self, scheme = "http") => Result.getOrThrow(form
1137
1459
  */
1138
1460
  export const formatUrlHostString = host => host.includes(":") && !host.startsWith("[") ? `[${host}]` : host;
1139
1461
  const UnixPathProto = {
1462
+ ...Inspectable.BaseProto,
1140
1463
  _tag: "UnixPathAddress",
1141
1464
  [TypeId]: TypeId,
1142
1465
  [Equal.symbol](that) {
@@ -1150,9 +1473,6 @@ const UnixPathProto = {
1150
1473
  },
1151
1474
  toJSON() {
1152
1475
  return this.toString();
1153
- },
1154
- [NodeInspectSymbol]() {
1155
- return this.toJSON();
1156
1476
  }
1157
1477
  };
1158
1478
  /**
@@ -1185,24 +1505,20 @@ export const formatUnixPath = self => `unix://${self.path}`;
1185
1505
  *
1186
1506
  * **Details**
1187
1507
  *
1188
- * Numeric IP strings are parsed without hostname resolution. Invalid IP
1189
- * literals, ports, and input shapes return a `NetAddressError`.
1508
+ * Internet addresses are converted like `inetAddressFromInput`, without
1509
+ * hostname resolution. Invalid IP literals, ports, and input shapes return a
1510
+ * `NetAddressError`.
1190
1511
  *
1191
1512
  * @stability unstable
1192
1513
  * @category constructors
1193
1514
  * @since 4.0.0
1194
1515
  */
1195
1516
  export const socketAddressFromInput = input => {
1196
- if (isSocketAddress(input)) return Result.succeed(input);
1197
- if (typeof input === "string") return inetAddressFromString(input);
1517
+ if (isUnixPathAddress(input)) return Result.succeed(input);
1198
1518
  if (hasProperty(input, "path")) {
1199
1519
  return typeof input.path === "string" ? Result.succeed(unixPathAddress(input.path)) : addressError(input, "path must be a string");
1200
1520
  }
1201
- if (!hasProperty(input, "address") || !hasProperty(input, "port")) {
1202
- return addressError(input, "expected an address and port or a Unix path");
1203
- }
1204
- const address = typeof input.address === "string" ? ipFromString(input.address) : isIpAddress(input.address) ? Result.succeed(input.address) : addressError(input, "address must be an IP address or numeric IP string");
1205
- return Result.flatMap(address, address => inetAddress(address, input.port));
1521
+ return inetAddressFromInput(input);
1206
1522
  };
1207
1523
  /**
1208
1524
  * Converts a trusted `SocketAddress.Input` to a concrete socket address,