effect 4.0.3 → 4.0.5

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 (449) 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 +117 -0
  5. package/ai-docs/src/52_graphql/20_testing.ts +45 -0
  6. package/ai-docs/src/52_graphql/30_batching.ts +118 -0
  7. package/ai-docs/src/52_graphql/40_aliased-batching.ts +124 -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/Array.d.ts +90 -6
  11. package/dist/Array.d.ts.map +1 -1
  12. package/dist/Array.js +4 -2
  13. package/dist/Array.js.map +1 -1
  14. package/dist/Channel.d.ts +6 -1
  15. package/dist/Channel.d.ts.map +1 -1
  16. package/dist/Channel.js +17 -3
  17. package/dist/Channel.js.map +1 -1
  18. package/dist/ConfigProvider.d.ts.map +1 -1
  19. package/dist/ConfigProvider.js +33 -32
  20. package/dist/ConfigProvider.js.map +1 -1
  21. package/dist/Context.d.ts.map +1 -1
  22. package/dist/Context.js +9 -0
  23. package/dist/Context.js.map +1 -1
  24. package/dist/Duration.d.ts.map +1 -1
  25. package/dist/Duration.js +2 -5
  26. package/dist/Duration.js.map +1 -1
  27. package/dist/Effect.d.ts +61 -19
  28. package/dist/Effect.d.ts.map +1 -1
  29. package/dist/Effect.js +58 -39
  30. package/dist/Effect.js.map +1 -1
  31. package/dist/FileSystem.d.ts +23 -9
  32. package/dist/FileSystem.d.ts.map +1 -1
  33. package/dist/FileSystem.js.map +1 -1
  34. package/dist/Match.d.ts +20 -6
  35. package/dist/Match.d.ts.map +1 -1
  36. package/dist/Match.js +2 -2
  37. package/dist/Match.js.map +1 -1
  38. package/dist/Path.d.ts +37 -5
  39. package/dist/Path.d.ts.map +1 -1
  40. package/dist/Path.js +36 -5
  41. package/dist/Path.js.map +1 -1
  42. package/dist/RequestResolver.d.ts.map +1 -1
  43. package/dist/RequestResolver.js +4 -10
  44. package/dist/RequestResolver.js.map +1 -1
  45. package/dist/Scheduler.d.ts +9 -0
  46. package/dist/Scheduler.d.ts.map +1 -1
  47. package/dist/Scheduler.js +9 -0
  48. package/dist/Scheduler.js.map +1 -1
  49. package/dist/Schema.d.ts +15 -2
  50. package/dist/Schema.d.ts.map +1 -1
  51. package/dist/Schema.js +16 -2
  52. package/dist/Schema.js.map +1 -1
  53. package/dist/SchemaGetter.d.ts +4 -0
  54. package/dist/SchemaGetter.d.ts.map +1 -1
  55. package/dist/SchemaGetter.js +52 -33
  56. package/dist/SchemaGetter.js.map +1 -1
  57. package/dist/Sink.d.ts.map +1 -1
  58. package/dist/Sink.js +38 -17
  59. package/dist/Sink.js.map +1 -1
  60. package/dist/Stream.d.ts +11 -0
  61. package/dist/Stream.d.ts.map +1 -1
  62. package/dist/Stream.js +16 -1
  63. package/dist/Stream.js.map +1 -1
  64. package/dist/String.d.ts +12 -0
  65. package/dist/String.d.ts.map +1 -1
  66. package/dist/String.js +17 -4
  67. package/dist/String.js.map +1 -1
  68. package/dist/TxRef.d.ts.map +1 -1
  69. package/dist/TxRef.js +3 -2
  70. package/dist/TxRef.js.map +1 -1
  71. package/dist/Utils.js +8 -3
  72. package/dist/Utils.js.map +1 -1
  73. package/dist/ai/AiError.d.ts +10 -10
  74. package/dist/ai/AiError.d.ts.map +1 -1
  75. package/dist/ai/AiError.js +1 -1
  76. package/dist/ai/AiError.js.map +1 -1
  77. package/dist/ai/AnthropicStructuredOutput.js +0 -2
  78. package/dist/ai/AnthropicStructuredOutput.js.map +1 -1
  79. package/dist/ai/Chat.d.ts +2 -2
  80. package/dist/ai/Chat.d.ts.map +1 -1
  81. package/dist/ai/Decision.d.ts +70 -19
  82. package/dist/ai/Decision.d.ts.map +1 -1
  83. package/dist/ai/Decision.js +37 -3
  84. package/dist/ai/Decision.js.map +1 -1
  85. package/dist/ai/DecisionModel.js +1 -1
  86. package/dist/ai/DecisionModel.js.map +1 -1
  87. package/dist/ai/LanguageModel.d.ts +38 -7
  88. package/dist/ai/LanguageModel.d.ts.map +1 -1
  89. package/dist/ai/LanguageModel.js +70 -40
  90. package/dist/ai/LanguageModel.js.map +1 -1
  91. package/dist/ai/McpServer.d.ts +61 -52
  92. package/dist/ai/McpServer.d.ts.map +1 -1
  93. package/dist/ai/McpServer.js +134 -50
  94. package/dist/ai/McpServer.js.map +1 -1
  95. package/dist/ai/Prompt.d.ts.map +1 -1
  96. package/dist/ai/Prompt.js +28 -5
  97. package/dist/ai/Prompt.js.map +1 -1
  98. package/dist/ai/Response.d.ts +5 -4
  99. package/dist/ai/Response.d.ts.map +1 -1
  100. package/dist/ai/Response.js.map +1 -1
  101. package/dist/cli/Completions.d.ts +5 -0
  102. package/dist/cli/Completions.d.ts.map +1 -1
  103. package/dist/cli/Completions.js.map +1 -1
  104. package/dist/cli/Flag.d.ts +100 -0
  105. package/dist/cli/Flag.d.ts.map +1 -1
  106. package/dist/cli/Flag.js +33 -0
  107. package/dist/cli/Flag.js.map +1 -1
  108. package/dist/cli/Param.d.ts +87 -0
  109. package/dist/cli/Param.d.ts.map +1 -1
  110. package/dist/cli/Param.js +30 -0
  111. package/dist/cli/Param.js.map +1 -1
  112. package/dist/cli/internal/command.d.ts.map +1 -1
  113. package/dist/cli/internal/command.js +2 -1
  114. package/dist/cli/internal/command.js.map +1 -1
  115. package/dist/cli/internal/completions/bash.js +4 -3
  116. package/dist/cli/internal/completions/bash.js.map +1 -1
  117. package/dist/cli/internal/completions/descriptor.js +8 -1
  118. package/dist/cli/internal/completions/descriptor.js.map +1 -1
  119. package/dist/cli/internal/completions/fish.js +4 -4
  120. package/dist/cli/internal/completions/fish.js.map +1 -1
  121. package/dist/cli/internal/completions/powershell.js +3 -2
  122. package/dist/cli/internal/completions/powershell.js.map +1 -1
  123. package/dist/cli/internal/completions/zsh.js +7 -3
  124. package/dist/cli/internal/completions/zsh.js.map +1 -1
  125. package/dist/cli/internal/parser.js +11 -3
  126. package/dist/cli/internal/parser.js.map +1 -1
  127. package/dist/cli/internal/wizard.d.ts.map +1 -1
  128. package/dist/cli/internal/wizard.js +2 -1
  129. package/dist/cli/internal/wizard.js.map +1 -1
  130. package/dist/cluster/ClusterWorkflowEngine.d.ts +1 -0
  131. package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
  132. package/dist/cluster/ClusterWorkflowEngine.js +113 -21
  133. package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
  134. package/dist/cluster/MessageStorage.d.ts.map +1 -1
  135. package/dist/cluster/MessageStorage.js +20 -12
  136. package/dist/cluster/MessageStorage.js.map +1 -1
  137. package/dist/cluster/Runners.d.ts.map +1 -1
  138. package/dist/cluster/Runners.js +54 -34
  139. package/dist/cluster/Runners.js.map +1 -1
  140. package/dist/cluster/Sharding.d.ts.map +1 -1
  141. package/dist/cluster/Sharding.js +6 -4
  142. package/dist/cluster/Sharding.js.map +1 -1
  143. package/dist/cluster/internal/entityManager.js +1 -1
  144. package/dist/cluster/internal/entityManager.js.map +1 -1
  145. package/dist/encoding/Sse.d.ts +6 -0
  146. package/dist/encoding/Sse.d.ts.map +1 -1
  147. package/dist/encoding/Sse.js +63 -71
  148. package/dist/encoding/Sse.js.map +1 -1
  149. package/dist/graphql/GraphQL.d.ts +349 -0
  150. package/dist/graphql/GraphQL.d.ts.map +1 -0
  151. package/dist/graphql/GraphQL.js +207 -0
  152. package/dist/graphql/GraphQL.js.map +1 -0
  153. package/dist/graphql/GraphQLClient.d.ts +562 -0
  154. package/dist/graphql/GraphQLClient.d.ts.map +1 -0
  155. package/dist/graphql/GraphQLClient.js +505 -0
  156. package/dist/graphql/GraphQLClient.js.map +1 -0
  157. package/dist/graphql/GraphQLClientError.d.ts +445 -0
  158. package/dist/graphql/GraphQLClientError.d.ts.map +1 -0
  159. package/dist/graphql/GraphQLClientError.js +479 -0
  160. package/dist/graphql/GraphQLClientError.js.map +1 -0
  161. package/dist/graphql/GraphQLGroup.d.ts +118 -0
  162. package/dist/graphql/GraphQLGroup.d.ts.map +1 -0
  163. package/dist/graphql/GraphQLGroup.js +109 -0
  164. package/dist/graphql/GraphQLGroup.js.map +1 -0
  165. package/dist/graphql/GraphQLMiddleware.d.ts +249 -0
  166. package/dist/graphql/GraphQLMiddleware.d.ts.map +1 -0
  167. package/dist/graphql/GraphQLMiddleware.js +130 -0
  168. package/dist/graphql/GraphQLMiddleware.js.map +1 -0
  169. package/dist/graphql/GraphQLProtocol.d.ts +969 -0
  170. package/dist/graphql/GraphQLProtocol.d.ts.map +1 -0
  171. package/dist/graphql/GraphQLProtocol.js +809 -0
  172. package/dist/graphql/GraphQLProtocol.js.map +1 -0
  173. package/dist/graphql/GraphQLResolver.d.ts +453 -0
  174. package/dist/graphql/GraphQLResolver.d.ts.map +1 -0
  175. package/dist/graphql/GraphQLResolver.js +582 -0
  176. package/dist/graphql/GraphQLResolver.js.map +1 -0
  177. package/dist/graphql/index.d.ts +40 -0
  178. package/dist/graphql/index.d.ts.map +1 -0
  179. package/dist/graphql/index.js +41 -0
  180. package/dist/graphql/index.js.map +1 -0
  181. package/dist/http/FetchHttpClient.d.ts +6 -3
  182. package/dist/http/FetchHttpClient.d.ts.map +1 -1
  183. package/dist/http/FetchHttpClient.js +6 -3
  184. package/dist/http/FetchHttpClient.js.map +1 -1
  185. package/dist/http/FindMyWay/internal/router.js +2 -1
  186. package/dist/http/FindMyWay/internal/router.js.map +1 -1
  187. package/dist/http/Headers.d.ts +3 -3
  188. package/dist/http/Headers.d.ts.map +1 -1
  189. package/dist/http/Headers.js +6 -5
  190. package/dist/http/Headers.js.map +1 -1
  191. package/dist/http/HttpClient.d.ts +27 -0
  192. package/dist/http/HttpClient.d.ts.map +1 -1
  193. package/dist/http/HttpClient.js +38 -11
  194. package/dist/http/HttpClient.js.map +1 -1
  195. package/dist/http/HttpClientError.d.ts.map +1 -1
  196. package/dist/http/HttpClientError.js +8 -6
  197. package/dist/http/HttpClientError.js.map +1 -1
  198. package/dist/http/HttpClientRequest.d.ts +147 -4
  199. package/dist/http/HttpClientRequest.d.ts.map +1 -1
  200. package/dist/http/HttpClientRequest.js +47 -1
  201. package/dist/http/HttpClientRequest.js.map +1 -1
  202. package/dist/http/HttpEffect.d.ts.map +1 -1
  203. package/dist/http/HttpEffect.js +14 -7
  204. package/dist/http/HttpEffect.js.map +1 -1
  205. package/dist/http/HttpMiddleware.d.ts +60 -0
  206. package/dist/http/HttpMiddleware.d.ts.map +1 -1
  207. package/dist/http/HttpMiddleware.js +93 -32
  208. package/dist/http/HttpMiddleware.js.map +1 -1
  209. package/dist/http/HttpRouter.d.ts +35 -0
  210. package/dist/http/HttpRouter.d.ts.map +1 -1
  211. package/dist/http/HttpRouter.js +87 -13
  212. package/dist/http/HttpRouter.js.map +1 -1
  213. package/dist/http/HttpServerError.d.ts.map +1 -1
  214. package/dist/http/HttpServerError.js +6 -4
  215. package/dist/http/HttpServerError.js.map +1 -1
  216. package/dist/http/HttpServerRequest.js +2 -2
  217. package/dist/http/HttpServerRequest.js.map +1 -1
  218. package/dist/http/HttpServerResponse.d.ts +8 -6
  219. package/dist/http/HttpServerResponse.d.ts.map +1 -1
  220. package/dist/http/HttpServerResponse.js +27 -16
  221. package/dist/http/HttpServerResponse.js.map +1 -1
  222. package/dist/http/HttpStaticServer.d.ts.map +1 -1
  223. package/dist/http/HttpStaticServer.js +4 -10
  224. package/dist/http/HttpStaticServer.js.map +1 -1
  225. package/dist/http/HttpTraceContext.js +1 -1
  226. package/dist/http/HttpTraceContext.js.map +1 -1
  227. package/dist/http/Multipart.d.ts.map +1 -1
  228. package/dist/http/Multipart.js +15 -1
  229. package/dist/http/Multipart.js.map +1 -1
  230. package/dist/http/Url.d.ts.map +1 -1
  231. package/dist/http/Url.js +2 -1
  232. package/dist/http/Url.js.map +1 -1
  233. package/dist/http/UrlParams.d.ts +112 -8
  234. package/dist/http/UrlParams.d.ts.map +1 -1
  235. package/dist/http/UrlParams.js +141 -14
  236. package/dist/http/UrlParams.js.map +1 -1
  237. package/dist/http/internal/compression.d.ts +1 -1
  238. package/dist/http/internal/compression.d.ts.map +1 -1
  239. package/dist/http/internal/compression.js +2 -10
  240. package/dist/http/internal/compression.js.map +1 -1
  241. package/dist/http/internal/compressionBody.d.ts +2 -0
  242. package/dist/http/internal/compressionBody.d.ts.map +1 -0
  243. package/dist/http/internal/compressionBody.js +36 -0
  244. package/dist/http/internal/compressionBody.js.map +1 -0
  245. package/dist/http/internal/decompression.d.ts +2 -0
  246. package/dist/http/internal/decompression.d.ts.map +1 -0
  247. package/dist/http/internal/decompression.js +162 -0
  248. package/dist/http/internal/decompression.js.map +1 -0
  249. package/dist/http/internal/tracing.js +14 -4
  250. package/dist/http/internal/tracing.js.map +1 -1
  251. package/dist/http/internal/urlParams.d.ts +2 -0
  252. package/dist/http/internal/urlParams.d.ts.map +1 -0
  253. package/dist/http/internal/urlParams.js +4 -0
  254. package/dist/http/internal/urlParams.js.map +1 -0
  255. package/dist/http-api/HttpApiClient.d.ts.map +1 -1
  256. package/dist/http-api/HttpApiClient.js +2 -1
  257. package/dist/http-api/HttpApiClient.js.map +1 -1
  258. package/dist/http-api/HttpApiScalar.d.ts +5 -0
  259. package/dist/http-api/HttpApiScalar.d.ts.map +1 -1
  260. package/dist/http-api/HttpApiScalar.js.map +1 -1
  261. package/dist/internal/core.js +17 -1
  262. package/dist/internal/core.js.map +1 -1
  263. package/dist/internal/dateTime.js +40 -35
  264. package/dist/internal/dateTime.js.map +1 -1
  265. package/dist/internal/effect.js +13 -6
  266. package/dist/internal/effect.js.map +1 -1
  267. package/dist/internal/graphql.d.ts +2 -0
  268. package/dist/internal/graphql.d.ts.map +1 -0
  269. package/dist/internal/graphql.js +205 -0
  270. package/dist/internal/graphql.js.map +1 -0
  271. package/dist/internal/graphqlHeaders.d.ts +4 -0
  272. package/dist/internal/graphqlHeaders.d.ts.map +1 -0
  273. package/dist/internal/graphqlHeaders.js +11 -0
  274. package/dist/internal/graphqlHeaders.js.map +1 -0
  275. package/dist/internal/request.js +20 -1
  276. package/dist/internal/request.js.map +1 -1
  277. package/dist/internal/schema/toCodeDocument.js +4 -1
  278. package/dist/internal/schema/toCodeDocument.js.map +1 -1
  279. package/dist/internal/schema/toJsonSchemaDocument.js +29 -5
  280. package/dist/internal/schema/toJsonSchemaDocument.js.map +1 -1
  281. package/dist/internal/version.js +1 -1
  282. package/dist/net/Host.d.ts +49 -0
  283. package/dist/net/Host.d.ts.map +1 -1
  284. package/dist/net/Host.js +55 -0
  285. package/dist/net/Host.js.map +1 -1
  286. package/dist/net/NetAddress.d.ts +8 -0
  287. package/dist/net/NetAddress.d.ts.map +1 -1
  288. package/dist/net/NetAddress.js +8 -0
  289. package/dist/net/NetAddress.js.map +1 -1
  290. package/dist/observability/Otlp.d.ts +15 -0
  291. package/dist/observability/Otlp.d.ts.map +1 -1
  292. package/dist/observability/Otlp.js +3 -0
  293. package/dist/observability/Otlp.js.map +1 -1
  294. package/dist/observability/OtlpExporter.d.ts +8 -0
  295. package/dist/observability/OtlpExporter.d.ts.map +1 -1
  296. package/dist/observability/OtlpExporter.js +10 -1
  297. package/dist/observability/OtlpExporter.js.map +1 -1
  298. package/dist/observability/OtlpLogger.d.ts +17 -0
  299. package/dist/observability/OtlpLogger.d.ts.map +1 -1
  300. package/dist/observability/OtlpLogger.js +14 -1
  301. package/dist/observability/OtlpLogger.js.map +1 -1
  302. package/dist/observability/OtlpMetrics.d.ts +17 -0
  303. package/dist/observability/OtlpMetrics.d.ts.map +1 -1
  304. package/dist/observability/OtlpMetrics.js +13 -0
  305. package/dist/observability/OtlpMetrics.js.map +1 -1
  306. package/dist/observability/OtlpTracer.d.ts +17 -0
  307. package/dist/observability/OtlpTracer.d.ts.map +1 -1
  308. package/dist/observability/OtlpTracer.js +15 -2
  309. package/dist/observability/OtlpTracer.js.map +1 -1
  310. package/dist/reactivity/AsyncResult.d.ts +6 -0
  311. package/dist/reactivity/AsyncResult.d.ts.map +1 -1
  312. package/dist/reactivity/AsyncResult.js +27 -0
  313. package/dist/reactivity/AsyncResult.js.map +1 -1
  314. package/dist/reactivity/AtomRegistry.js +3 -1
  315. package/dist/reactivity/AtomRegistry.js.map +1 -1
  316. package/dist/rpc/RpcClient.d.ts.map +1 -1
  317. package/dist/rpc/RpcClient.js +6 -1
  318. package/dist/rpc/RpcClient.js.map +1 -1
  319. package/dist/rpc/RpcServer.d.ts.map +1 -1
  320. package/dist/rpc/RpcServer.js +36 -9
  321. package/dist/rpc/RpcServer.js.map +1 -1
  322. package/dist/socket/Socket.d.ts +6 -0
  323. package/dist/socket/Socket.d.ts.map +1 -1
  324. package/dist/socket/Socket.js.map +1 -1
  325. package/dist/sql/SqlClient.d.ts +8 -7
  326. package/dist/sql/SqlClient.d.ts.map +1 -1
  327. package/dist/sql/SqlClient.js +8 -7
  328. package/dist/sql/SqlClient.js.map +1 -1
  329. package/dist/testing/TestClock.d.ts +16 -3
  330. package/dist/testing/TestClock.d.ts.map +1 -1
  331. package/dist/testing/TestClock.js +112 -22
  332. package/dist/testing/TestClock.js.map +1 -1
  333. package/dist/workflow/Activity.js +1 -0
  334. package/dist/workflow/Activity.js.map +1 -1
  335. package/dist/workflow/DurableDeferred.d.ts.map +1 -1
  336. package/dist/workflow/DurableDeferred.js +32 -3
  337. package/dist/workflow/DurableDeferred.js.map +1 -1
  338. package/dist/workflow/Workflow.d.ts +22 -0
  339. package/dist/workflow/Workflow.d.ts.map +1 -1
  340. package/dist/workflow/Workflow.js +15 -3
  341. package/dist/workflow/Workflow.js.map +1 -1
  342. package/dist/workflow/WorkflowEngine.d.ts +44 -3
  343. package/dist/workflow/WorkflowEngine.d.ts.map +1 -1
  344. package/dist/workflow/WorkflowEngine.js +45 -22
  345. package/dist/workflow/WorkflowEngine.js.map +1 -1
  346. package/package.json +6 -3
  347. package/src/Array.ts +95 -6
  348. package/src/Channel.ts +24 -3
  349. package/src/ConfigProvider.ts +40 -44
  350. package/src/Context.ts +9 -0
  351. package/src/Duration.ts +4 -5
  352. package/src/Effect.ts +140 -53
  353. package/src/FileSystem.ts +23 -9
  354. package/src/Match.ts +65 -12
  355. package/src/Path.ts +52 -7
  356. package/src/RequestResolver.ts +4 -10
  357. package/src/Scheduler.ts +9 -0
  358. package/src/Schema.ts +25 -4
  359. package/src/SchemaGetter.ts +47 -35
  360. package/src/Sink.ts +45 -18
  361. package/src/Stream.ts +33 -4
  362. package/src/String.ts +17 -4
  363. package/src/TxRef.ts +4 -2
  364. package/src/Utils.ts +8 -5
  365. package/src/ai/AiError.ts +3 -1
  366. package/src/ai/AnthropicStructuredOutput.ts +2 -2
  367. package/src/ai/Chat.ts +2 -2
  368. package/src/ai/Decision.ts +70 -21
  369. package/src/ai/DecisionModel.ts +1 -1
  370. package/src/ai/LanguageModel.ts +141 -63
  371. package/src/ai/McpServer.ts +259 -145
  372. package/src/ai/Prompt.ts +24 -10
  373. package/src/ai/Response.ts +6 -3
  374. package/src/cli/Completions.ts +5 -0
  375. package/src/cli/Flag.ts +101 -0
  376. package/src/cli/Param.ts +96 -0
  377. package/src/cli/internal/command.ts +2 -1
  378. package/src/cli/internal/completions/bash.ts +4 -3
  379. package/src/cli/internal/completions/descriptor.ts +10 -1
  380. package/src/cli/internal/completions/fish.ts +4 -4
  381. package/src/cli/internal/completions/powershell.ts +5 -2
  382. package/src/cli/internal/completions/zsh.ts +7 -3
  383. package/src/cli/internal/parser.ts +12 -3
  384. package/src/cli/internal/wizard.ts +2 -1
  385. package/src/cluster/ClusterWorkflowEngine.ts +143 -36
  386. package/src/cluster/MessageStorage.ts +14 -3
  387. package/src/cluster/Runners.ts +88 -66
  388. package/src/cluster/Sharding.ts +12 -9
  389. package/src/cluster/internal/entityManager.ts +1 -1
  390. package/src/encoding/Sse.ts +70 -80
  391. package/src/graphql/GraphQL.ts +494 -0
  392. package/src/graphql/GraphQLClient.ts +924 -0
  393. package/src/graphql/GraphQLClientError.ts +542 -0
  394. package/src/graphql/GraphQLGroup.ts +167 -0
  395. package/src/graphql/GraphQLMiddleware.ts +253 -0
  396. package/src/graphql/GraphQLProtocol.ts +1540 -0
  397. package/src/graphql/GraphQLResolver.ts +1038 -0
  398. package/src/graphql/index.ts +48 -0
  399. package/src/http/FetchHttpClient.ts +6 -3
  400. package/src/http/FindMyWay/internal/router.ts +2 -1
  401. package/src/http/Headers.ts +6 -9
  402. package/src/http/HttpClient.ts +72 -11
  403. package/src/http/HttpClientError.ts +10 -6
  404. package/src/http/HttpClientRequest.ts +173 -7
  405. package/src/http/HttpEffect.ts +11 -5
  406. package/src/http/HttpMiddleware.ts +113 -34
  407. package/src/http/HttpRouter.ts +95 -13
  408. package/src/http/HttpServerError.ts +8 -4
  409. package/src/http/HttpServerRequest.ts +2 -2
  410. package/src/http/HttpServerResponse.ts +28 -16
  411. package/src/http/HttpStaticServer.ts +4 -10
  412. package/src/http/HttpTraceContext.ts +1 -1
  413. package/src/http/Multipart.ts +17 -1
  414. package/src/http/Url.ts +2 -1
  415. package/src/http/UrlParams.ts +225 -26
  416. package/src/http/internal/compression.ts +3 -17
  417. package/src/http/internal/compressionBody.ts +56 -0
  418. package/src/http/internal/decompression.ts +226 -0
  419. package/src/http/internal/tracing.ts +21 -4
  420. package/src/http/internal/urlParams.ts +5 -0
  421. package/src/http-api/HttpApiClient.ts +2 -1
  422. package/src/http-api/HttpApiScalar.ts +5 -0
  423. package/src/internal/core.ts +21 -1
  424. package/src/internal/dateTime.ts +13 -10
  425. package/src/internal/effect.ts +13 -7
  426. package/src/internal/graphql.ts +286 -0
  427. package/src/internal/graphqlHeaders.ts +11 -0
  428. package/src/internal/request.ts +31 -3
  429. package/src/internal/schema/toCodeDocument.ts +7 -1
  430. package/src/internal/schema/toJsonSchemaDocument.ts +34 -2
  431. package/src/internal/version.ts +1 -1
  432. package/src/net/Host.ts +72 -0
  433. package/src/net/NetAddress.ts +9 -0
  434. package/src/observability/Otlp.ts +18 -0
  435. package/src/observability/OtlpExporter.ts +14 -3
  436. package/src/observability/OtlpLogger.ts +31 -2
  437. package/src/observability/OtlpMetrics.ts +30 -1
  438. package/src/observability/OtlpTracer.ts +32 -3
  439. package/src/reactivity/AsyncResult.ts +31 -0
  440. package/src/reactivity/AtomRegistry.ts +3 -1
  441. package/src/rpc/RpcClient.ts +6 -1
  442. package/src/rpc/RpcServer.ts +55 -15
  443. package/src/socket/Socket.ts +6 -0
  444. package/src/sql/SqlClient.ts +9 -7
  445. package/src/testing/TestClock.ts +144 -29
  446. package/src/workflow/Activity.ts +1 -0
  447. package/src/workflow/DurableDeferred.ts +43 -5
  448. package/src/workflow/Workflow.ts +31 -5
  449. package/src/workflow/WorkflowEngine.ts +107 -25
