effect 4.0.2 → 4.0.4

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 (389) hide show
  1. package/AGENTS.md +24 -0
  2. package/CLAUDE.md +24 -0
  3. package/ai-docs/package.json +2 -2
  4. package/ai-docs/src/52_graphql/10_basics.ts +111 -0
  5. package/ai-docs/src/52_graphql/20_testing.ts +45 -0
  6. package/ai-docs/src/52_graphql/30_batching.ts +116 -0
  7. package/ai-docs/src/52_graphql/40_aliased-batching.ts +122 -0
  8. package/ai-docs/src/52_graphql/50_errors-and-retries.ts +74 -0
  9. package/ai-docs/src/52_graphql/index.md +6 -0
  10. package/dist/Context.d.ts.map +1 -1
  11. package/dist/Context.js +12 -3
  12. package/dist/Context.js.map +1 -1
  13. package/dist/Crypto.d.ts +33 -5
  14. package/dist/Crypto.d.ts.map +1 -1
  15. package/dist/Crypto.js +8 -2
  16. package/dist/Crypto.js.map +1 -1
  17. package/dist/DateTime.d.ts +9 -6
  18. package/dist/DateTime.d.ts.map +1 -1
  19. package/dist/DateTime.js +9 -6
  20. package/dist/DateTime.js.map +1 -1
  21. package/dist/Duration.d.ts +6 -6
  22. package/dist/Duration.d.ts.map +1 -1
  23. package/dist/Duration.js +27 -8
  24. package/dist/Duration.js.map +1 -1
  25. package/dist/FileSystem.d.ts +44 -2
  26. package/dist/FileSystem.d.ts.map +1 -1
  27. package/dist/FileSystem.js.map +1 -1
  28. package/dist/RequestResolver.d.ts.map +1 -1
  29. package/dist/RequestResolver.js +4 -10
  30. package/dist/RequestResolver.js.map +1 -1
  31. package/dist/Scheduler.d.ts +9 -0
  32. package/dist/Scheduler.d.ts.map +1 -1
  33. package/dist/Scheduler.js +9 -0
  34. package/dist/Scheduler.js.map +1 -1
  35. package/dist/Schema.d.ts +481 -1
  36. package/dist/Schema.d.ts.map +1 -1
  37. package/dist/Schema.js +362 -4
  38. package/dist/Schema.js.map +1 -1
  39. package/dist/SchemaGetter.d.ts +4 -0
  40. package/dist/SchemaGetter.d.ts.map +1 -1
  41. package/dist/SchemaGetter.js +52 -33
  42. package/dist/SchemaGetter.js.map +1 -1
  43. package/dist/Sink.d.ts.map +1 -1
  44. package/dist/Sink.js +38 -17
  45. package/dist/Sink.js.map +1 -1
  46. package/dist/Stdio.d.ts +7 -1
  47. package/dist/Stdio.d.ts.map +1 -1
  48. package/dist/Stdio.js +1 -0
  49. package/dist/Stdio.js.map +1 -1
  50. package/dist/Stream.d.ts +22 -11
  51. package/dist/Stream.d.ts.map +1 -1
  52. package/dist/Stream.js +21 -6
  53. package/dist/Stream.js.map +1 -1
  54. package/dist/Utils.js +8 -3
  55. package/dist/Utils.js.map +1 -1
  56. package/dist/ai/AnthropicStructuredOutput.js +0 -2
  57. package/dist/ai/AnthropicStructuredOutput.js.map +1 -1
  58. package/dist/ai/Chat.d.ts +2 -2
  59. package/dist/ai/Chat.d.ts.map +1 -1
  60. package/dist/ai/LanguageModel.d.ts +38 -7
  61. package/dist/ai/LanguageModel.d.ts.map +1 -1
  62. package/dist/ai/LanguageModel.js +25 -7
  63. package/dist/ai/LanguageModel.js.map +1 -1
  64. package/dist/ai/McpServer.d.ts +61 -0
  65. package/dist/ai/McpServer.d.ts.map +1 -1
  66. package/dist/ai/McpServer.js +196 -44
  67. package/dist/ai/McpServer.js.map +1 -1
  68. package/dist/ai/Prompt.d.ts.map +1 -1
  69. package/dist/ai/Prompt.js +28 -5
  70. package/dist/ai/Prompt.js.map +1 -1
  71. package/dist/ai/Response.d.ts +4 -3
  72. package/dist/ai/Response.d.ts.map +1 -1
  73. package/dist/ai/Response.js.map +1 -1
  74. package/dist/ai/internal/mcpProtocol/v2026_07_28.js +5 -0
  75. package/dist/ai/internal/mcpProtocol/v2026_07_28.js.map +1 -1
  76. package/dist/ai/internal/mcpProtocol.js.map +1 -1
  77. package/dist/ai/internal/mcpRuntime.js +1 -0
  78. package/dist/ai/internal/mcpRuntime.js.map +1 -1
  79. package/dist/cli/CliOutput.d.ts +27 -0
  80. package/dist/cli/CliOutput.d.ts.map +1 -1
  81. package/dist/cli/CliOutput.js +33 -10
  82. package/dist/cli/CliOutput.js.map +1 -1
  83. package/dist/cli/Command.d.ts.map +1 -1
  84. package/dist/cli/Command.js +6 -3
  85. package/dist/cli/Command.js.map +1 -1
  86. package/dist/cli/Completions.d.ts +3 -3
  87. package/dist/cli/Completions.d.ts.map +1 -1
  88. package/dist/cli/Completions.js +8 -5
  89. package/dist/cli/Completions.js.map +1 -1
  90. package/dist/cli/GlobalFlag.d.ts +5 -4
  91. package/dist/cli/GlobalFlag.d.ts.map +1 -1
  92. package/dist/cli/GlobalFlag.js +3 -3
  93. package/dist/cli/GlobalFlag.js.map +1 -1
  94. package/dist/cli/Prompt.d.ts +17 -1
  95. package/dist/cli/Prompt.d.ts.map +1 -1
  96. package/dist/cli/Prompt.js +119 -114
  97. package/dist/cli/Prompt.js.map +1 -1
  98. package/dist/cli/internal/ansi.d.ts +0 -1
  99. package/dist/cli/internal/ansi.d.ts.map +1 -1
  100. package/dist/cli/internal/ansi.js +20 -3
  101. package/dist/cli/internal/ansi.js.map +1 -1
  102. package/dist/cli/internal/completions/powershell.d.ts +2 -0
  103. package/dist/cli/internal/completions/powershell.d.ts.map +1 -0
  104. package/dist/cli/internal/completions/powershell.js +273 -0
  105. package/dist/cli/internal/completions/powershell.js.map +1 -0
  106. package/dist/cli/internal/completions/zsh.js +3 -2
  107. package/dist/cli/internal/completions/zsh.js.map +1 -1
  108. package/dist/cli/internal/wizard.d.ts +3 -3
  109. package/dist/cli/internal/wizard.d.ts.map +1 -1
  110. package/dist/cli/internal/wizard.js +21 -18
  111. package/dist/cli/internal/wizard.js.map +1 -1
  112. package/dist/cluster/ClusterSchema.d.ts +28 -0
  113. package/dist/cluster/ClusterSchema.d.ts.map +1 -1
  114. package/dist/cluster/ClusterSchema.js +30 -0
  115. package/dist/cluster/ClusterSchema.js.map +1 -1
  116. package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
  117. package/dist/cluster/ClusterWorkflowEngine.js +56 -26
  118. package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
  119. package/dist/cluster/MessageStorage.d.ts +18 -3
  120. package/dist/cluster/MessageStorage.d.ts.map +1 -1
  121. package/dist/cluster/MessageStorage.js +31 -11
  122. package/dist/cluster/MessageStorage.js.map +1 -1
  123. package/dist/cluster/Runners.d.ts.map +1 -1
  124. package/dist/cluster/Runners.js +8 -2
  125. package/dist/cluster/Runners.js.map +1 -1
  126. package/dist/cluster/Sharding.d.ts.map +1 -1
  127. package/dist/cluster/Sharding.js +187 -66
  128. package/dist/cluster/Sharding.js.map +1 -1
  129. package/dist/cluster/SqlMessageStorage.d.ts +59 -19
  130. package/dist/cluster/SqlMessageStorage.d.ts.map +1 -1
  131. package/dist/cluster/SqlMessageStorage.js +84 -55
  132. package/dist/cluster/SqlMessageStorage.js.map +1 -1
  133. package/dist/cluster/SqlRunnerStorage.d.ts +68 -19
  134. package/dist/cluster/SqlRunnerStorage.d.ts.map +1 -1
  135. package/dist/cluster/SqlRunnerStorage.js +191 -113
  136. package/dist/cluster/SqlRunnerStorage.js.map +1 -1
  137. package/dist/cluster/internal/entityManager.js +104 -37
  138. package/dist/cluster/internal/entityManager.js.map +1 -1
  139. package/dist/encoding/Sse.d.ts +6 -0
  140. package/dist/encoding/Sse.d.ts.map +1 -1
  141. package/dist/encoding/Sse.js +62 -70
  142. package/dist/encoding/Sse.js.map +1 -1
  143. package/dist/graphql/GraphQL.d.ts +349 -0
  144. package/dist/graphql/GraphQL.d.ts.map +1 -0
  145. package/dist/graphql/GraphQL.js +207 -0
  146. package/dist/graphql/GraphQL.js.map +1 -0
  147. package/dist/graphql/GraphQLClient.d.ts +562 -0
  148. package/dist/graphql/GraphQLClient.d.ts.map +1 -0
  149. package/dist/graphql/GraphQLClient.js +498 -0
  150. package/dist/graphql/GraphQLClient.js.map +1 -0
  151. package/dist/graphql/GraphQLClientError.d.ts +445 -0
  152. package/dist/graphql/GraphQLClientError.d.ts.map +1 -0
  153. package/dist/graphql/GraphQLClientError.js +479 -0
  154. package/dist/graphql/GraphQLClientError.js.map +1 -0
  155. package/dist/graphql/GraphQLGroup.d.ts +118 -0
  156. package/dist/graphql/GraphQLGroup.d.ts.map +1 -0
  157. package/dist/graphql/GraphQLGroup.js +109 -0
  158. package/dist/graphql/GraphQLGroup.js.map +1 -0
  159. package/dist/graphql/GraphQLMiddleware.d.ts +249 -0
  160. package/dist/graphql/GraphQLMiddleware.d.ts.map +1 -0
  161. package/dist/graphql/GraphQLMiddleware.js +130 -0
  162. package/dist/graphql/GraphQLMiddleware.js.map +1 -0
  163. package/dist/graphql/GraphQLProtocol.d.ts +731 -0
  164. package/dist/graphql/GraphQLProtocol.d.ts.map +1 -0
  165. package/dist/graphql/GraphQLProtocol.js +719 -0
  166. package/dist/graphql/GraphQLProtocol.js.map +1 -0
  167. package/dist/graphql/GraphQLResolver.d.ts +453 -0
  168. package/dist/graphql/GraphQLResolver.d.ts.map +1 -0
  169. package/dist/graphql/GraphQLResolver.js +552 -0
  170. package/dist/graphql/GraphQLResolver.js.map +1 -0
  171. package/dist/graphql/index.d.ts +40 -0
  172. package/dist/graphql/index.d.ts.map +1 -0
  173. package/dist/graphql/index.js +41 -0
  174. package/dist/graphql/index.js.map +1 -0
  175. package/dist/http/FindMyWay/internal/router.js +3 -6
  176. package/dist/http/FindMyWay/internal/router.js.map +1 -1
  177. package/dist/http/HttpClient.d.ts +21 -0
  178. package/dist/http/HttpClient.d.ts.map +1 -1
  179. package/dist/http/HttpClient.js +63 -12
  180. package/dist/http/HttpClient.js.map +1 -1
  181. package/dist/http/HttpEffect.d.ts.map +1 -1
  182. package/dist/http/HttpEffect.js +14 -7
  183. package/dist/http/HttpEffect.js.map +1 -1
  184. package/dist/http/HttpMiddleware.d.ts.map +1 -1
  185. package/dist/http/HttpMiddleware.js +31 -32
  186. package/dist/http/HttpMiddleware.js.map +1 -1
  187. package/dist/http/HttpRouter.d.ts +35 -0
  188. package/dist/http/HttpRouter.d.ts.map +1 -1
  189. package/dist/http/HttpRouter.js +35 -0
  190. package/dist/http/HttpRouter.js.map +1 -1
  191. package/dist/http/HttpServerResponse.d.ts +8 -6
  192. package/dist/http/HttpServerResponse.d.ts.map +1 -1
  193. package/dist/http/HttpServerResponse.js +27 -16
  194. package/dist/http/HttpServerResponse.js.map +1 -1
  195. package/dist/http/HttpTraceContext.d.ts.map +1 -1
  196. package/dist/http/HttpTraceContext.js +4 -2
  197. package/dist/http/HttpTraceContext.js.map +1 -1
  198. package/dist/http/Multipart.d.ts.map +1 -1
  199. package/dist/http/Multipart.js +15 -1
  200. package/dist/http/Multipart.js.map +1 -1
  201. package/dist/http-api/HttpApiScalar.d.ts +5 -0
  202. package/dist/http-api/HttpApiScalar.d.ts.map +1 -1
  203. package/dist/http-api/HttpApiScalar.js.map +1 -1
  204. package/dist/internal/dateTime.js +40 -35
  205. package/dist/internal/dateTime.js.map +1 -1
  206. package/dist/internal/effect.js +19 -9
  207. package/dist/internal/effect.js.map +1 -1
  208. package/dist/internal/graphql.d.ts +2 -0
  209. package/dist/internal/graphql.d.ts.map +1 -0
  210. package/dist/internal/graphql.js +195 -0
  211. package/dist/internal/graphql.js.map +1 -0
  212. package/dist/internal/graphqlHeaders.d.ts +4 -0
  213. package/dist/internal/graphqlHeaders.d.ts.map +1 -0
  214. package/dist/internal/graphqlHeaders.js +11 -0
  215. package/dist/internal/graphqlHeaders.js.map +1 -0
  216. package/dist/internal/request.js +20 -1
  217. package/dist/internal/request.js.map +1 -1
  218. package/dist/internal/schema/toCodeDocument.js +4 -1
  219. package/dist/internal/schema/toCodeDocument.js.map +1 -1
  220. package/dist/internal/schema/toJsonSchemaDocument.js +29 -5
  221. package/dist/internal/schema/toJsonSchemaDocument.js.map +1 -1
  222. package/dist/internal/version.js +1 -1
  223. package/dist/net/AddressResolver.d.ts +145 -0
  224. package/dist/net/AddressResolver.d.ts.map +1 -0
  225. package/dist/net/AddressResolver.js +114 -0
  226. package/dist/net/AddressResolver.js.map +1 -0
  227. package/dist/net/Dns.d.ts +596 -0
  228. package/dist/net/Dns.d.ts.map +1 -0
  229. package/dist/net/Dns.js +549 -0
  230. package/dist/net/Dns.js.map +1 -0
  231. package/dist/net/Host.d.ts +369 -0
  232. package/dist/net/Host.d.ts.map +1 -0
  233. package/dist/net/Host.js +397 -0
  234. package/dist/net/Host.js.map +1 -0
  235. package/dist/net/IpInterface.d.ts +76 -3
  236. package/dist/net/IpInterface.d.ts.map +1 -1
  237. package/dist/net/IpInterface.js +53 -4
  238. package/dist/net/IpInterface.js.map +1 -1
  239. package/dist/net/IpNetwork.d.ts +82 -8
  240. package/dist/net/IpNetwork.d.ts.map +1 -1
  241. package/dist/net/IpNetwork.js +60 -4
  242. package/dist/net/IpNetwork.js.map +1 -1
  243. package/dist/net/NetAddress.d.ts +396 -35
  244. package/dist/net/NetAddress.d.ts.map +1 -1
  245. package/dist/net/NetAddress.js +358 -34
  246. package/dist/net/NetAddress.js.map +1 -1
  247. package/dist/net/index.d.ts +15 -0
  248. package/dist/net/index.d.ts.map +1 -1
  249. package/dist/net/index.js +15 -0
  250. package/dist/net/index.js.map +1 -1
  251. package/dist/observability/OtlpMetrics.d.ts.map +1 -1
  252. package/dist/observability/OtlpMetrics.js +15 -21
  253. package/dist/observability/OtlpMetrics.js.map +1 -1
  254. package/dist/observability/PrometheusMetrics.js +1 -0
  255. package/dist/observability/PrometheusMetrics.js.map +1 -1
  256. package/dist/persistence/PersistedQueue.d.ts +32 -3
  257. package/dist/persistence/PersistedQueue.d.ts.map +1 -1
  258. package/dist/persistence/PersistedQueue.js +75 -16
  259. package/dist/persistence/PersistedQueue.js.map +1 -1
  260. package/dist/rpc/RpcClient.d.ts +22 -6
  261. package/dist/rpc/RpcClient.d.ts.map +1 -1
  262. package/dist/rpc/RpcClient.js +12 -5
  263. package/dist/rpc/RpcClient.js.map +1 -1
  264. package/dist/rpc/RpcServer.d.ts +6 -0
  265. package/dist/rpc/RpcServer.d.ts.map +1 -1
  266. package/dist/rpc/RpcServer.js +78 -29
  267. package/dist/rpc/RpcServer.js.map +1 -1
  268. package/dist/socket/DatagramSocket.d.ts +456 -0
  269. package/dist/socket/DatagramSocket.d.ts.map +1 -0
  270. package/dist/socket/DatagramSocket.js +535 -0
  271. package/dist/socket/DatagramSocket.js.map +1 -0
  272. package/dist/socket/Socket.d.ts +20 -1
  273. package/dist/socket/Socket.d.ts.map +1 -1
  274. package/dist/socket/Socket.js +9 -1
  275. package/dist/socket/Socket.js.map +1 -1
  276. package/dist/socket/index.d.ts +5 -0
  277. package/dist/socket/index.d.ts.map +1 -1
  278. package/dist/socket/index.js +5 -0
  279. package/dist/socket/index.js.map +1 -1
  280. package/dist/sql/Migrator.d.ts.map +1 -1
  281. package/dist/sql/Migrator.js +7 -2
  282. package/dist/sql/Migrator.js.map +1 -1
  283. package/dist/sql/SqlClient.d.ts +7 -1
  284. package/dist/sql/SqlClient.d.ts.map +1 -1
  285. package/dist/sql/SqlClient.js +31 -6
  286. package/dist/sql/SqlClient.js.map +1 -1
  287. package/dist/testing/TestCrypto.d.ts +73 -0
  288. package/dist/testing/TestCrypto.d.ts.map +1 -0
  289. package/dist/testing/TestCrypto.js +87 -0
  290. package/dist/testing/TestCrypto.js.map +1 -0
  291. package/dist/testing/index.d.ts +5 -0
  292. package/dist/testing/index.d.ts.map +1 -1
  293. package/dist/testing/index.js +5 -0
  294. package/dist/testing/index.js.map +1 -1
  295. package/dist/workflow/DurableDeferred.d.ts +54 -0
  296. package/dist/workflow/DurableDeferred.d.ts.map +1 -1
  297. package/dist/workflow/DurableDeferred.js +108 -50
  298. package/dist/workflow/DurableDeferred.js.map +1 -1
  299. package/dist/workflow/WorkflowEngine.d.ts +24 -2
  300. package/dist/workflow/WorkflowEngine.d.ts.map +1 -1
  301. package/dist/workflow/WorkflowEngine.js +13 -3
  302. package/dist/workflow/WorkflowEngine.js.map +1 -1
  303. package/package.json +6 -3
  304. package/src/Context.ts +12 -3
  305. package/src/Crypto.ts +43 -9
  306. package/src/DateTime.ts +9 -6
  307. package/src/Duration.ts +36 -16
  308. package/src/FileSystem.ts +48 -2
  309. package/src/RequestResolver.ts +4 -10
  310. package/src/Scheduler.ts +9 -0
  311. package/src/Schema.ts +677 -5
  312. package/src/SchemaGetter.ts +47 -35
  313. package/src/Sink.ts +45 -18
  314. package/src/Stdio.ts +9 -2
  315. package/src/Stream.ts +44 -15
  316. package/src/Utils.ts +8 -5
  317. package/src/ai/AnthropicStructuredOutput.ts +2 -2
  318. package/src/ai/Chat.ts +2 -2
  319. package/src/ai/LanguageModel.ts +96 -24
  320. package/src/ai/McpServer.ts +288 -94
  321. package/src/ai/Prompt.ts +24 -10
  322. package/src/ai/Response.ts +6 -3
  323. package/src/ai/internal/mcpProtocol/v2026_07_28.ts +5 -0
  324. package/src/ai/internal/mcpProtocol.ts +3 -0
  325. package/src/ai/internal/mcpRuntime.ts +2 -0
  326. package/src/cli/CliOutput.ts +33 -16
  327. package/src/cli/Command.ts +4 -3
  328. package/src/cli/Completions.ts +9 -6
  329. package/src/cli/GlobalFlag.ts +19 -11
  330. package/src/cli/Prompt.ts +159 -149
  331. package/src/cli/internal/ansi.ts +26 -3
  332. package/src/cli/internal/completions/powershell.ts +322 -0
  333. package/src/cli/internal/completions/zsh.ts +4 -2
  334. package/src/cli/internal/wizard.ts +34 -26
  335. package/src/cluster/ClusterSchema.ts +32 -0
  336. package/src/cluster/ClusterWorkflowEngine.ts +64 -36
  337. package/src/cluster/MessageStorage.ts +45 -14
  338. package/src/cluster/Runners.ts +8 -2
  339. package/src/cluster/Sharding.ts +219 -58
  340. package/src/cluster/SqlMessageStorage.ts +118 -84
  341. package/src/cluster/SqlRunnerStorage.ts +224 -128
  342. package/src/cluster/internal/entityManager.ts +151 -55
  343. package/src/encoding/Sse.ts +69 -79
  344. package/src/graphql/GraphQL.ts +494 -0
  345. package/src/graphql/GraphQLClient.ts +912 -0
  346. package/src/graphql/GraphQLClientError.ts +542 -0
  347. package/src/graphql/GraphQLGroup.ts +167 -0
  348. package/src/graphql/GraphQLMiddleware.ts +253 -0
  349. package/src/graphql/GraphQLProtocol.ts +1286 -0
  350. package/src/graphql/GraphQLResolver.ts +1010 -0
  351. package/src/graphql/index.ts +48 -0
  352. package/src/http/FindMyWay/internal/router.ts +4 -7
  353. package/src/http/HttpClient.ts +110 -12
  354. package/src/http/HttpEffect.ts +11 -5
  355. package/src/http/HttpMiddleware.ts +33 -34
  356. package/src/http/HttpRouter.ts +35 -0
  357. package/src/http/HttpServerResponse.ts +28 -16
  358. package/src/http/HttpTraceContext.ts +8 -2
  359. package/src/http/Multipart.ts +17 -1
  360. package/src/http-api/HttpApiScalar.ts +5 -0
  361. package/src/internal/dateTime.ts +13 -10
  362. package/src/internal/effect.ts +22 -15
  363. package/src/internal/graphql.ts +263 -0
  364. package/src/internal/graphqlHeaders.ts +11 -0
  365. package/src/internal/request.ts +31 -3
  366. package/src/internal/schema/toCodeDocument.ts +7 -1
  367. package/src/internal/schema/toJsonSchemaDocument.ts +34 -2
  368. package/src/internal/version.ts +1 -1
  369. package/src/net/AddressResolver.ts +222 -0
  370. package/src/net/Dns.ts +1035 -0
  371. package/src/net/Host.ts +544 -0
  372. package/src/net/IpInterface.ts +117 -7
  373. package/src/net/IpNetwork.ts +116 -17
  374. package/src/net/NetAddress.ts +620 -76
  375. package/src/net/index.ts +18 -0
  376. package/src/observability/OtlpMetrics.ts +12 -23
  377. package/src/observability/PrometheusMetrics.ts +1 -0
  378. package/src/persistence/PersistedQueue.ts +146 -53
  379. package/src/rpc/RpcClient.ts +41 -19
  380. package/src/rpc/RpcServer.ts +115 -40
  381. package/src/socket/DatagramSocket.ts +919 -0
  382. package/src/socket/Socket.ts +28 -2
  383. package/src/socket/index.ts +6 -0
  384. package/src/sql/Migrator.ts +21 -5
  385. package/src/sql/SqlClient.ts +39 -15
  386. package/src/testing/TestCrypto.ts +94 -0
  387. package/src/testing/index.ts +6 -0
  388. package/src/workflow/DurableDeferred.ts +160 -47
  389. package/src/workflow/WorkflowEngine.ts +50 -5