package/src/Match.ts CHANGED
@@ -712,6 +712,26 @@ export const withReturnType: <Ret>() => <I, F, R, A, Pr, _, Args extends Array<a
712
712
  ) => [Ret] extends [[A] extends [never] ? any : A] ? Matcher<I, F, R, A, Pr, Ret, Args>
713
713
  : "withReturnType constraint does not extend Result type" = internal.withReturnType
714
714
 
715
+ // `P` is a const type parameter, so object literals skip excess-property checks.
716
+ // Reject pattern keys that no object variant of the input has. Functions,
717
+ // refinements, and array patterns are not checked.
718
+ type PatternKey<K> = K extends number ? `${K}` : K
719
+
720
+ type PatternKeys<A> = object extends A ? PropertyKey
721
+ : A extends object ? PatternKey<keyof A>
722
+ : never
723
+
724
+ type ObjectPatternGuard<A, P> = [P] extends [Function | ReadonlyArray<any> | SafeRefinement<never, any>] ? unknown
725
+ : [P] extends [object] ? { readonly [K in Exclude<PatternKey<keyof P>, PatternKeys<A>>]: never }
726
+ : unknown
727
+
728
+ type ExactPattern<R, P> = (Types.PatternPrimitive<R> | Types.PatternBase<R>) & ObjectPatternGuard<R, P>
729
+
730
+ type ExactPatterns<R, P> = {
731
+ readonly [I in keyof P]: I extends number | `${number}` ? P[I] & ExactPattern<R, P[I]>
732
+ : P[I]
733
+ }
734
+
715
735
  /**
716
736
  * Defines a condition for matching values.
717
737
  *
@@ -763,7 +783,7 @@ export const withReturnType: <Ret>() => <I, F, R, A, Pr, _, Args extends Array<a
763
783
  */
764
784
  export const when: <
765
785
  R,
766
- const P extends Types.PatternPrimitive<R> | Types.PatternBase<R>,
786
+ const P extends ExactPattern<R, P>,
767
787
  Ret,
768
788
  Args extends Array<any>,
769
789
  Fn extends (_: Types.WhenMatch<R, P>, ...args: Args) => Ret
@@ -831,7 +851,7 @@ export const whenOr: <
831
851
  Args extends Array<any>,
832
852
  Fn extends (_: Types.WhenMatch<R, P[number]>, ...args: Args) => Ret
833
853
  >(
834
- ...args: [...patterns: P, f: Fn]
854
+ ...args: [...patterns: ExactPatterns<R, P>, f: Fn]
835
855
  ) => <I, F, A, Pr>(
836
856
  self: Matcher<I, F, R, A, Pr, Ret, Args>
837
857
  ) => Matcher<
@@ -842,7 +862,13 @@ export const whenOr: <
842
862
  Pr,
843
863
  Ret,
844
864
  Args
845
- > = internal.whenOr
865
+ > = <
866
+ R,
867
+ const P extends ReadonlyArray<Types.PatternPrimitive<R> | Types.PatternBase<R>>,
868
+ Ret,
869
+ Args extends Array<any>,
870
+ Fn extends (_: Types.WhenMatch<R, P[number]>, ...args: Args) => Ret
871
+ >(...args: [...patterns: ExactPatterns<R, P>, f: Fn]) => internal.whenOr<R, P, Ret, Args, Fn>(...args)
846
872
 