@@ -9,10 +9,11 @@ import * as Data from "../Data.ts"
9
9
  import * as Equal from "../Equal.ts"
10
10
  import { dual } from "../Function.ts"
11
11
  import * as Hash from "../Hash.ts"
12
- import { NodeInspectSymbol } from "../Inspectable.ts"
12
+ import * as Inspectable from "../Inspectable.ts"
13
13
  import * as Option from "../Option.ts"
14
- import { hasProperty } from "../Predicate.ts"
14
+ import { hasProperty, isTupleOf } from "../Predicate.ts"
15
15
  import * as Result from "../Result.ts"
16
+ import type { TupleOf } from "../Types.ts"
16
17
 
17
18
  const TypeId = "~effect/net/NetAddress" as const
18
19
 
@@ -23,11 +24,9 @@ const TypeId = "~effect/net/NetAddress" as const
23
24
  * @category models
24
25
  * @since 4.0.0
25
26
  */
26
- export interface Ipv4Address extends Equal.Equal, Hash.Hash {
27
+ export interface Ipv4Address extends Equal.Equal, Hash.Hash, Inspectable.Inspectable {
27
28
  readonly _tag: "Ipv4Address"
28
29
  readonly [TypeId]: typeof TypeId
29
- toString(): string
30
- toJSON(): string
31
30
  }
32
31
 
33
32
  /**
@@ -37,11 +36,9 @@ export interface Ipv4Address extends Equal.Equal, Hash.Hash {
37
36
  * @category models
38
37
  * @since 4.0.0
39
38
  */
40
- export interface Ipv6Address extends Equal.Equal, Hash.Hash {
39
+ export interface Ipv6Address extends Equal.Equal, Hash.Hash, Inspectable.Inspectable {
41
40
  readonly _tag: "Ipv6Address"
42
41
  readonly [TypeId]: typeof TypeId
43
- toString(): string
44
- toJSON(): string
45
42
  }
46
43
 
47
44
  /**
@@ -53,6 +50,89 @@ export interface Ipv6Address extends Equal.Equal, Hash.Hash {
53
50
  */
54
51
  export type IpAddress = Ipv4Address | Ipv6Address
55
52
 
53
+ /**
54
+ * The four octets of an IPv4 address in network order.
55
+ *
56
+ * @stability unstable
57
+ * @category models
58
+ * @since 4.0.0
59
+ */
60
+ export type Ipv4Octets = Readonly<TupleOf<4, number>>
61
+
62
+ /**
63
+ * The eight 16-bit segments of an IPv6 address in network order.
64
+ *
65
+ * @stability unstable
66
+ * @category models
67
+ * @since 4.0.0
68
+ */
69
+ export type Ipv6Segments = Readonly<TupleOf<8, number>>
70
+
71
+ /**
72
+ * The six octets of a MAC address in transmission order.
73
+ *
74
+ * @stability unstable
75
+ * @category models
76
+ * @since 4.0.0
77
+ */
78
+ export type MacAddressOctets = Readonly<TupleOf<6, number>>
79
+
80
+ /**
81
+ * An IPv4 address, or a string, four octets, or four network-order bytes to
82
+ * convert to one.
83
+ *
84
+ * @stability unstable
85
+ * @category models
86
+ * @since 4.0.0
87
+ */
88
+ export type Ipv4AddressInput = Ipv4Address | string | Ipv4Octets | Uint8Array
89
+
90
+ /**
91
+ * An IPv6 address, or a string, eight 16-bit segments, or sixteen
92
+ * network-order bytes to convert to one.
93
+ *
94
+ * @stability unstable
95
+ * @category models
96
+ * @since 4.0.0
97
+ */
98
+ export type Ipv6AddressInput = Ipv6Address | string | Ipv6Segments | Uint8Array
99
+
100
+ /**
101
+ * An IP address, or any `Ipv4AddressInput` or `Ipv6AddressInput` to convert to
102
+ * one.
103
+ *
104
+ * @stability unstable
105
+ * @category models
106
+ * @since 4.0.0
107
+ */
108
+ export type IpAddressInput = Ipv4AddressInput | Ipv6AddressInput
109
+
110
+ /**
111
+ * An IPv6 literal with a zone, such as `fe80::1%eth0` or `fe80::1%3`.
112
+ *
113
+ * **Details**
114
+ *
115
+ * Named zones are kept as written because mapping an interface name to a
116
+ * numeric scope ID requires the operating system's interface table. Numeric
117
+ * zones must be unsigned 32-bit integers and are stored without leading zeros,
118
+ * and the address part is stored in canonical form.
119
+ *
120
+ * @see {@link scopedIpv6LiteralFromString} for parsing scoped IPv6 literals
121
+ * @stability experimental
122
+ * @category models
123
+ * @since 4.0.0
124
+ */
125
+ export type ScopedIpv6Literal = Brand.Branded<string, "~effect/net/NetAddress/ScopedIpv6Literal">
126
+
127
+ /**
128
+ * A scoped IPv6 literal or a string to parse as one.
129
+ *
130
+ * @stability experimental
131
+ * @category models
132
+ * @since 4.0.0
133
+ */
134
+ export type ScopedIpv6LiteralInput = ScopedIpv6Literal | string
135
+
56
136
  /**
57
137
  * An immutable 48-bit IEEE 802 MAC address.
58
138
  *
@@ -60,13 +140,20 @@ export type IpAddress = Ipv4Address | Ipv6Address
60
140
  * @category models
61
141
  * @since 4.0.0
62
142
  */
63
- export interface MacAddress extends Equal.Equal, Hash.Hash {
143
+ export interface MacAddress extends Equal.Equal, Hash.Hash, Inspectable.Inspectable {
64
144
  readonly _tag: "MacAddress"
65
145
  readonly [TypeId]: typeof TypeId
66
- toString(): string
67
- toJSON(): string
68
146
  }
69
147
 
148
+ /**
149
+ * A MAC address, or a string or six octets to convert to one.
150
+ *
151
+ * @stability unstable
152
+ * @category models
153
+ * @since 4.0.0
154
+ */
155
+ export type MacAddressInput = MacAddress | string | MacAddressOctets
156
+
70
157
  const MulticastTypeId = "~effect/net/NetAddress/MulticastAddress" as const
71
158
  const UnicastTypeId = "~effect/net/NetAddress/UnicastAddress" as const
72
159
  const BroadcastTypeId = "~effect/net/NetAddress/BroadcastAddress" as const
@@ -228,13 +315,11 @@ const getMacBytes = (self: MacAddress): Uint8Array => (self as any).bytes
228
315
  * @category models
229
316
  * @since 4.0.0
230
317
  */
231
- export interface InetAddressV4 extends Equal.Equal, Hash.Hash {
318
+ export interface InetAddressV4 extends Equal.Equal, Hash.Hash, Inspectable.Inspectable {
232
319
  readonly _tag: "InetAddressV4"
233
320
  readonly address: Ipv4Address
234
321
  readonly port: number
235
322
  readonly [TypeId]: typeof TypeId
236
- toString(): string
237
- toJSON(): string
238
323
  }
239
324
 
240
325
  /**
@@ -244,14 +329,12 @@ export interface InetAddressV4 extends Equal.Equal, Hash.Hash {
244
329
  * @category models
245
330
  * @since 4.0.0
246
331
  */
247
- export interface InetAddressV6 extends Equal.Equal, Hash.Hash {
332
+ export interface InetAddressV6 extends Equal.Equal, Hash.Hash, Inspectable.Inspectable {
248
333
  readonly _tag: "InetAddressV6"
249
334
  readonly address: Ipv6Address
250
335
  readonly port: number
251
336
  readonly scopeId: number
252
337
  readonly [TypeId]: typeof TypeId
253
- toString(): string
254
- toJSON(): string
255
338
  }
256
339
 
257
340
  /**
@@ -263,6 +346,32 @@ export interface InetAddressV6 extends Equal.Equal, Hash.Hash {
263
346
  */
264
347
  export type InetAddress = InetAddressV4 | InetAddressV6
265
348
 
349
+ /**
350
+ * The address, port, and optional IPv6 scope identifier of an internet address.
351
+ *
352
+ * **Details**
353
+ *
354
+ * A nonzero `scopeId` is only valid with an IPv6 address.
355
+ *
356
+ * @stability unstable
357
+ * @category models
358
+ * @since 4.0.0
359
+ */
360
+ export interface InetAddressParts<A extends IpAddressInput = IpAddressInput> {
361
+ readonly address: A
362
+ readonly port: number
363
+ readonly scopeId?: number | undefined
364
+ }
365
+
366
+ /**
367
+ * An internet address and port, or a string or parts to convert to one.
368
+ *
369
+ * @stability unstable
370
+ * @category models
371
+ * @since 4.0.0
372
+ */
373
+ export type InetAddressInput = InetAddress | string | InetAddressParts
374
+
266
375
  /**
267
376
  * An opaque Unix-domain filesystem socket path.
268
377
  *
@@ -270,12 +379,10 @@ export type InetAddress = InetAddressV4 | InetAddressV6
270
379
  * @category models
271
380
  * @since 4.0.0
272
381
  */
273
- export interface UnixPathAddress extends Equal.Equal, Hash.Hash {
382
+ export interface UnixPathAddress extends Equal.Equal, Hash.Hash, Inspectable.Inspectable {
274
383
  readonly _tag: "UnixPathAddress"
275
384
  readonly path: string
276
385
  readonly [TypeId]: typeof TypeId
277
- toString(): string
278
- toJSON(): string
279
386
  }
280
387
 
281
388
  /**
@@ -287,6 +394,17 @@ export interface UnixPathAddress extends Equal.Equal, Hash.Hash {
287
394
  */
288
395
  export type SocketAddress = InetAddress | UnixPathAddress
289
396
 
397
+ /**
398
+ * The path of a Unix-domain socket address.
399
+ *
400
+ * @stability unstable
401
+ * @category models
402
+ * @since 4.0.0
403
+ */
404
+ export interface UnixPathAddressParts {
405
+ readonly path: string
406
+ }
407
+
290
408
  /**
291
409
  * Companion types for constructing socket addresses.
292
410
  *
@@ -300,18 +418,14 @@ export declare namespace SocketAddress {
300
418
  *
301
419
  * **Details**
302
420
  *
303
- * String inputs must use `IPv4:port` or `[IPv6]:port` notation. Address
304
- * properties must be numeric IPv4 or IPv6 literals.
421
+ * Accepts any `InetAddressInput` or a Unix path. String inputs must use
422
+ * `IPv4:port` or `[IPv6]:port` notation.
305
423
  *
306
424
  * @stability unstable
307
425
  * @category models
308
426
  * @since 4.0.0
309
427
  */
310
- export type Input =
311
- | SocketAddress
312
- | string
313
- | { readonly address: IpAddress | string; readonly port: number }
314
- | { readonly path: string }
428
+ export type Input = SocketAddress | InetAddressInput | UnixPathAddressParts
315
429
  }
316
430
 
317
431
  /**
@@ -338,6 +452,29 @@ export declare namespace SocketAddress {
338
452
  export type Family<A extends IpAddress | InetAddress> = A extends Ipv4Address | InetAddressV4 ? Ipv4Address
339
453
  : Ipv6Address
340
454
 
455
+ /**
456
+ * The name of an IP address family, spelled as in `os.networkInterfaces()` and
457
+ * socket address information on Node.js, Deno, and Bun.
458
+ *
459
+ * @see {@link familyOf} for reading the family of an address
460
+ * @see {@link FamilyAddress} for the address type of a family
461
+ * @stability experimental
462
+ * @category models
463
+ * @since 4.0.0
464
+ */
465
+ export type IpFamily = "IPv4" | "IPv6"
466
+
467
+ /**
468
+ * The IP address type for an IP address family name. `FamilyAddress<IpFamily>`
469
+ * is `IpAddress`.
470
+ *
471
+ * @see {@link Family} for the inverse mapping from an address type
472
+ * @stability experimental
473
+ * @category models
474
+ * @since 4.0.0
475
+ */
476
+ export type FamilyAddress<F extends IpFamily> = F extends "IPv4" ? Ipv4Address : Ipv6Address
477
+
341
478
  /**
342
479
  * The internet address type for an IP address family.
343
480
  *
@@ -444,6 +581,93 @@ export const isIpAddress = (u: unknown): u is IpAddress => isIpv4Address(u) || i
444
581
  */
445
582
  export const width = (address: IpAddress): 32 | 128 => isIpv4Address(address) ? 32 : 128
446
583
 
584
+ /**
585
+ * Returns the family of an IP address or internet address.
586
+ *
587
+ * **Example** (Reading address families)
588
+ *
589
+ * ```ts import.meta.vitest
590
+ * import { NetAddress } from "effect/net"
591
+ *
592
+ * NetAddress.familyOf(NetAddress.ipv4Loopback) // => "IPv4"
593
+ * NetAddress.familyOf(NetAddress.inetAddressFromStringUnsafe("[::1]:80")) // => "IPv6"
594
+ * ```
595
+ *
596
+ * @stability experimental
597
+ * @category getters
598
+ * @since 4.0.0
599
+ */
600
+ export const familyOf = (self: IpAddress | InetAddress): IpFamily =>
601
+ isIpv4Address(self) || isInetAddressV4(self) ? "IPv4" : "IPv6"
602
+
603
+ /**
604
+ * Returns `true` when an IP address or internet address belongs to a family,
605
+ * narrowing it to that family.
606
+ *
607
+ * @stability experimental
608
+ * @category predicates
609
+ * @since 4.0.0
610
+ */
611
+ export const isFamily: {
612
+ /**
613
+ * Returns `true` when an IP address or internet address belongs to a family,
614
+ * narrowing it to that family.
615
+ *
616
+ * @stability experimental
617
+ * @category predicates
618
+ * @since 4.0.0
619
+ */
620
+ (family: "IPv4"): <A extends IpAddress | InetAddress>(self: A) => self is Extract<A, Ipv4Address | InetAddressV4>
621
+ /**
622
+ * Returns `true` when an IP address or internet address belongs to a family,
623
+ * narrowing it to that family.
624
+ *
625
+ * @stability experimental
626
+ * @category predicates
627
+ * @since 4.0.0
628
+ */
629
+ (family: "IPv6"): <A extends IpAddress | InetAddress>(self: A) => self is Extract<A, Ipv6Address | InetAddressV6>
630
+ /**
631
+ * Returns `true` when an IP address or internet address belongs to a family,
632
+ * narrowing it to that family.
633
+ *
634
+ * @stability experimental
635
+ * @category predicates
636
+ * @since 4.0.0
637
+ */
638
+ (family: IpFamily): (self: IpAddress | InetAddress) => boolean
639
+ /**
640
+ * Returns `true` when an IP address or internet address belongs to a family,
641
+ * narrowing it to that family.
642
+ *
643
+ * @stability experimental
644
+ * @category predicates
645
+ * @since 4.0.0
646
+ */
647
+ <A extends IpAddress | InetAddress>(self: A, family: "IPv4"): self is Extract<A, Ipv4Address | InetAddressV4>
648
+ /**
649
+ * Returns `true` when an IP address or internet address belongs to a family,
650
+ * narrowing it to that family.
651
+ *
652
+ * @stability experimental
653
+ * @category predicates
654
+ * @since 4.0.0
655
+ */
656
+ <A extends IpAddress | InetAddress>(self: A, family: "IPv6"): self is Extract<A, Ipv6Address | InetAddressV6>
657
+ /**
658
+ * Returns `true` when an IP address or internet address belongs to a family,
659
+ * narrowing it to that family.
660
+ *
661
+ * @stability experimental
662
+ * @category predicates
663
+ * @since 4.0.0
664
+ */
665
+ (self: IpAddress | InetAddress, family: IpFamily): boolean
666
+ } = dual(
667
+ 2,
668
+ <A extends IpAddress | InetAddress>(self: A, family: IpFamily): self is A => familyOf(self) === family
669
+ )
670
+
447
671
  /**
448
672
  * Returns `true` when a value is a MAC address.
449
673
  *
@@ -499,6 +723,7 @@ export const isUnixPathAddress = (u: unknown): u is UnixPathAddress => isAddress
499
723
  export const isSocketAddress = (u: unknown): u is SocketAddress => isInetAddress(u) || isUnixPathAddress(u)
500
724
 
501
725
  const Ipv4Proto = {
726
+ ...Inspectable.BaseProto,
502
727
  _tag: "Ipv4Address",
503
728
  [TypeId]: TypeId,
504
729
  [Equal.symbol](this: Ipv4Address, that: Equal.Equal): boolean {
@@ -512,13 +737,11 @@ const Ipv4Proto = {
512
737
  },
513
738
  toJSON(this: Ipv4Address): string {
514
739
  return this.toString()
515
- },
516
- [NodeInspectSymbol](this: Ipv4Address): string {
517
- return this.toJSON()
518
740
  }
519
741
  }
520
742
 
521
743
  const Ipv6Proto = {
744
+ ...Inspectable.BaseProto,
522
745
  _tag: "Ipv6Address",
523
746
  [TypeId]: TypeId,
524
747
  [Equal.symbol](this: Ipv6Address, that: Equal.Equal): boolean {
@@ -539,13 +762,11 @@ const Ipv6Proto = {
539
762
  },
540
763
  toJSON(this: Ipv6Address): string {
541
764
  return this.toString()
542
- },
543
- [NodeInspectSymbol](this: Ipv6Address): string {
544
- return this.toJSON()
545
765
  }
546
766
  }
547
767
 
548
768
  const MacProto = {
769
+ ...Inspectable.BaseProto,
549
770
  _tag: "MacAddress",
550
771
  [TypeId]: TypeId,
551
772
  [Equal.symbol](this: MacAddress, that: Equal.Equal): boolean {
@@ -559,9 +780,6 @@ const MacProto = {
559
780
  },
560
781
  toJSON(this: MacAddress): string {
561
782
  return this.toString()
562
- },
563
- [NodeInspectSymbol](this: MacAddress): string {
564
- return this.toJSON()
565
783
  }
566
784
  }
567
785
 
@@ -597,7 +815,7 @@ const packOctets = (a: number, b: number, c: number, d: number): number => ((a <
597
815
  const packBytes = (bytes: Uint8Array, offset: number): number =>
598
816
  packOctets(bytes[offset], bytes[offset + 1], bytes[offset + 2], bytes[offset + 3])
599
817
 
600
- const wordToOctets = (word: number): readonly [number, number, number, number] => [
818
+ const wordToOctets = (word: number): Ipv4Octets => [
601
819
  word >>> 24,
602
820
  (word >>> 16) & 0xff,
603
821
  (word >>> 8) & 0xff,
@@ -646,6 +864,15 @@ export const ipv4Loopback: Ipv4Address = makeIpv4(0x7f000001)
646
864
  */
647
865
  export const ipv6Loopback: Ipv6Address = makeIpv6(0, 0, 0, 1)
648
866
 
867
+ /**
868
+ * The loopback addresses `127.0.0.1` and `::1`.
869
+ *
870
+ * @stability unstable
871
+ * @category constants
872
+ * @since 4.0.0
873
+ */
874
+ export const loopbackAddresses: readonly [Ipv4Address, Ipv6Address] = [ipv4Loopback, ipv6Loopback]
875
+
649
876
  /**
650
877
  * The unspecified IPv4 address `0.0.0.0`.
651
878
  *
@@ -676,6 +903,15 @@ export const ipv4Broadcast: Ipv4Address = makeIpv4(0xffffffff)
676
903
  const addressError = (input: unknown, message: string): Result.Result<never, NetAddressError> =>
677
904
  Result.fail(new NetAddressError({ input, message }))
678
905
 
906
+ // Checks by index because `every` skips holes in sparse arrays.
907
+ const allIntegersInRange = (values: ReadonlyArray<number>, max: number): boolean => {
908
+ for (let i = 0; i < values.length; i++) {
909
+ const n = values[i]
910
+ if (!Number.isInteger(n) || n < 0 || n > max) return false
911
+ }
912
+ return true
913
+ }
914
+
679
915
  /**
680
916
  * Creates an IPv4 address from four checked octets.
681
917
  *
@@ -684,9 +920,9 @@ const addressError = (input: unknown, message: string): Result.Result<never, Net
684
920
  * @since 4.0.0
685
921
  */
686
922
  export const ipv4FromOctets = (
687
- octets: readonly [number, number, number, number]
923
+ octets: Ipv4Octets
688
924
  ): Result.Result<Ipv4Address, NetAddressError> => {
689
- if (!octets.every((n) => Number.isInteger(n) && n >= 0 && n <= 255)) {
925
+ if (!allIntegersInRange(octets, 255)) {
690
926
  return addressError(octets, "octets must be integers from 0 through 255")
691
927
  }
692
928
  return Result.succeed(makeIpv4(packOctets(octets[0], octets[1], octets[2], octets[3])))
@@ -700,9 +936,9 @@ export const ipv4FromOctets = (
700
936
  * @since 4.0.0
701
937
  */
702
938
  export const ipv6FromSegments = (
703
- segments: readonly [number, number, number, number, number, number, number, number]
939
+ segments: Ipv6Segments
704
940
  ): Result.Result<Ipv6Address, NetAddressError> => {
705
- if (!segments.every((n) => Number.isInteger(n) && n >= 0 && n <= 0xffff)) {
941
+ if (!allIntegersInRange(segments, 0xffff)) {
706
942
  return addressError(segments, "segments must be integers from 0 through 65535")
707
943
  }
708
944
  return Result.succeed(makeIpv6(
@@ -721,9 +957,9 @@ export const ipv6FromSegments = (
721
957
  * @since 4.0.0
722
958
  */
723
959
  export const macAddressFromOctets = (
724
- octets: readonly [number, number, number, number, number, number]
960
+ octets: MacAddressOctets
725
961
  ): Result.Result<MacAddress, NetAddressError> => {
726
- if (!octets.every((n) => Number.isInteger(n) && n >= 0 && n <= 255)) {
962
+ if (!allIntegersInRange(octets, 255)) {
727
963
  return addressError(octets, "octets must be integers from 0 through 255")
728
964
  }
729
965
  return Result.succeed(makeMac(new Uint8Array(octets)))
@@ -752,6 +988,32 @@ export const macAddressFromString = (input: string): Result.Result<MacAddress, N
752
988
  */
753
989
  export const macAddressFromStringUnsafe = (input: string): MacAddress => Result.getOrThrow(macAddressFromString(input))
754
990
 
991
+ /**
992
+ * Converts a `MacAddressInput` to a MAC address, parsing strings like
993
+ * `macAddressFromString`, checking octets like `macAddressFromOctets`, and
994
+ * returning MAC addresses unchanged.
995
+ *
996
+ * @stability unstable
997
+ * @category constructors
998
+ * @since 4.0.0
999
+ */
1000
+ export const macAddressFromInput = (input: MacAddressInput): Result.Result<MacAddress, NetAddressError> => {
1001
+ if (isMacAddress(input)) return Result.succeed(input)
1002
+ if (typeof input === "string") return macAddressFromString(input)
1003
+ if (Array.isArray(input) && isTupleOf(input, 6)) return macAddressFromOctets(input)
1004
+ return addressError(input, "expected a MAC address, string, or 6 octets")
1005
+ }
1006
+
1007
+ /**
1008
+ * Converts a trusted `MacAddressInput` to a MAC address, throwing on failure.
1009
+ *
1010
+ * @stability unstable
1011
+ * @category unsafe
1012
+ * @since 4.0.0
1013
+ */
1014
+ export const macAddressFromInputUnsafe = (input: MacAddressInput): MacAddress =>
1015
+ Result.getOrThrow(macAddressFromInput(input))
1016
+
755
1017
  /**
756
1018
  * Parses a strict dotted-decimal IPv4 address.
757
1019
  *
@@ -875,6 +1137,141 @@ export const ipFromString = (input: string): Result.Result<IpAddress, NetAddress
875
1137
  */
876
1138
  export const ipFromStringUnsafe = (input: string): IpAddress => Result.getOrThrow(ipFromString(input))
877
1139
 
1140
+ /**
1141
+ * Converts an `IpAddressInput` to an IP address, returning IP addresses
1142
+ * unchanged.
1143
+ *
1144
+ * **Details**
1145
+ *
1146
+ * Strings are parsed like `ipFromString`. Four octets or bytes make an IPv4
1147
+ * address, and eight segments or sixteen bytes make an IPv6 address.
1148
+ *
1149
+ * **Example** (Converting IP address inputs)
1150
+ *
1151
+ * ```ts import.meta.vitest
1152
+ * import { Result } from "effect"
1153
+ * import { NetAddress } from "effect/net"
1154
+ *
1155
+ * const address = Result.getOrThrow(NetAddress.ipFromInput("192.0.2.1"))
1156
+ * NetAddress.formatIp(address) // => "192.0.2.1"
1157
+ * Result.getOrThrow(NetAddress.ipFromInput(address)) === address // => true
1158
+ * NetAddress.formatIp(Result.getOrThrow(NetAddress.ipFromInput([192, 0, 2, 1]))) // => "192.0.2.1"
1159
+ * Result.isFailure(NetAddress.ipFromInput("example.com")) // => true
1160
+ * ```
1161
+ *
1162
+ * @stability unstable
1163
+ * @category constructors
1164
+ * @since 4.0.0
1165
+ */
1166
+ export const ipFromInput = (input: IpAddressInput): Result.Result<IpAddress, NetAddressError> => {
1167
+ if (isIpAddress(input)) return Result.succeed(input)
1168
+ if (typeof input === "string") return ipFromString(input)
1169
+ if (input instanceof Uint8Array && input.length === 4) return Result.succeed(ipv4FromBytesUnsafe(input))
1170
+ if (input instanceof Uint8Array && input.length === 16) return Result.succeed(ipv6FromBytesUnsafe(input))
1171
+ if (Array.isArray(input) && isTupleOf(input, 4)) return ipv4FromOctets(input)
1172
+ if (Array.isArray(input) && isTupleOf(input, 8)) return ipv6FromSegments(input)
1173
+ return addressError(input, "expected an IP address, string, 4 octets, 8 segments, or 4 or 16 bytes")
1174
+ }
1175
+
1176
+ /**
1177
+ * Converts a trusted `IpAddressInput` to an IP address, throwing on failure.
1178
+ *
1179
+ * @stability unstable
1180
+ * @category unsafe
1181
+ * @since 4.0.0
1182
+ */
1183
+ export const ipFromInputUnsafe = (input: IpAddressInput): IpAddress => Result.getOrThrow(ipFromInput(input))
1184
+
1185
+ /**
1186
+ * Converts an `Ipv4AddressInput` to an IPv4 address, parsing strings like
1187
+ * `ipv4FromString`, checking octets like `ipv4FromOctets`, and returning IPv4
1188
+ * addresses unchanged.
1189
+ *
1190
+ * @stability unstable
1191
+ * @category constructors
1192
+ * @since 4.0.0
1193
+ */
1194
+ export const ipv4FromInput = (input: Ipv4AddressInput): Result.Result<Ipv4Address, NetAddressError> => {
1195
+ if (isIpv4Address(input)) return Result.succeed(input)
1196
+ if (typeof input === "string") return ipv4FromString(input)
1197
+ if (input instanceof Uint8Array && input.length === 4) return Result.succeed(ipv4FromBytesUnsafe(input))
1198
+ if (Array.isArray(input) && isTupleOf(input, 4)) return ipv4FromOctets(input)
1199
+ return addressError(input, "expected an IPv4 address, string, 4 octets, or 4 bytes")
1200
+ }
1201
+
1202
+ /**
1203
+ * Converts an `Ipv6AddressInput` to an IPv6 address, parsing strings like
1204
+ * `ipv6FromString`, checking segments like `ipv6FromSegments`, and returning
1205
+ * IPv6 addresses unchanged.
1206
+ *
1207
+ * @stability unstable
1208
+ * @category constructors
1209
+ * @since 4.0.0
1210
+ */
1211
+ export const ipv6FromInput = (input: Ipv6AddressInput): Result.Result<Ipv6Address, NetAddressError> => {
1212
+ if (isIpv6Address(input)) return Result.succeed(input)
1213
+ if (typeof input === "string") return ipv6FromString(input)
1214
+ if (input instanceof Uint8Array && input.length === 16) return Result.succeed(ipv6FromBytesUnsafe(input))
1215
+ if (Array.isArray(input) && isTupleOf(input, 8)) return ipv6FromSegments(input)
1216
+ return addressError(input, "expected an IPv6 address, string, 8 segments, or 16 bytes")
1217
+ }
1218
+
1219
+ /**
1220
+ * Returns `true` when a value is a canonical scoped IPv6 literal.
1221
+ *
1222
+ * @stability experimental
1223
+ * @category guards
1224
+ * @since 4.0.0
1225
+ */
1226
+ export const isScopedIpv6Literal = (u: unknown): u is ScopedIpv6Literal => {
1227
+ if (typeof u !== "string" || !u.includes("%")) return false
1228
+ const result = scopedIpv6LiteralFromString(u)
1229
+ return Result.isSuccess(result) && result.success === u
1230
+ }
1231
+
1232
+ /**
1233
+ * Parses an IPv6 literal with a numeric or named zone, such as `fe80::1%eth0`.
1234
+ *
1235
+ * @stability experimental
1236
+ * @category decoding
1237
+ * @since 4.0.0
1238
+ */
1239
+ export const scopedIpv6LiteralFromString = (
1240
+ input: string
1241
+ ): Result.Result<ScopedIpv6Literal, NetAddressError> => {
1242
+ const separator = input.indexOf("%")
1243
+ if (separator === -1) return addressError(input, "expected an IPv6 zone")
1244
+ let zone = input.slice(separator + 1)
1245
+ if (zone.length === 0 || /[%[\]/\s\p{Cc}]/u.test(zone)) {
1246
+ return addressError(input, "invalid IPv6 scope identifier")
1247
+ }
1248
+ if (/^\d+$/.test(zone)) {
1249
+ const scopeId = Number(zone)
1250
+ if (scopeId > 0xffffffff) return addressError(input, "scope identifier must be an unsigned 32-bit integer")
1251
+ zone = String(scopeId)
1252
+ }
1253
+ return Result.map(
1254
+ ipv6FromString(input.slice(0, separator)),
1255
+ (address) => `${formatIp(address)}%${zone}` as ScopedIpv6Literal
1256
+ )
1257
+ }
1258
+
1259
+ /**
1260
+ * Converts a `ScopedIpv6LiteralInput` to a scoped IPv6 literal, parsing it
1261
+ * like `scopedIpv6LiteralFromString`.
1262
+ *
1263
+ * **Details**
1264
+ *
1265
+ * Scoped IPv6 literals are strings, so every input is parsed.
1266
+ *
1267
+ * @stability experimental
1268
+ * @category constructors
1269
+ * @since 4.0.0
1270
+ */
1271
+ export const scopedIpv6LiteralFromInput = (
1272
+ input: ScopedIpv6LiteralInput
1273
+ ): Result.Result<ScopedIpv6Literal, NetAddressError> => scopedIpv6LiteralFromString(input)
1274
+
878
1275
  /**
879
1276
  * Returns the four numeric octets of an IPv4 address in a fresh tuple.
880
1277
  *
@@ -882,8 +1279,7 @@ export const ipFromStringUnsafe = (input: string): IpAddress => Result.getOrThro
882
1279
  * @category getters
883
1280
  * @since 4.0.0
884
1281
  */
885
- export const ipv4ToOctets = (self: Ipv4Address): readonly [number, number, number, number] =>
886
- wordToOctets(ipv4Value(self))
1282
+ export const ipv4ToOctets = (self: Ipv4Address): Ipv4Octets => wordToOctets(ipv4Value(self))
887
1283
 
888
1284
  /**
889
1285
  * Returns the eight numeric segments of an IPv6 address in a fresh tuple.
@@ -892,9 +1288,7 @@ export const ipv4ToOctets = (self: Ipv4Address): readonly [number, number, numbe
892
1288
  * @category getters
893
1289
  * @since 4.0.0
894
1290
  */
895
- export const ipv6ToSegments = (
896
- self: Ipv6Address
897
- ): readonly [number, number, number, number, number, number, number, number] => {
1291
+ export const ipv6ToSegments = (self: Ipv6Address): Ipv6Segments => {
898
1292
  const { w0, w1, w2, w3 } = ipv6Words(self)
899
1293
  return [w0 >>> 16, w0 & 0xffff, w1 >>> 16, w1 & 0xffff, w2 >>> 16, w2 & 0xffff, w3 >>> 16, w3 & 0xffff]
900
1294
  }
@@ -920,9 +1314,7 @@ export const ipv6ToOctets = (
920
1314
  * @category getters
921
1315
  * @since 4.0.0
922
1316
  */
923
- export const macAddressToOctets = (
924
- self: MacAddress
925
- ): readonly [number, number, number, number, number, number] => {
1317
+ export const macAddressToOctets = (self: MacAddress): MacAddressOctets => {
926
1318
  const bytes = getMacBytes(self)
927
1319
  return [bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5]]
928
1320
  }
@@ -1254,6 +1646,7 @@ export function toCanonical(self: IpAddress | InetAddress): IpAddress | InetAddr
1254
1646
  }
1255
1647
 
1256
1648
  const InetV4Proto = {
1649
+ ...Inspectable.BaseProto,
1257
1650
  _tag: "InetAddressV4",
1258
1651
  [TypeId]: TypeId,
1259
1652
  [Equal.symbol](this: InetAddressV4, that: Equal.Equal): boolean {
@@ -1267,13 +1660,11 @@ const InetV4Proto = {
1267
1660
  },
1268
1661
  toJSON(this: InetAddressV4): string {
1269
1662
  return this.toString()
1270
- },
1271
- [NodeInspectSymbol](this: InetAddressV4): string {
1272
- return this.toJSON()
1273
1663
  }
1274
1664
  }
1275
1665
 
1276
1666
  const InetV6Proto = {
1667
+ ...Inspectable.BaseProto,
1277
1668
  _tag: "InetAddressV6",
1278
1669
  [TypeId]: TypeId,
1279
1670
  [Equal.symbol](this: InetAddressV6, that: Equal.Equal): boolean {
@@ -1291,9 +1682,6 @@ const InetV6Proto = {
1291
1682
  },
1292
1683
  toJSON(this: InetAddressV6): string {
1293
1684
  return this.toString()
1294
- },
1295
- [NodeInspectSymbol](this: InetAddressV6): string {
1296
- return this.toJSON()
1297
1685
  }
1298
1686
  }
1299
1687
 
@@ -1396,6 +1784,112 @@ export const inetAddressFromIpString = (
1396
1784
  export const inetAddressFromIpStringUnsafe = (address: string, port: number): InetAddress =>
1397
1785
  Result.getOrThrow(inetAddressFromIpString(address, port))
1398
1786
 
1787
+ /**
1788
+ * Creates an internet address from a trusted native numeric host and port.
1789
+ * Named IPv6 zones are resolved using the supplied interface-to-scope map.
1790
+ * Use only for runtime-supplied socket addresses: this skips input validation,
1791
+ * so malformed strings or ports may silently produce incorrect values. An
1792
+ * unknown named IPv6 zone throws rather than losing its scope.
1793
+ *
1794
+ * @stability unstable
1795
+ * @category unsafe
1796
+ * @since 4.0.0
1797
+ */
1798
+ export const inetAddressFromNativeUnsafe = (
1799
+ host: string,
1800
+ port: number,
1801
+ scopeIds?: ReadonlyMap<string, number>
1802
+ ): InetAddress => {
1803
+ const zoneStart = host.indexOf("%")
1804
+ const end = zoneStart === -1 ? host.length : zoneStart
1805
+ if (host.indexOf(":") === -1) {
1806
+ const self = Object.create(InetV4Proto)
1807
+ self.address = makeIpv4(parseNativeIpv4(host, 0, end))
1808
+ self.port = port
1809
+ return Object.freeze(self)
1810
+ }
1811
+
1812
+ let scopeId = 0
1813
+ if (zoneStart !== -1) {
1814
+ const zone = host.slice(zoneStart + 1)
1815
+ const resolved = numericZone.test(zone) ? Number(zone) : scopeIds?.get(zone)
1816
+ if (resolved === undefined) throw new Error(`unknown IPv6 interface: ${zone}`)
1817
+ scopeId = resolved
1818
+ }
1819
+
1820
+ let w0 = 0
1821
+ let w1 = 0
1822
+ let w2 = 0
1823
+ let w3 = 0
1824
+ let segment = 0
1825
+ let i = 0
1826
+ while (i < end) {
1827
+ if (host.charCodeAt(i) === 58) {
1828
+ // The rest of a compressed address is anchored at the last segment.
1829
+ i += 2
1830
+ if (i === end) break
1831
+ let remaining = 1
1832
+ for (let j = i; j < end; j++) {
1833
+ if (host.charCodeAt(j) === 58) remaining++
1834
+ }
1835
+ const dot = host.indexOf(".", i)
1836
+ if (dot !== -1 && dot < end) remaining++
1837
+ segment = 8 - remaining
1838
+ }
1839
+ const start = i
1840
+ let value = 0
1841
+ while (i < end) {
1842
+ const ch = host.charCodeAt(i)
1843
+ if (ch === 58 || ch === 46) break
1844
+ value = (value << 4) | (ch <= 57 ? ch - 48 : (ch & 0x5f) - 55)
1845
+ i++
1846
+ }
1847
+ if (i < end && host.charCodeAt(i) === 46) {
1848
+ w3 = parseNativeIpv4(host, start, end)
1849
+ break
1850
+ }
1851
+ // even segments fill the high half of their 32-bit word
1852
+ const shifted = value << ((1 - (segment & 1)) * 16)
1853
+ switch (segment >>> 1) {
1854
+ case 0:
1855
+ w0 |= shifted
1856
+ break
1857
+ case 1:
1858
+ w1 |= shifted
1859
+ break
1860
+ case 2:
1861
+ w2 |= shifted
1862
+ break
1863
+ default:
1864
+ w3 |= shifted
1865
+ }
1866
+ segment++
1867
+ if (i < end && host.charCodeAt(i + 1) !== 58) i++
1868
+ }
1869
+ const self = Object.create(InetV6Proto)
1870
+ self.address = makeIpv6(w0, w1, w2, w3)
1871
+ self.port = port
1872
+ self.scopeId = scopeId
1873
+ return Object.freeze(self)
1874
+ }
1875
+
1876
+ const numericZone = /^\d+$/
1877
+
1878
+ const parseNativeIpv4 = (host: string, start: number, end: number): number => {
1879
+ let value = 0
1880
+ let octet = 0
1881
+ for (let i = start; i < end; i++) {
1882
+ const ch = host.charCodeAt(i)
1883
+ if (ch === 46) {
1884
+ value = (value << 8) | octet
1885
+ octet = 0
1886
+ } else {
1887
+ octet = octet * 10 + ch - 48
1888
+ }
1889
+ }
1890
+ return ((value << 8) | octet) >>> 0
1891
+ }
1892
+
1399
1893
  /**
1400
1894
  * Parses an unbracketed numeric host and port, resolving named IPv6 zones using
1401
1895
  * a supplied map of interface names to numeric scope IDs.
@@ -1443,7 +1937,33 @@ export const inetAddressFromHostString = (
1443
1937
  */
1444
1938
  export interface NetworkInterfaceAddress {
1445
1939
  readonly family: string
1446
- readonly scopeid?: number | undefined
1940
+ readonly scopeid?: number | null | undefined
1941
+ }
1942
+
1943
+ /**
1944
+ * Returns the IPv6 scope ID of a network interface from its addresses.
1945
+ *
1946
+ * **Details**
1947
+ *
1948
+ * The first IPv6 address with a positive scope ID supplies the result. Accepts
1949
+ * the addresses of one interface, such as `os.networkInterfaces()[name]` or the
1950
+ * entries of `Deno.networkInterfaces()` with that name, without performing any
1951
+ * operating-system lookup itself.
1952
+ *
1953
+ * @see {@link scopeIdsFromInterfaces} for mapping every interface at once
1954
+ * @stability experimental
1955
+ * @category converting
1956
+ * @since 4.0.0
1957
+ */
1958
+ export const scopeIdFromInterface = (
1959
+ addresses: ReadonlyArray<NetworkInterfaceAddress> | undefined
1960
+ ): Option.Option<number> => {
1961
+ for (const address of addresses ?? []) {
1962
+ if (address.family === "IPv6" && typeof address.scopeid === "number" && address.scopeid > 0) {
1963
+ return Option.some(address.scopeid)
1964
+ }
1965
+ }
1966
+ return Option.none()
1447
1967
  }
1448
1968
 
1449
1969
  /**
@@ -1468,8 +1988,8 @@ export const scopeIdsFromInterfaces = (
1468
1988
  ): Map<string, number> => {
1469
1989
  const scopeIds = new Map<string, number>()
1470
1990
  for (const [name, addresses] of interfaces) {
1471
- const address = addresses?.find((address) => address.family === "IPv6" && (address.scopeid ?? 0) > 0)
1472
- if (address?.scopeid !== undefined) scopeIds.set(name, address.scopeid)
1991
+ const scopeId = scopeIdFromInterface(addresses)
1992
+ if (Option.isSome(scopeId)) scopeIds.set(name, scopeId.value)
1473
1993
  }
1474
1994
  return scopeIds
1475
1995
  }
@@ -1539,6 +2059,40 @@ export const inetAddressFromString = (input: string): Result.Result<InetAddress,
1539
2059
  export const inetAddressFromStringUnsafe = (input: string): InetAddress =>
1540
2060
  Result.getOrThrow(inetAddressFromString(input))
1541
2061
 
2062
+ /**
2063
+ * Converts an `InetAddressInput` to an internet address, parsing strings like
2064
+ * `inetAddressFromString`, converting parts like `inetAddressV4` and
2065
+ * `inetAddressV6`, and returning internet addresses unchanged.
2066
+ *
2067
+ * @stability unstable
2068
+ * @category constructors
2069
+ * @since 4.0.0
2070
+ */
2071
+ export const inetAddressFromInput = (input: InetAddressInput): Result.Result<InetAddress, NetAddressError> => {
2072
+ if (isInetAddress(input)) return Result.succeed(input)
2073
+ if (typeof input === "string") return inetAddressFromString(input)
2074
+ if (!hasProperty(input, "address") || !hasProperty(input, "port")) {
2075
+ return addressError(input, "expected an address and port")
2076
+ }
2077
+ const { port, scopeId } = input
2078
+ return Result.flatMap(ipFromInput(input.address), (address): Result.Result<InetAddress, NetAddressError> => {
2079
+ if (isIpv6Address(address)) return inetAddressV6(address, port, { scopeId })
2080
+ return (scopeId ?? 0) === 0
2081
+ ? inetAddressV4(address, port)
2082
+ : addressError(input, "scopeId requires an IPv6 address")
2083
+ })
2084
+ }
2085
+
2086
+ /**
2087
+ * Converts a trusted `InetAddressInput` to an internet address, throwing on failure.
2088
+ *
2089
+ * @stability unstable
2090
+ * @category unsafe
2091
+ * @since 4.0.0
2092
+ */
2093
+ export const inetAddressFromInputUnsafe = (input: InetAddressInput): InetAddress =>
2094
+ Result.getOrThrow(inetAddressFromInput(input))
2095
+
1542
2096
  /**
1543
2097
  * Formats the numeric host of an internet address without brackets or a port,
1544
2098
  * preserving a nonzero IPv6 scope ID as a `%` suffix.
@@ -1722,6 +2276,7 @@ export const formatUrlHostString = (host: string): string =>
1722
2276
  host.includes(":") && !host.startsWith("[") ? `[${host}]` : host
1723
2277
 
1724
2278
  const UnixPathProto = {
2279
+ ...Inspectable.BaseProto,
1725
2280
  _tag: "UnixPathAddress",
1726
2281
  [TypeId]: TypeId,
1727
2282
  [Equal.symbol](this: UnixPathAddress, that: Equal.Equal): boolean {
@@ -1735,9 +2290,6 @@ const UnixPathProto = {
1735
2290
  },
1736
2291
  toJSON(this: UnixPathAddress): string {
1737
2292
  return this.toString()
1738
- },
1739
- [NodeInspectSymbol](this: UnixPathAddress): string {
1740
- return this.toJSON()
1741
2293
  }
1742
2294
  }
1743
2295
 
@@ -1773,8 +2325,9 @@ export const formatUnixPath = (self: UnixPathAddress): string => `unix://${self.
1773
2325
  *
1774
2326
  * **Details**
1775
2327
  *
1776
- * Numeric IP strings are parsed without hostname resolution. Invalid IP
1777
- * literals, ports, and input shapes return a `NetAddressError`.
2328
+ * Internet addresses are converted like `inetAddressFromInput`, without
2329
+ * hostname resolution. Invalid IP literals, ports, and input shapes return a
2330
+ * `NetAddressError`.
1778
2331
  *
1779
2332
  * @stability unstable
1780
2333
  * @category constructors
@@ -1783,22 +2336,13 @@ export const formatUnixPath = (self: UnixPathAddress): string => `unix://${self.
1783
2336
  export const socketAddressFromInput = (
1784
2337
  input: SocketAddress.Input
1785
2338
  ): Result.Result<SocketAddress, NetAddressError> => {
1786
- if (isSocketAddress(input)) return Result.succeed(input)
1787
- if (typeof input === "string") return inetAddressFromString(input)
2339
+ if (isUnixPathAddress(input)) return Result.succeed(input)
1788
2340
  if (hasProperty(input, "path")) {
1789
2341
  return typeof input.path === "string"
1790
2342
  ? Result.succeed(unixPathAddress(input.path))
1791
2343
  : addressError(input, "path must be a string")
1792
2344
  }
1793
- if (!hasProperty(input, "address") || !hasProperty(input, "port")) {
1794
- return addressError(input, "expected an address and port or a Unix path")
1795
- }
1796
- const address = typeof input.address === "string"
1797
- ? ipFromString(input.address)
1798
- : isIpAddress(input.address)
1799
- ? Result.succeed(input.address)
1800
- : addressError(input, "address must be an IP address or numeric IP string")
1801
- return Result.flatMap(address, (address) => inetAddress(address, input.port as number))
2345
+ return inetAddressFromInput(input)
1802
2346
  }
1803
2347
 
1804
2348
  /**