847
873
  /**
848
874
  * Matches a value that satisfies all provided patterns.
@@ -890,7 +916,7 @@ export const whenAnd: <
890
916
  Args extends Array<any>,
891
917
  Fn extends (_: Types.WhenMatch<R, T.UnionToIntersection<P[number]>>, ...args: Args) => Ret
892
918
  >(
893
- ...args: [...patterns: P, f: Fn]
919
+ ...args: [...patterns: ExactPatterns<R, P>, f: Fn]
894
920
  ) => <I, F, A, Pr>(
895
921
  self: Matcher<I, F, R, A, Pr, Ret, Args>
896
922
  ) => Matcher<
@@ -901,7 +927,13 @@ export const whenAnd: <
901
927
  Pr,
902
928
  Ret,
903
929
  Args
904
- > = internal.whenAnd
930
+ > = <
931
+ R,
932
+ const P extends ReadonlyArray<Types.PatternPrimitive<R> | Types.PatternBase<R>>,
933
+ Ret,
934
+ Args extends Array<any>,
935
+ Fn extends (_: Types.WhenMatch<R, T.UnionToIntersection<P[number]>>, ...args: Args) => Ret
936
+ >(...args: [...patterns: ExactPatterns<R, P>, f: Fn]) => internal.whenAnd<R, P, Ret, Args, Fn>(...args)
905
937
 
906
938
  /**
907
939
  * Matches values based on a specified discriminant field.
@@ -1398,7 +1430,7 @@ export const tagsExhaustive: <
1398
1430
  */
1399
1431
  export const not: <
1400
1432
  R,
1401
- const P extends Types.PatternPrimitive<R> | Types.PatternBase<R>,
1433
+ const P extends ExactPattern<R, P>,
1402
1434
  Ret,
1403
1435
  Args extends Array<any>,
1404
1436
  Fn extends (_: Types.NotMatch<R, P>, ...args: Args) => Ret
@@ -2835,6 +2867,32 @@ export declare namespace Types {
2835
2867
 
2836
2868
  type Simplify<A> = { [K in keyof A]: A[K] } & {}
2837
2869
 
2870
+ // Tuple patterns match a prefix at runtime. For inputs with a variadic part,
2871
+ // narrow each position the pattern requires and keep the rest of the input.
2872
+ type NarrowArrayPattern<I extends ReadonlyArray<any>, P extends ReadonlyArray<any>> = number extends I["length"]
2873
+ ? number extends P["length"] ? MapArrayPattern<I, P>
2874
+ : P["length"] extends Required<P>["length"] ? NarrowArrayPrefix<I, P>
2875
+ : MapArrayPattern<I, P>
2876
+ : MapArrayPattern<I, P>
2877
+
2878
+ type MapArrayPattern<I, P> = {
2879
+ readonly [K in keyof I]: K extends keyof P ? ExtractAndNarrow<I[K], P[K]> : I[K]
2880
+ } extends infer R ? Fail extends R[keyof R] ? never
2881
+ : R
2882
+ : never
2883
+
2884
+ type NarrowArrayPrefix<
2885
+ I extends ReadonlyArray<any>,
2886
+ P extends ReadonlyArray<any>,
2887
+ Out extends ReadonlyArray<any> = readonly []
2888
+ > = P extends readonly [infer PH, ...infer PT] ?
2889
+ I extends readonly [infer IH, ...infer IT] ?
2890
+ [ExtractAndNarrow<IH, PH>] extends [infer N] ? [N] extends [never] ? never
2891
+ : NarrowArrayPrefix<IT, PT, readonly [...Out, N]>
2892
+ : never
2893
+ : NarrowArrayPrefix<readonly [I[number], ...Array<I[number]>], P, Out>
2894
+ : readonly [...Out, ...I]
2895
+
2838
2896
  type ExtractAndNarrow<Input, P> = P extends Predicate.Refinement<infer _In, infer _Out> ?
2839
2897
  _Out extends Input ? Extract<_Out, Input>
2840
2898
  : Extract<Input, _Out> :
@@ -2843,12 +2901,7 @@ export declare namespace Types {
2843
2901
  : Extract<Input, _In>
2844
2902
  : P extends Predicate.Predicate<infer _In> ? Extract<Input, _In>
2845
2903
  : Input extends infer I ? Exclude<
2846
- I extends ReadonlyArray<any> ? P extends ReadonlyArray<any> ? {
2847
- readonly [K in keyof I]: K extends keyof P ? ExtractAndNarrow<I[K], P[K]>
2848
- : I[K]
2849
- } extends infer R ? Fail extends R[keyof R] ? never
2850
- : R
2851
- : never
2904
+ I extends ReadonlyArray<any> ? P extends ReadonlyArray<any> ? NarrowArrayPattern<I, P>
2852
2905
  : never
2853
2906
  : IsPlainObject<I> extends true ? string extends keyof I ? I extends P ? I
2854
2907
  : never
package/src/Path.ts CHANGED
@@ -14,6 +14,7 @@ import * as Context from "./Context.ts"
14
14
  import * as Effect from "./Effect.ts"
15
15
  import { identity } from "./Function.ts"
16
16
  import * as Layer from "./Layer.ts"
17
+ import * as Option from "./Option.ts"
17
18
  import { BadArgument } from "./PlatformError.ts"
18
19
 
19
20
  /**
@@ -47,10 +48,17 @@ export const TypeId = "~effect/Path"
47
48
  * formatting, and converting file system paths. URL conversion methods return
48
49
  * `Effect`s because invalid file URLs or paths can fail with `BadArgument`.
49
50
  *
51
+ * `resolveWithin(root, input)` resolves a relative `input` beneath `root` and
52
+ * returns `Option.none()` when the result would leave the root or when `input`
53
+ * has its own root (an absolute path, or a Windows drive or UNC prefix). The
54
+ * root itself is allowed. The check is lexical: it does not follow symlinks,
55
+ * so it is not a sandbox on its own. A relative `root` is resolved against the
56
+ * current working directory, as with `resolve`.
57
+ *
50
58
  * **Example** (Using path operations)
51
59
  *
52
60
  * ```ts import.meta.vitest
53
- * import { Effect, Path } from "effect"
61
+ * import { Effect, Option, Path } from "effect"
54
62
  *
55
63
  * const program = Effect.gen(function*() {
56
64
  * const path = yield* Path.Path
@@ -64,7 +72,8 @@ export const TypeId = "~effect/Path"
64
72
  * isAbsolute: path.isAbsolute("/absolute/path"),
65
73
  * name: path.parse("/path/to/file.txt").name,
66
74
  * relative: path.relative("/from/path", "/to/path"),
67
- * resolved: path.resolve("/base", "relative", "path")
75
+ * resolved: path.resolve("/base", "relative", "path"),
76
+ * within: path.resolveWithin("/base", "../outside")
68
77
  * }
69
78
  * })
70
79
  *
@@ -78,6 +87,7 @@ export const TypeId = "~effect/Path"
78
87
  * result.name // => "file"
79
88
  * result.relative // => "../../to/path"
80
89
  * result.resolved // => "/base/relative/path"
90
+ * result.within // => Option.none()
81
91
  * ```
82
92
  *
83
93
  * @stability unstable
@@ -98,6 +108,7 @@ export interface Path {
98
108
  readonly parse: (path: string) => Path.Parsed
99
109
  readonly relative: (from: string, to: string) => string
100
110
  readonly resolve: (...pathSegments: ReadonlyArray<string>) => string
111
+ readonly resolveWithin: (root: string, input: string) => Option.Option<string>
101
112
  readonly toFileUrl: (path: string) => Effect.Effect<URL, BadArgument>
102
113
  readonly toNamespacedPath: (path: string) => string
103
114
  }
@@ -204,8 +215,7 @@ export declare namespace Path {
204
215
  * import { Effect, Layer, Path } from "effect"
205
216
  *
206
217
  * // Create a custom path implementation
207
- * const customPath: Path.Path = {
208
- * [Path.TypeId]: Path.TypeId,
218
+ * const customPath = Path.make({
209
219
  * sep: "/",
210
220
  * basename: (path: string, suffix?: string) => {
211
221
  * const base = path.split("/").pop() || ""
@@ -239,7 +249,7 @@ export declare namespace Path {
239
249
  * resolve: (...pathSegments: ReadonlyArray<string>) => pathSegments.join("/"),
240
250
  * toFileUrl: (path: string) => Effect.succeed(new URL(`file://${path}`)),
241
251
  * toNamespacedPath: (path: string) => path
242
- * }
252
+ * })
243
253
  *
244
254
  * // Provide the path service
245
255
  * const customPathLayer = Layer.succeed(Path.Path)(customPath)
@@ -259,6 +269,42 @@ export declare namespace Path {
259
269
  */
260
270
  export const Path: Context.Service<Path, Path> = Context.Service("effect/Path")
261
271
 
272
+ /**
273
+ * Creates a `Path` service from platform path operations.
274
+ *
275
+ * **When to use**
276
+ *
277
+ * Use to build a `Path` implementation, such as a platform layer or a test
278
+ * double, without implementing the operations that can be derived from the
279
+ * others.
280
+ *
281
+ * **Details**
282
+ *
283
+ * Adds the `Path` type marker and derives `resolveWithin` from the provided
284
+ * `parse`, `resolve`, `relative`, `isAbsolute`, and `sep`, so containment
285
+ * follows the same platform rules as those operations.
286
+ *
287
+ * @see {@link layer} for the built-in POSIX `Path` service layer
288
+ *
289
+ * @stability unstable
290
+ * @category constructors
291
+ * @since 4.0.0
292
+ */
293
+ export const make = (impl: Omit<Path, typeof TypeId | "resolveWithin">): Path =>
294
+ Path.of({
295
+ ...impl,
296
+ [TypeId]: TypeId,
297
+ resolveWithin(root, input) {
298
+ if (impl.parse(input).root !== "") return Option.none()
299
+ const base = impl.resolve(root)
300
+ const candidate = impl.resolve(base, input)
301
+ const relative = impl.relative(base, candidate)
302
+ return relative === ".." || relative.startsWith(`..${impl.sep}`) || impl.isAbsolute(relative)
303
+ ? Option.none()
304
+ : Option.some(candidate)
305
+ }
306
+ })
307
+
262
308
  /**
263
309
  * The following functions are adapted from the Node.js source code:
264
310
  * https://github.com/nodejs/node/blob/main/lib/internal/url.js
@@ -479,8 +525,7 @@ function encodePathChars(filepath: string) {
479
525
  return filepath
480
526
  }
481
527
 
482
- const posixImpl = Path.of({
483
- [TypeId]: TypeId,
528
+ const posixImpl = make({
484
529
  resolve,
485
530
  normalize(path) {
486
531
  if (path.length === 0) return "."
@@ -311,16 +311,10 @@ export const makeGrouped = <A extends Request.Any, K>(options: {
311
311
  })
312
312
 
313
313
  const hashGroupKey = <A, K>(get: (entry: Request.Entry<A>) => K) => {
314
- const groupKeys = MutableHashMap.empty<K, K>()
315
- return (entry: Request.Entry<A>): unknown => {
316
- const key = get(entry)
317
- const okey = MutableHashMap.get(groupKeys, key)
318
- if (okey._tag === "Some") {
319
- return okey.value
320
- }
321
- MutableHashMap.set(groupKeys, key, key)
322
- return key
323
- }
314
+ // Pending batches match equal keys, so they share one batch.
315
+ const batchKey = (entry: Request.Entry<A>): unknown => get(entry)
316
+ internal.equalBatchKeys.add(batchKey)
317
+ return batchKey
324
318
  }
325
319
 
326
320
  /**
package/src/Scheduler.ts CHANGED
@@ -160,6 +160,15 @@ class PriorityBuckets {
160
160
  * operation counts to decide when fibers should yield, and is the default
161
161
  * scheduler implementation.
162
162
  *
163
+ * **Gotchas**
164
+ *
165
+ * On Cloudflare Workers, request-owned scheduler timers can be discarded,
166
+ * leaving shared fibers suspended. Use `new MixedScheduler("sync")` for the
167
+ * whole application; see `HttpRouter.toWebHandler` for a recipe.
168
+ * Sync mode does not yield to the event loop: CPU-heavy work delays other
169
+ * requests, and I/O-polling loops can exhaust the CPU limit. It does not fix
170
+ * request-owned timers (such as `Effect.sleep`) or request-bound async contexts.
171
+ *
163
172
  * @stability stable
164
173
  * @category models
165
174
  * @since 2.0.0
package/src/Schema.ts CHANGED
@@ -36,6 +36,7 @@ import * as HashMap_ from "./HashMap.ts"
36
36
  import * as HashSet_ from "./HashSet.ts"
37
37
  import * as Cookies_ from "./http/Cookies.ts"
38
38
  import * as Headers_ from "./http/Headers.ts"
39
+ import * as UrlParams_internal from "./http/internal/urlParams.ts"
39
40
  import * as UrlParams_ from "./http/UrlParams.ts"
40
41
  import { NodeInspectSymbol } from "./Inspectable.ts"
41
42
  import * as core from "./internal/core.ts"
@@ -4029,6 +4030,7 @@ export declare namespace StructWithRest {
4029
4030
  */
4030
4031
  type Objects = Constraint & {
4031
4032
  readonly ast: SchemaAST.Objects
4033
+ readonly Encoded: object
4032
4034
  }
4033
4035
  /**
4034
4036
  * Readonly list of record schemas that provide the additional index signatures
@@ -4198,6 +4200,13 @@ export interface StructWithRest<
4198
4200
  *
4199
4201
  * **Gotchas**
4200
4202
  *
4203
+ * The base schema must have an object-shaped encoded type. Whole-object
4204
+ * transformations are not supported, even with an empty rest array. Apply
4205
+ * transformations such as `Schema.fromJsonString` to the completed
4206
+ * `StructWithRest` schema instead. Object-shaped encoded types alone do not
4207
+ * guarantee compatibility: unsupported encodings are still rejected at runtime.
4208
+ * Transformations on individual fields remain supported.
4209
+ *
4201
4210
  * TypeScript index signatures also apply to fixed keys. `StructWithRest` does
4202
4211
  * not reject incompatible fixed fields at the call site; use
4203
4212
  * `StructWithRest.ValidateRecords` when you want an explicit type-level
@@ -5958,6 +5967,9 @@ export type DecodingDefaultOptions = {
5958
5967
  function toIssueEffect<A, R>(
5959
5968
  self: Effect.Effect<A, SchemaError, R>
5960
5969
  ): Effect.Effect<A, SchemaIssue.Issue, R> {
5970
+ if (effectIsExit(self) && self._tag === "Success") {
5971
+ return self as unknown as Exit_.Exit<A, SchemaIssue.Issue>
5972
+ }
5961
5973
  return Effect.catchCause(self, (cause) => Effect.failCauseSync(() => Cause_.map(cause, (error) => error.issue)))
5962
5974
  }
5963
5975
  /**
@@ -6304,6 +6316,12 @@ type Flatten<Schemas> = Schemas extends readonly [infer Head, ...infer Tail]
6304
6316
  ? Head extends Union<infer Inner> ? [...Flatten<Inner>, ...Flatten<Tail>]
6305
6317
  : [Head, ...Flatten<Tail>]
6306
6318
  : []
6319
+ type DiscriminantKey<T extends PropertyKey> = T extends number ? `${T}` : T
6320
+ type EnsureUniqueDiscriminants<Tags extends ReadonlyArray<PropertyKey>, Seen = never> = Tags extends
6321
+ readonly [infer Head extends PropertyKey, ...infer Tail extends ReadonlyArray<PropertyKey>]
6322
+ ? [DiscriminantKey<Head> & Seen] extends [never] ? EnsureUniqueDiscriminants<Tail, Seen | DiscriminantKey<Head>>
6323
+ : never
6324
+ : unknown
6307
6325
  type MatchCasesResult<Cases> = {
6308
6326
  [K in keyof Cases]-?: NonNullable<Cases[K]> extends (...args: Array<any>) => infer R ? R : never
6309
6327
  }[keyof Cases]
@@ -6388,7 +6406,10 @@ export type toTaggedUnion<
6388
6406
  *
6389
6407
  * **Gotchas**
6390
6408
  *
6391
- * Throws if multiple members use the same discriminant property key.
6409
+ * Rejects overlapping discriminant types in known member tuples at compile
6410
+ * time, including nested unions. Numeric and string values such as `1` and
6411
+ * `"1"` count as duplicates. Also throws at runtime if multiple members use the
6412
+ * same discriminant property key.
6392
6413
  *
6393
6414
  * **Example** (Adding tagged-union utilities to an existing union)
6394
6415
  *
@@ -6415,7 +6436,7 @@ export type toTaggedUnion<
6415
6436
  */
6416
6437
  export function toTaggedUnion<const Tag extends PropertyKey>(tag: Tag) {
6417
6438
  return <const Members extends ReadonlyArray<Constraint & { readonly Type: { readonly [K in Tag]: PropertyKey } }>>(
6418
- self: Union<Members>
6439
+ self: Union<Members> & NoInfer<EnsureUniqueDiscriminants<TaggedUnionUtils<Tag, Members>["discriminants"]>>
6419
6440
  ): toTaggedUnion<Tag, Members> => {
6420
6441
  const cases: Record<PropertyKey, unknown> = {}
6421
6442
  const discriminants: Array<PropertyKey> = []
@@ -15213,9 +15234,9 @@ export const UrlParams: UrlParams = declare(
15213
15234
  toCodec: () =>
15214
15235
  link<UrlParams_.UrlParams>()(
15215
15236
  ArraySchema(Tuple([String, String])),
15216
- SchemaTransformation.transform({
15237
+ SchemaTransformation.transform<UrlParams_.UrlParams, ReadonlyArray<readonly [string, string]>>({
15217
15238
  decode: UrlParams_.make,
15218
- encode: (self) => self.params
15239
+ encode: (self) => self.params.map(([key, value]) => [key, UrlParams_internal.unwrap(value)])
15219
15240
  })
15220
15241
  )
15221
15242
  }
@@ -2264,6 +2264,8 @@ function bracketPathToTokens(bracketPath: string): Array<string | number> {
2264
2264
  .map((part) => (Arr.isCanonicalArrayIndex(part) ? globalThis.Number(part) : part))
2265
2265
  }
2266
2266
 
2267
+ const MAX_ARRAY_HOLES = 20
2268
+
2267
2269
  /**
2268
2270
  * Builds a nested tree object from a list of bracket-path entries.
2269
2271
  *
@@ -2287,6 +2289,10 @@ function bracketPathToTokens(bracketPath: string): Array<string | number> {
2287
2289
  * - `""` → real empty key
2288
2290
  * - Numeric bracket segments become array indices only when they are valid
2289
2291
  * JavaScript array-index strings; otherwise they remain object keys.
2292
+ * - An indexed container becomes an array only when it has at most 20 holes
2293
+ * (missing indices below its highest index). Otherwise it is returned as an
2294
+ * object keyed by the index strings, so untrusted input such as
2295
+ * `a[4294967294]` cannot produce huge sparse arrays.
2290
2296
  * - Duplicate keys for the same path are merged into arrays.
2291
2297
  * - If a structural path conflicts with a previous leaf or a different container
2292
2298
  * type, the later structural path replaces the conflicting value.
@@ -2319,43 +2325,31 @@ export function makeTreeRecord<A>(
2319
2325
  const out: any = {}
2320
2326
  const containers = new WeakSet<object>()
2321
2327
  const duplicates = new WeakSet<object>()
2322
-
2323
- function getOrCreateContainer(self: any, key: PropertyKey, shouldBeArray: boolean): any {
2324
- const current = Object.hasOwn(self, key) ? self[key] : undefined
2325
- if (containers.has(current) && Array.isArray(current) === shouldBeArray) {
2326
- return current
2327
- }
2328
- const container = shouldBeArray ? [] : {}
2329
- containers.add(container)
2330
- InternalRecord.assignProperty(self, key, container)
2331
- return container
2332
- }
2328
+ // Indexed containers are built as plain objects so that large indices never
2329
+ // allocate sparse arrays, and are materialized once all entries are applied
2330
+ const indexed = new Map<object, { readonly parent: any; readonly key: PropertyKey; length: number }>()
2333
2331
 
2334
2332
  bracketPathEntries.forEach(([key, value]) => {
2335
2333
  const tokens = bracketPathToTokens(key)
2336
2334
  let cur: any = out
2337
- tokens.forEach((token, i) => {
2338
- const isLast = i === tokens.length - 1
2339
-
2340
- // We are inside an array and see "[]" (empty token) => append
2341
- if (Array.isArray(cur) && token === "") {
2342
- if (isLast) {
2343
- cur.push(value)
2344
- } else {
2345
- // bracket path: "foo[][bar]" => push a new element and descend into it
2346
- const next = tokens[i + 1]
2347
- const shouldBeArray = typeof next === "number" || next === ""
2348
- const index = cur.length
2349
- cur = getOrCreateContainer(cur, index, shouldBeArray)
2350
- }
2351
- } else if (isLast) {
2352
- // If we're setting a value at a path that already exists
2353
- // convert it to an array to support multiple values for the same key
2354
- const hasOwn = Object.hasOwn(cur, token)
2355
- if (hasOwn && Array.isArray(cur[token]) && (containers.has(cur[token]) || duplicates.has(cur[token]))) {
2356
- cur[token].push(value)
2335
+ for (let i = 0; i < tokens.length; i++) {
2336
+ const state = indexed.get(cur)
2337
+ // Resolve "[]" to the next index before handling leaves or containers
2338
+ const token = tokens[i] === "" && state !== undefined ? state.length : tokens[i]
2339
+ if (state !== undefined && typeof token === "number") {
2340
+ state.length = Math.max(state.length, token + 1)
2341
+ }
2342
+ const hasOwn = Object.hasOwn(cur, token)
2343
+ const current = hasOwn ? cur[token] : undefined
2344
+
2345
+ if (i === tokens.length - 1) {
2346
+ const currentState = indexed.get(current)
2347
+ if (currentState !== undefined) {
2348
+ InternalRecord.assignProperty(current, currentState.length++, value)
2349
+ } else if (duplicates.has(current)) {
2350
+ current.push(value)
2357
2351
  } else if (hasOwn) {
2358
- const values = [cur[token], value]
2352
+ const values = [current, value]
2359
2353
  duplicates.add(values)
2360
2354
  InternalRecord.assignProperty(cur, token, values)
2361
2355
  } else {
@@ -2363,12 +2357,30 @@ export function makeTreeRecord<A>(
2363
2357
  }
2364
2358
  } else {
2365
2359
  const next = tokens[i + 1]
2366
- // if next is a number OR "" (from []), we are building an array
2367
2360
  const shouldBeArray = typeof next === "number" || next === ""
2368
- cur = getOrCreateContainer(cur, token, shouldBeArray)
2361
+ if (containers.has(current) && indexed.has(current) === shouldBeArray) {
2362
+ cur = current
2363
+ } else {
2364
+ const container = {}
2365
+ containers.add(container)
2366
+ if (shouldBeArray) {
2367
+ indexed.set(container, { parent: cur, key: token, length: 0 })
2368
+ }
2369
+ InternalRecord.assignProperty(cur, token, container)
2370
+ cur = container
2371
+ }
2369
2372
  }
2370
- })
2373
+ }
2371
2374
  })
2375
+
2376
+ // Children are created after their parents, so materializing in reverse
2377
+ // creation order replaces every nested container before its parent is copied
2378
+ for (const [builder, { key, length, parent }] of Array.from(indexed).reverse()) {
2379
+ // A later conflicting path may have replaced the container in its parent
2380
+ if (parent[key] === builder && length - Object.keys(builder).length <= MAX_ARRAY_HOLES) {
2381
+ InternalRecord.assignProperty(parent, key, Object.assign(new Array(length), builder))
2382
+ }
2383
+ }
2372
2384
  return out
2373
2385
  }
2374
2386
 
package/src/Sink.ts CHANGED
@@ -2177,13 +2177,24 @@ export const takeWhileFilterEffect = <In, Out, X, E, R>(
2177
2177
  * @since 4.0.0
2178
2178
  */
2179
2179
  export const takeUntil = <In>(predicate: Predicate<In>): Sink<Array<In>, In, In> =>
2180
- suspend(() => {
2181
- let done = false
2182
- return takeWhile((i) => {
2183
- if (done) return false
2184
- done = predicate(i)
2185
- return true
2186
- })
2180
+ fromTransform((upstream) => {
2181
+ const out = Arr.empty<In>()
2182
+ return upstream.pipe(
2183
+ Effect.flatMap((arr) => {
2184
+ for (let i = 0; i < arr.length; i++) {
2185
+ out.push(arr[i])
2186
+ if (predicate(arr[i])) {
2187
+ const leftover: NonEmptyReadonlyArray<In> | undefined = (i + 1) < arr.length
2188
+ ? arr.slice(i + 1) as Arr.NonEmptyArray<In>
2189
+ : undefined
2190
+ return Cause.done([out, leftover] as const)
2191
+ }
2192
+ }
2193
+ return Effect.void
2194
+ }),
2195
+ Effect.forever({ disableYield: true }),
2196
+ Pull.catchDone((end) => Effect.succeed<End<Array<In>, In>>(end ?? [out]))
2197
+ )
2187
2198
  })
2188
2199
 
2189
2200
  /**
@@ -2201,17 +2212,33 @@ export const takeUntil = <In>(predicate: Predicate<In>): Sink<Array<In>, In, In>
2201
2212
  export const takeUntilEffect = <In, E, R>(
2202
2213
  predicate: (input: In) => Effect.Effect<boolean, E, R>
2203
2214
  ): Sink<Array<In>, In, In, E, R> =>
2204
- suspend(() => {
2205
- let done = false
2206
- return takeWhileEffect((input) => {
2207
- if (done) {
2208
- return Effect.succeed(false)
2209
- }
2210
- return Effect.map(predicate(input), (b) => {
2211
- done = b
2212
- return true
2213
- })
2214
- })
2215
+ fromTransform((upstream) => {
2216
+ const out = Arr.empty<In>()
2217
+ let leftover: NonEmptyReadonlyArray<In> | undefined = undefined
2218
+ return upstream.pipe(
2219
+ Effect.flatMap((arr) => {
2220
+ let i = 0
2221
+ return Effect.whileLoop({
2222
+ while: () => i < arr.length,
2223
+ body: () => {
2224
+ const input = arr[i++]
2225
+ return Effect.flatMap(predicate(input), (matched) => {
2226
+ out.push(input)
2227
+ if (!matched) {
2228
+ return Effect.void
2229
+ }
2230
+ if (i < arr.length) {
2231
+ leftover = arr.slice(i) as Arr.NonEmptyArray<In>
2232
+ }
2233
+ return Cause.done()
2234
+ })
2235
+ },
2236
+ step: constVoid
2237
+ })
2238
+ }),
2239
+ Effect.forever({ disableYield: true }),
2240
+ Pull.catchDone(() => Effect.succeed([out, leftover] as const))
2241
+ )
2215
2242
  })
2216
2243
 
2217
2244
  /**