effect 4.0.6 → 4.0.7

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 (480) hide show
  1. package/dist/Arbitrary.d.ts +10 -2
  2. package/dist/Arbitrary.d.ts.map +1 -1
  3. package/dist/Arbitrary.js +2 -1
  4. package/dist/Arbitrary.js.map +1 -1
  5. package/dist/Channel.d.ts.map +1 -1
  6. package/dist/Channel.js +21 -6
  7. package/dist/Channel.js.map +1 -1
  8. package/dist/Data.d.ts +54 -235
  9. package/dist/Data.d.ts.map +1 -1
  10. package/dist/Data.js.map +1 -1
  11. package/dist/Effect.d.ts +1 -1
  12. package/dist/Effect.js +1 -1
  13. package/dist/Equal.d.ts.map +1 -1
  14. package/dist/Equal.js +8 -1
  15. package/dist/Equal.js.map +1 -1
  16. package/dist/Exit.d.ts +3 -3
  17. package/dist/Exit.d.ts.map +1 -1
  18. package/dist/Exit.js.map +1 -1
  19. package/dist/Formatter.d.ts.map +1 -1
  20. package/dist/Formatter.js +27 -13
  21. package/dist/Formatter.js.map +1 -1
  22. package/dist/Hash.d.ts.map +1 -1
  23. package/dist/Hash.js +4 -1
  24. package/dist/Hash.js.map +1 -1
  25. package/dist/JsonPatch.js +4 -0
  26. package/dist/JsonPatch.js.map +1 -1
  27. package/dist/JsonSchema.d.ts.map +1 -1
  28. package/dist/JsonSchema.js +13 -40
  29. package/dist/JsonSchema.js.map +1 -1
  30. package/dist/Metric.d.ts +3 -3
  31. package/dist/MutableList.d.ts +5 -2
  32. package/dist/MutableList.d.ts.map +1 -1
  33. package/dist/MutableList.js +7 -5
  34. package/dist/MutableList.js.map +1 -1
  35. package/dist/MutableRef.d.ts.map +1 -1
  36. package/dist/MutableRef.js +7 -0
  37. package/dist/MutableRef.js.map +1 -1
  38. package/dist/PartitionedSemaphore.d.ts +2 -1
  39. package/dist/PartitionedSemaphore.d.ts.map +1 -1
  40. package/dist/PartitionedSemaphore.js +22 -12
  41. package/dist/PartitionedSemaphore.js.map +1 -1
  42. package/dist/Pool.d.ts.map +1 -1
  43. package/dist/Pool.js +77 -27
  44. package/dist/Pool.js.map +1 -1
  45. package/dist/PubSub.d.ts.map +1 -1
  46. package/dist/PubSub.js +5 -6
  47. package/dist/PubSub.js.map +1 -1
  48. package/dist/Ref.d.ts.map +1 -1
  49. package/dist/Ref.js +8 -0
  50. package/dist/Ref.js.map +1 -1
  51. package/dist/Schedule.js +1 -1
  52. package/dist/Schedule.js.map +1 -1
  53. package/dist/Schema.d.ts +24 -8
  54. package/dist/Schema.d.ts.map +1 -1
  55. package/dist/Schema.js +37 -28
  56. package/dist/Schema.js.map +1 -1
  57. package/dist/SchemaAST.d.ts +4 -2
  58. package/dist/SchemaAST.d.ts.map +1 -1
  59. package/dist/SchemaAST.js +14 -17
  60. package/dist/SchemaAST.js.map +1 -1
  61. package/dist/SchemaParser.d.ts.map +1 -1
  62. package/dist/SchemaParser.js +48 -22
  63. package/dist/SchemaParser.js.map +1 -1
  64. package/dist/SchemaRepresentation.d.ts +19 -10
  65. package/dist/SchemaRepresentation.d.ts.map +1 -1
  66. package/dist/SchemaRepresentation.js +23 -13
  67. package/dist/SchemaRepresentation.js.map +1 -1
  68. package/dist/SchemaTransformation.d.ts +4 -1
  69. package/dist/SchemaTransformation.d.ts.map +1 -1
  70. package/dist/SchemaTransformation.js +9 -2
  71. package/dist/SchemaTransformation.js.map +1 -1
  72. package/dist/Semaphore.d.ts.map +1 -1
  73. package/dist/Semaphore.js +54 -35
  74. package/dist/Semaphore.js.map +1 -1
  75. package/dist/Sink.d.ts.map +1 -1
  76. package/dist/Sink.js +7 -2
  77. package/dist/Sink.js.map +1 -1
  78. package/dist/Stream.d.ts.map +1 -1
  79. package/dist/Stream.js +22 -10
  80. package/dist/Stream.js.map +1 -1
  81. package/dist/String.d.ts +3 -0
  82. package/dist/String.d.ts.map +1 -1
  83. package/dist/String.js +3 -0
  84. package/dist/String.js.map +1 -1
  85. package/dist/Tracer.d.ts +11 -1
  86. package/dist/Tracer.d.ts.map +1 -1
  87. package/dist/Tracer.js +6 -1
  88. package/dist/Tracer.js.map +1 -1
  89. package/dist/ai/LanguageModel.d.ts.map +1 -1
  90. package/dist/ai/LanguageModel.js +9 -0
  91. package/dist/ai/LanguageModel.js.map +1 -1
  92. package/dist/ai/McpSchema.d.ts +110 -110
  93. package/dist/ai/McpSchema.d.ts.map +1 -1
  94. package/dist/ai/McpServer.d.ts.map +1 -1
  95. package/dist/ai/McpServer.js +21 -15
  96. package/dist/ai/McpServer.js.map +1 -1
  97. package/dist/ai/Prompt.d.ts +52 -0
  98. package/dist/ai/Prompt.d.ts.map +1 -1
  99. package/dist/ai/Prompt.js +38 -0
  100. package/dist/ai/Prompt.js.map +1 -1
  101. package/dist/ai/Response.d.ts +16 -3
  102. package/dist/ai/Response.d.ts.map +1 -1
  103. package/dist/ai/Response.js +4 -0
  104. package/dist/ai/Response.js.map +1 -1
  105. package/dist/ai/Tool.d.ts +24 -0
  106. package/dist/ai/Tool.d.ts.map +1 -1
  107. package/dist/ai/Tool.js +5 -2
  108. package/dist/ai/Tool.js.map +1 -1
  109. package/dist/ai/Toolkit.d.ts.map +1 -1
  110. package/dist/ai/Toolkit.js +8 -1
  111. package/dist/ai/Toolkit.js.map +1 -1
  112. package/dist/cli/Argument.d.ts +15 -0
  113. package/dist/cli/Argument.d.ts.map +1 -1
  114. package/dist/cli/Argument.js +5 -0
  115. package/dist/cli/Argument.js.map +1 -1
  116. package/dist/cli/CliError.d.ts +78 -0
  117. package/dist/cli/CliError.d.ts.map +1 -1
  118. package/dist/cli/CliError.js +65 -3
  119. package/dist/cli/CliError.js.map +1 -1
  120. package/dist/cli/CliOutput.d.ts +155 -6
  121. package/dist/cli/CliOutput.d.ts.map +1 -1
  122. package/dist/cli/CliOutput.js +62 -6
  123. package/dist/cli/CliOutput.js.map +1 -1
  124. package/dist/cli/Command.d.ts +24 -16
  125. package/dist/cli/Command.d.ts.map +1 -1
  126. package/dist/cli/Command.js +59 -29
  127. package/dist/cli/Command.js.map +1 -1
  128. package/dist/cli/Completions.d.ts +58 -0
  129. package/dist/cli/Completions.d.ts.map +1 -1
  130. package/dist/cli/Completions.js +49 -9
  131. package/dist/cli/Completions.js.map +1 -1
  132. package/dist/cli/Flag.d.ts +15 -0
  133. package/dist/cli/Flag.d.ts.map +1 -1
  134. package/dist/cli/Flag.js +5 -0
  135. package/dist/cli/Flag.js.map +1 -1
  136. package/dist/cli/GlobalFlag.d.ts.map +1 -1
  137. package/dist/cli/GlobalFlag.js +15 -7
  138. package/dist/cli/GlobalFlag.js.map +1 -1
  139. package/dist/cli/Param.d.ts +9 -0
  140. package/dist/cli/Param.d.ts.map +1 -1
  141. package/dist/cli/Param.js +21 -2
  142. package/dist/cli/Param.js.map +1 -1
  143. package/dist/cli/TerminalCapabilities.d.ts +3 -2
  144. package/dist/cli/TerminalCapabilities.d.ts.map +1 -1
  145. package/dist/cli/TerminalCapabilities.js +3 -1
  146. package/dist/cli/TerminalCapabilities.js.map +1 -1
  147. package/dist/cli/internal/completions/bash.js +73 -27
  148. package/dist/cli/internal/completions/bash.js.map +1 -1
  149. package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
  150. package/dist/cluster/ClusterWorkflowEngine.js +45 -10
  151. package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
  152. package/dist/cluster/MessageStorage.d.ts +23 -45
  153. package/dist/cluster/MessageStorage.d.ts.map +1 -1
  154. package/dist/cluster/MessageStorage.js +6 -7
  155. package/dist/cluster/MessageStorage.js.map +1 -1
  156. package/dist/cluster/Sharding.d.ts.map +1 -1
  157. package/dist/cluster/Sharding.js +61 -21
  158. package/dist/cluster/Sharding.js.map +1 -1
  159. package/dist/cluster/ShardingConfig.d.ts +10 -0
  160. package/dist/cluster/ShardingConfig.d.ts.map +1 -1
  161. package/dist/cluster/ShardingConfig.js.map +1 -1
  162. package/dist/cluster/Snowflake.d.ts.map +1 -1
  163. package/dist/cluster/Snowflake.js +3 -7
  164. package/dist/cluster/Snowflake.js.map +1 -1
  165. package/dist/cluster/SqlRunnerStorage.d.ts.map +1 -1
  166. package/dist/cluster/SqlRunnerStorage.js +87 -39
  167. package/dist/cluster/SqlRunnerStorage.js.map +1 -1
  168. package/dist/cluster/internal/entityManager.js +54 -20
  169. package/dist/cluster/internal/entityManager.js.map +1 -1
  170. package/dist/devtools/DevToolsClient.d.ts.map +1 -1
  171. package/dist/devtools/DevToolsClient.js +2 -0
  172. package/dist/devtools/DevToolsClient.js.map +1 -1
  173. package/dist/encoding/Base64.js +36 -0
  174. package/dist/encoding/Base64.js.map +1 -1
  175. package/dist/encoding/Sse.d.ts.map +1 -1
  176. package/dist/encoding/Sse.js +3 -3
  177. package/dist/encoding/Sse.js.map +1 -1
  178. package/dist/encoding/Toml.d.ts.map +1 -1
  179. package/dist/encoding/Toml.js +21 -16
  180. package/dist/encoding/Toml.js.map +1 -1
  181. package/dist/eventlog/SqlEventJournal.d.ts.map +1 -1
  182. package/dist/eventlog/SqlEventJournal.js +47 -27
  183. package/dist/eventlog/SqlEventJournal.js.map +1 -1
  184. package/dist/eventlog/internal/conflicts.d.ts +0 -1
  185. package/dist/eventlog/internal/conflicts.d.ts.map +1 -1
  186. package/dist/eventlog/internal/conflicts.js +0 -3
  187. package/dist/eventlog/internal/conflicts.js.map +1 -1
  188. package/dist/http/Cookies.d.ts.map +1 -1
  189. package/dist/http/Cookies.js +10 -9
  190. package/dist/http/Cookies.js.map +1 -1
  191. package/dist/http/HttpClient.d.ts +423 -0
  192. package/dist/http/HttpClient.d.ts.map +1 -1
  193. package/dist/http/HttpClient.js +231 -7
  194. package/dist/http/HttpClient.js.map +1 -1
  195. package/dist/http/HttpClientError.d.ts +8 -1
  196. package/dist/http/HttpClientError.d.ts.map +1 -1
  197. package/dist/http/HttpClientError.js +37 -1
  198. package/dist/http/HttpClientError.js.map +1 -1
  199. package/dist/http/HttpClientRequest.d.ts.map +1 -1
  200. package/dist/http/HttpClientRequest.js +1 -1
  201. package/dist/http/HttpClientRequest.js.map +1 -1
  202. package/dist/http/HttpMiddleware.d.ts +1 -1
  203. package/dist/http/HttpMiddleware.d.ts.map +1 -1
  204. package/dist/http/HttpMiddleware.js +14 -16
  205. package/dist/http/HttpMiddleware.js.map +1 -1
  206. package/dist/http/HttpRouter.d.ts.map +1 -1
  207. package/dist/http/HttpRouter.js +2 -1
  208. package/dist/http/HttpRouter.js.map +1 -1
  209. package/dist/http/HttpServerError.js +2 -2
  210. package/dist/http/HttpServerError.js.map +1 -1
  211. package/dist/http/HttpServerRequest.d.ts +6 -1
  212. package/dist/http/HttpServerRequest.d.ts.map +1 -1
  213. package/dist/http/HttpServerRequest.js +73 -10
  214. package/dist/http/HttpServerRequest.js.map +1 -1
  215. package/dist/http/HttpStaticServer.d.ts.map +1 -1
  216. package/dist/http/HttpStaticServer.js +48 -21
  217. package/dist/http/HttpStaticServer.js.map +1 -1
  218. package/dist/http/MultipartParser/internal/contentType.js +3 -3
  219. package/dist/http/UrlParams.d.ts +3 -1
  220. package/dist/http/UrlParams.d.ts.map +1 -1
  221. package/dist/http/UrlParams.js +4 -2
  222. package/dist/http/UrlParams.js.map +1 -1
  223. package/dist/http/internal/compression.js +4 -5
  224. package/dist/http/internal/compression.js.map +1 -1
  225. package/dist/http/internal/decompression.js +3 -0
  226. package/dist/http/internal/decompression.js.map +1 -1
  227. package/dist/http/internal/httpBody.js +8 -1
  228. package/dist/http/internal/httpBody.js.map +1 -1
  229. package/dist/http/internal/urlParams.js +25 -0
  230. package/dist/http/internal/urlParams.js.map +1 -1
  231. package/dist/http-api/HttpApi.d.ts +3 -6
  232. package/dist/http-api/HttpApi.d.ts.map +1 -1
  233. package/dist/http-api/HttpApi.js +3 -6
  234. package/dist/http-api/HttpApi.js.map +1 -1
  235. package/dist/http-api/HttpApiBuilder.d.ts.map +1 -1
  236. package/dist/http-api/HttpApiBuilder.js +27 -11
  237. package/dist/http-api/HttpApiBuilder.js.map +1 -1
  238. package/dist/http-api/HttpApiClient.d.ts +77 -7
  239. package/dist/http-api/HttpApiClient.d.ts.map +1 -1
  240. package/dist/http-api/HttpApiClient.js +142 -44
  241. package/dist/http-api/HttpApiClient.js.map +1 -1
  242. package/dist/http-api/HttpApiEndpoint.d.ts +24 -7
  243. package/dist/http-api/HttpApiEndpoint.d.ts.map +1 -1
  244. package/dist/http-api/HttpApiEndpoint.js +109 -27
  245. package/dist/http-api/HttpApiEndpoint.js.map +1 -1
  246. package/dist/http-api/HttpApiSchema.d.ts +76 -29
  247. package/dist/http-api/HttpApiSchema.d.ts.map +1 -1
  248. package/dist/http-api/HttpApiSchema.js +70 -59
  249. package/dist/http-api/HttpApiSchema.js.map +1 -1
  250. package/dist/http-api/HttpApiTest.d.ts.map +1 -1
  251. package/dist/http-api/HttpApiTest.js +3 -2
  252. package/dist/http-api/HttpApiTest.js.map +1 -1
  253. package/dist/http-api/OpenApi.d.ts.map +1 -1
  254. package/dist/http-api/OpenApi.js +25 -16
  255. package/dist/http-api/OpenApi.js.map +1 -1
  256. package/dist/http-api/internal/toCodecHttpProperties.d.ts +2 -0
  257. package/dist/http-api/internal/toCodecHttpProperties.d.ts.map +1 -0
  258. package/dist/http-api/internal/toCodecHttpProperties.js +38 -0
  259. package/dist/http-api/internal/toCodecHttpProperties.js.map +1 -0
  260. package/dist/internal/arbitrary/runner.d.ts.map +1 -1
  261. package/dist/internal/arbitrary/runner.js +120 -44
  262. package/dist/internal/arbitrary/runner.js.map +1 -1
  263. package/dist/internal/core.js +2 -0
  264. package/dist/internal/core.js.map +1 -1
  265. package/dist/internal/effect.js +21 -13
  266. package/dist/internal/effect.js.map +1 -1
  267. package/dist/internal/equal.js +14 -0
  268. package/dist/internal/equal.js.map +1 -1
  269. package/dist/internal/jsonSchema.d.ts +2 -0
  270. package/dist/internal/jsonSchema.d.ts.map +1 -0
  271. package/dist/internal/jsonSchema.js +28 -0
  272. package/dist/internal/jsonSchema.js.map +1 -0
  273. package/dist/internal/matcher.js +1 -1
  274. package/dist/internal/matcher.js.map +1 -1
  275. package/dist/internal/schema/compilerRegistry.js +4 -1
  276. package/dist/internal/schema/compilerRegistry.js.map +1 -1
  277. package/dist/internal/schema/content.d.ts +2 -0
  278. package/dist/internal/schema/content.d.ts.map +1 -0
  279. package/dist/internal/schema/content.js +13 -0
  280. package/dist/internal/schema/content.js.map +1 -0
  281. package/dist/internal/schema/fromJsonSchemaDocument.js +173 -185
  282. package/dist/internal/schema/fromJsonSchemaDocument.js.map +1 -1
  283. package/dist/internal/schema/fromRepresentation.js +2 -1
  284. package/dist/internal/schema/fromRepresentation.js.map +1 -1
  285. package/dist/internal/schema/standardSchema.js +8 -2
  286. package/dist/internal/schema/standardSchema.js.map +1 -1
  287. package/dist/internal/schema/toCodeDocument.js +3 -3
  288. package/dist/internal/schema/toCodeDocument.js.map +1 -1
  289. package/dist/internal/schema/toCodec.js +21 -24
  290. package/dist/internal/schema/toCodec.js.map +1 -1
  291. package/dist/internal/schema/toJsonSchemaDocument.js +205 -140
  292. package/dist/internal/schema/toJsonSchemaDocument.js.map +1 -1
  293. package/dist/internal/schema/toRepresentation.js +107 -129
  294. package/dist/internal/schema/toRepresentation.js.map +1 -1
  295. package/dist/internal/sql.d.ts +2 -0
  296. package/dist/internal/sql.d.ts.map +1 -0
  297. package/dist/internal/sql.js +13 -0
  298. package/dist/internal/sql.js.map +1 -0
  299. package/dist/internal/version.js +1 -1
  300. package/dist/observability/OtlpProxy.d.ts +154 -0
  301. package/dist/observability/OtlpProxy.d.ts.map +1 -0
  302. package/dist/observability/OtlpProxy.js +235 -0
  303. package/dist/observability/OtlpProxy.js.map +1 -0
  304. package/dist/observability/OtlpTracer.d.ts.map +1 -1
  305. package/dist/observability/OtlpTracer.js +4 -0
  306. package/dist/observability/OtlpTracer.js.map +1 -1
  307. package/dist/observability/index.d.ts +5 -0
  308. package/dist/observability/index.d.ts.map +1 -1
  309. package/dist/observability/index.js +5 -0
  310. package/dist/observability/index.js.map +1 -1
  311. package/dist/persistence/CircuitBreaker.d.ts +897 -0
  312. package/dist/persistence/CircuitBreaker.d.ts.map +1 -0
  313. package/dist/persistence/CircuitBreaker.js +1165 -0
  314. package/dist/persistence/CircuitBreaker.js.map +1 -0
  315. package/dist/persistence/Redis.d.ts +78 -2
  316. package/dist/persistence/Redis.d.ts.map +1 -1
  317. package/dist/persistence/Redis.js +62 -7
  318. package/dist/persistence/Redis.js.map +1 -1
  319. package/dist/persistence/index.d.ts +5 -0
  320. package/dist/persistence/index.d.ts.map +1 -1
  321. package/dist/persistence/index.js +5 -0
  322. package/dist/persistence/index.js.map +1 -1
  323. package/dist/process/ChildProcess.d.ts +30 -4
  324. package/dist/process/ChildProcess.d.ts.map +1 -1
  325. package/dist/process/ChildProcess.js.map +1 -1
  326. package/dist/process/ChildProcessSpawner.d.ts +30 -0
  327. package/dist/process/ChildProcessSpawner.d.ts.map +1 -1
  328. package/dist/process/ChildProcessSpawner.js +5 -2
  329. package/dist/process/ChildProcessSpawner.js.map +1 -1
  330. package/dist/reactivity/AsyncResult.d.ts +1 -1
  331. package/dist/reactivity/AsyncResult.d.ts.map +1 -1
  332. package/dist/rpc/RpcClient.d.ts.map +1 -1
  333. package/dist/rpc/RpcClient.js +9 -8
  334. package/dist/rpc/RpcClient.js.map +1 -1
  335. package/dist/rpc/RpcSerialization.d.ts +14 -0
  336. package/dist/rpc/RpcSerialization.d.ts.map +1 -1
  337. package/dist/rpc/RpcSerialization.js +20 -8
  338. package/dist/rpc/RpcSerialization.js.map +1 -1
  339. package/dist/rpc/RpcServer.d.ts.map +1 -1
  340. package/dist/rpc/RpcServer.js +11 -1
  341. package/dist/rpc/RpcServer.js.map +1 -1
  342. package/dist/rpc/RpcTest.d.ts +1 -0
  343. package/dist/rpc/RpcTest.d.ts.map +1 -1
  344. package/dist/rpc/RpcTest.js +1 -0
  345. package/dist/rpc/RpcTest.js.map +1 -1
  346. package/dist/sql/Migrator.d.ts +2 -1
  347. package/dist/sql/Migrator.d.ts.map +1 -1
  348. package/dist/sql/Migrator.js +11 -8
  349. package/dist/sql/Migrator.js.map +1 -1
  350. package/dist/sql/SqlClient.d.ts +9 -4
  351. package/dist/sql/SqlClient.d.ts.map +1 -1
  352. package/dist/sql/SqlClient.js +8 -1
  353. package/dist/sql/SqlClient.js.map +1 -1
  354. package/dist/sql/SqlResolver.d.ts +4 -0
  355. package/dist/sql/SqlResolver.d.ts.map +1 -1
  356. package/dist/sql/SqlResolver.js +18 -4
  357. package/dist/sql/SqlResolver.js.map +1 -1
  358. package/dist/sql/Statement.d.ts +7 -0
  359. package/dist/sql/Statement.d.ts.map +1 -1
  360. package/dist/sql/Statement.js +21 -2
  361. package/dist/sql/Statement.js.map +1 -1
  362. package/dist/workflow/DurableDeferred.d.ts.map +1 -1
  363. package/dist/workflow/DurableDeferred.js +21 -2
  364. package/dist/workflow/DurableDeferred.js.map +1 -1
  365. package/package.json +1 -1
  366. package/src/Arbitrary.ts +10 -2
  367. package/src/Channel.ts +47 -18
  368. package/src/Data.ts +60 -265
  369. package/src/Effect.ts +1 -1
  370. package/src/Equal.ts +8 -1
  371. package/src/Exit.ts +3 -3
  372. package/src/Formatter.ts +28 -13
  373. package/src/Hash.ts +4 -1
  374. package/src/JsonPatch.ts +4 -0
  375. package/src/JsonSchema.ts +12 -40
  376. package/src/Metric.ts +3 -3
  377. package/src/MutableList.ts +7 -5
  378. package/src/MutableRef.ts +8 -1
  379. package/src/PartitionedSemaphore.ts +24 -13
  380. package/src/Pool.ts +109 -37
  381. package/src/PubSub.ts +5 -6
  382. package/src/Ref.ts +8 -0
  383. package/src/Schedule.ts +1 -1
  384. package/src/Schema.ts +48 -25
  385. package/src/SchemaAST.ts +20 -20
  386. package/src/SchemaParser.ts +51 -18
  387. package/src/SchemaRepresentation.ts +31 -34
  388. package/src/SchemaTransformation.ts +9 -2
  389. package/src/Semaphore.ts +67 -40
  390. package/src/Sink.ts +15 -2
  391. package/src/Stream.ts +33 -16
  392. package/src/String.ts +3 -0
  393. package/src/Tracer.ts +15 -1
  394. package/src/ai/LanguageModel.ts +9 -0
  395. package/src/ai/McpServer.ts +14 -13
  396. package/src/ai/Prompt.ts +65 -0
  397. package/src/ai/Response.ts +34 -9
  398. package/src/ai/Tool.ts +38 -2
  399. package/src/ai/Toolkit.ts +4 -1
  400. package/src/cli/Argument.ts +15 -0
  401. package/src/cli/CliError.ts +90 -3
  402. package/src/cli/CliOutput.ts +183 -6
  403. package/src/cli/Command.ts +53 -41
  404. package/src/cli/Completions.ts +51 -0
  405. package/src/cli/Flag.ts +15 -0
  406. package/src/cli/GlobalFlag.ts +6 -7
  407. package/src/cli/Param.ts +29 -6
  408. package/src/cli/TerminalCapabilities.ts +6 -3
  409. package/src/cli/internal/completions/bash.ts +79 -29
  410. package/src/cluster/ClusterWorkflowEngine.ts +46 -16
  411. package/src/cluster/MessageStorage.ts +19 -14
  412. package/src/cluster/Sharding.ts +83 -21
  413. package/src/cluster/ShardingConfig.ts +5 -0
  414. package/src/cluster/Snowflake.ts +3 -7
  415. package/src/cluster/SqlRunnerStorage.ts +110 -47
  416. package/src/cluster/internal/entityManager.ts +75 -22
  417. package/src/devtools/DevToolsClient.ts +2 -0
  418. package/src/encoding/Base64.ts +38 -0
  419. package/src/encoding/Sse.ts +4 -3
  420. package/src/encoding/Toml.ts +33 -16
  421. package/src/eventlog/SqlEventJournal.ts +68 -45
  422. package/src/eventlog/internal/conflicts.ts +0 -4
  423. package/src/http/Cookies.ts +10 -11
  424. package/src/http/HttpClient.ts +547 -7
  425. package/src/http/HttpClientError.ts +35 -1
  426. package/src/http/HttpClientRequest.ts +9 -1
  427. package/src/http/HttpMiddleware.ts +15 -18
  428. package/src/http/HttpRouter.ts +2 -1
  429. package/src/http/HttpServerError.ts +2 -2
  430. package/src/http/HttpServerRequest.ts +102 -16
  431. package/src/http/HttpStaticServer.ts +51 -22
  432. package/src/http/MultipartParser/internal/contentType.ts +3 -3
  433. package/src/http/UrlParams.ts +6 -1
  434. package/src/http/internal/compression.ts +4 -5
  435. package/src/http/internal/decompression.ts +6 -0
  436. package/src/http/internal/httpBody.ts +10 -2
  437. package/src/http/internal/urlParams.ts +29 -0
  438. package/src/http-api/HttpApi.ts +3 -6
  439. package/src/http-api/HttpApiBuilder.ts +45 -15
  440. package/src/http-api/HttpApiClient.ts +218 -72
  441. package/src/http-api/HttpApiEndpoint.ts +121 -30
  442. package/src/http-api/HttpApiSchema.ts +141 -48
  443. package/src/http-api/HttpApiTest.ts +3 -2
  444. package/src/http-api/OpenApi.ts +20 -17
  445. package/src/http-api/internal/toCodecHttpProperties.ts +56 -0
  446. package/src/internal/arbitrary/runner.ts +133 -36
  447. package/src/internal/core.ts +2 -0
  448. package/src/internal/effect.ts +24 -16
  449. package/src/internal/equal.ts +17 -0
  450. package/src/internal/jsonSchema.ts +27 -0
  451. package/src/internal/matcher.ts +1 -1
  452. package/src/internal/schema/compilerRegistry.ts +6 -1
  453. package/src/internal/schema/content.ts +18 -0
  454. package/src/internal/schema/fromJsonSchemaDocument.ts +228 -190
  455. package/src/internal/schema/fromRepresentation.ts +2 -1
  456. package/src/internal/schema/standardSchema.ts +2 -2
  457. package/src/internal/schema/toCodeDocument.ts +4 -4
  458. package/src/internal/schema/toCodec.ts +26 -22
  459. package/src/internal/schema/toJsonSchemaDocument.ts +189 -167
  460. package/src/internal/schema/toRepresentation.ts +122 -140
  461. package/src/internal/sql.ts +14 -0
  462. package/src/internal/version.ts +1 -1
  463. package/src/observability/OtlpProxy.ts +314 -0
  464. package/src/observability/OtlpTracer.ts +4 -0
  465. package/src/observability/index.ts +6 -0
  466. package/src/persistence/CircuitBreaker.ts +1678 -0
  467. package/src/persistence/Redis.ts +129 -8
  468. package/src/persistence/index.ts +6 -0
  469. package/src/process/ChildProcess.ts +30 -4
  470. package/src/process/ChildProcessSpawner.ts +41 -2
  471. package/src/reactivity/AsyncResult.ts +1 -1
  472. package/src/rpc/RpcClient.ts +13 -10
  473. package/src/rpc/RpcSerialization.ts +32 -9
  474. package/src/rpc/RpcServer.ts +16 -1
  475. package/src/rpc/RpcTest.ts +3 -0
  476. package/src/sql/Migrator.ts +12 -7
  477. package/src/sql/SqlClient.ts +11 -4
  478. package/src/sql/SqlResolver.ts +23 -9
  479. package/src/sql/Statement.ts +30 -2
  480. package/src/workflow/DurableDeferred.ts +23 -6
@@ -25,6 +25,7 @@ import * as Inspectable from "../Inspectable.ts"
25
25
  import { getStackTraceLimit, setStackTraceLimit } from "../internal/stackTraceLimit.ts"
26
26
  import * as Layer from "../Layer.ts"
27
27
  import * as Option from "../Option.ts"
28
+ import type * as CircuitBreaker from "../persistence/CircuitBreaker.ts"
28
29
  import type * as RateLimiter from "../persistence/RateLimiter.ts"
29
30
  import { type Pipeable, pipeArguments } from "../Pipeable.ts"
30
31
  import * as Predicate from "../Predicate.ts"
@@ -836,12 +837,11 @@ export const make = (
836
837
  fiber.getRef(TracerDisabledWhen)(request)
837
838
  if (tracerDisabled) {
838
839
  const effect = f(request, url, controller.signal, fiber as any)
839
- if (scopedController) return effect
840
+ if (scopedController) return Effect.map(effect, (response) => trackResponse(response, controller, true))
840
841
  return Effect.uninterruptibleMask((restore) =>
841
842
  Effect.matchCauseEffect(restore(effect), {
842
843
  onSuccess(response) {
843
- responseRegistry.register(response, controller)
844
- return Effect.succeed(new InterruptibleResponse(response, controller))
844
+ return Effect.succeed(trackResponse(response, controller, false))
845
845
  },
846
846
  onFailure(cause) {
847
847
  if (Cause.hasInterrupts(cause)) {
@@ -882,9 +882,7 @@ export const make = (
882
882
  endSpanWithStatusError(fiber, span, request, response)
883
883
  }
884
884
 
885
- if (scopedController) return Effect.succeed(response)
886
- responseRegistry.register(response, controller)
887
- return Effect.succeed(new InterruptibleResponse(response, controller))
885
+ return Effect.succeed(trackResponse(response, controller, scopedController !== undefined))
888
886
  },
889
887
  onFailure(cause) {
890
888
  if (!scopedController && Cause.hasInterrupts(cause)) {
@@ -1678,6 +1676,515 @@ export const withRateLimiter: {
1678
1676
  })
1679
1677
  })
1680
1678
 
1679
+ /**
1680
+ * Namespace containing configuration types for `withCircuitBreaker`.
1681
+ *
1682
+ * @stability experimental
1683
+ * @since 4.0.6
1684
+ */
1685
+ export declare namespace WithCircuitBreaker {
1686
+ /**
1687
+ * Options used to configure `withCircuitBreaker`.
1688
+ *
1689
+ * @stability experimental
1690
+ * @category circuit breaking
1691
+ * @since 4.0.6
1692
+ */
1693
+ export interface Options<E, R2 = never> {
1694
+ /**
1695
+ * The `CircuitBreaker` service that guards each request.
1696
+ */
1697
+ readonly breaker: CircuitBreaker.CircuitBreaker
1698
+ /**
1699
+ * The circuit key for a request. Requests with the same key share one
1700
+ * circuit. Defaults to the request origin, falling back to the raw request
1701
+ * URL when it cannot be parsed.
1702
+ */
1703
+ readonly key?: string | ((request: HttpClientRequest.HttpClientRequest) => string) | undefined
1704
+ /**
1705
+ * Classifies the `Exit` of each request that the breaker admitted.
1706
+ * Defaults to `circuitBreakerClassifier`.
1707
+ */
1708
+ readonly classify?:
1709
+ | ((
1710
+ exit: Exit.Exit<HttpClientResponse.HttpClientResponse, E>
1711
+ ) => CircuitBreaker.Outcome | Effect.Effect<CircuitBreaker.Outcome, never, R2>)
1712
+ | undefined
1713
+ }
1714
+ }
1715
+
1716
+ /**
1717
+ * Guards requests with a `CircuitBreaker`.
1718
+ *
1719
+ * **Details**
1720
+ *
1721
+ * Requests are keyed by origin unless `key` is set, and classified with
1722
+ * `circuitBreakerClassifier` unless `classify` is set. A rejected request
1723
+ * fails with `CircuitBreakerError` without reaching the wrapped client.
1724
+ *
1725
+ * Apply it after `withRateLimiter` and `retryTransient`, so the breaker sees
1726
+ * one outcome per call and an open circuit skips the retry loop.
1727
+ * `retryTransient` never retries a `CircuitBreakerError`. A custom `classify`
1728
+ * can delegate the cases it doesn't handle to `circuitBreakerClassifier`.
1729
+ *
1730
+ * **Gotchas**
1731
+ *
1732
+ * - The breaker only sees the response headers. To count an error in the
1733
+ * body, lift it into the error channel below the breaker with
1734
+ * `transformResponse` and count it in `classify`.
1735
+ * - `withRateLimiter` retries `429` without limit by default, which can hold
1736
+ * the probe slot for minutes. Set its `times`.
1737
+ * - A rejected request has no client span. The rejection fails the caller's
1738
+ * span instead.
1739
+ *
1740
+ * **Example** (Guarding an API in the recommended order)
1741
+ *
1742
+ * ```ts import.meta.vitest
1743
+ * import { Effect, Layer, Ref, Schedule } from "effect"
1744
+ * import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http"
1745
+ * import { CircuitBreaker, RateLimiter } from "effect/persistence"
1746
+ *
1747
+ * const program = Effect.gen(function*() {
1748
+ * const requests = yield* Ref.make(0)
1749
+ * // A dependency that always answers 503.
1750
+ * const unavailable = HttpClient.make((request) =>
1751
+ * Effect.as(Ref.update(requests, (n) => n + 1), HttpClientResponse.fromWeb(request, new Response(null, { status: 503 })))
1752
+ * )
1753
+ *
1754
+ * const breaker = yield* CircuitBreaker.make({
1755
+ * tripPolicy: CircuitBreaker.consecutive(1),
1756
+ * openDuration: "30 seconds"
1757
+ * })
1758
+ * const client = unavailable.pipe(
1759
+ * HttpClient.withRateLimiter({
1760
+ * limiter: yield* RateLimiter.RateLimiter,
1761
+ * key: "inventory",
1762
+ * limit: 100,
1763
+ * window: "1 second",
1764
+ * times: 3
1765
+ * }),
1766
+ * HttpClient.retryTransient({ times: 2, schedule: Schedule.exponential("1 millis") }),
1767
+ * HttpClient.withCircuitBreaker({ breaker })
1768
+ * )
1769
+ *
1770
+ * // Three attempts, then the breaker records one failure and opens.
1771
+ * yield* client.execute(HttpClientRequest.get("http://inventory.test/items"))
1772
+ * // Rejected before the retry loop starts, so no further request is sent.
1773
+ * const rejected = yield* Effect.flip(client.execute(HttpClientRequest.get("http://inventory.test/items")))
1774
+ *
1775
+ * return [yield* Ref.get(requests), rejected._tag]
1776
+ * }).pipe(
1777
+ * Effect.scoped,
1778
+ * Effect.provide(Layer.merge(
1779
+ * CircuitBreaker.layerStoreMemory(),
1780
+ * RateLimiter.layer.pipe(Layer.provide(RateLimiter.layerStoreMemory))
1781
+ * ))
1782
+ * )
1783
+ *
1784
+ * await Effect.runPromise(program) // => [3, "CircuitBreakerError"]
1785
+ * ```
1786
+ *
1787
+ * **Example** (Counting an error in the body as a failure)
1788
+ *
1789
+ * This API answers `200` with `{ "status": "degraded" }` when it is failing.
1790
+ *
1791
+ * ```ts import.meta.vitest
1792
+ * import { Data, Effect, Exit, Option } from "effect"
1793
+ * import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http"
1794
+ * import { CircuitBreaker } from "effect/persistence"
1795
+ *
1796
+ * class Degraded extends Data.TaggedError("Degraded") {}
1797
+ *
1798
+ * const degraded = HttpClient.make((request) =>
1799
+ * Effect.succeed(HttpClientResponse.fromWeb(request, Response.json({ status: "degraded" })))
1800
+ * )
1801
+ *
1802
+ * const program = Effect.gen(function*() {
1803
+ * const breaker = yield* CircuitBreaker.make({
1804
+ * tripPolicy: CircuitBreaker.consecutive(1),
1805
+ * openDuration: "30 seconds"
1806
+ * })
1807
+ * const client = degraded.pipe(
1808
+ * HttpClient.transformResponse(Effect.flatMap((response) =>
1809
+ * Effect.flatMap(response.json, (body) =>
1810
+ * typeof body === "object" && body !== null && "status" in body && body.status === "degraded"
1811
+ * ? Effect.fail(new Degraded())
1812
+ * : Effect.succeed(response))
1813
+ * )),
1814
+ * HttpClient.withCircuitBreaker({
1815
+ * breaker,
1816
+ * classify: (exit) =>
1817
+ * Option.exists(Exit.findErrorOption(exit), (error) => error._tag === "Degraded")
1818
+ * ? CircuitBreaker.failure()
1819
+ * : HttpClient.circuitBreakerClassifier(exit)
1820
+ * })
1821
+ * )
1822
+ *
1823
+ * yield* Effect.flip(client.get("http://status.test/"))
1824
+ * const state = yield* breaker.state("http://status.test")
1825
+ * return state._tag
1826
+ * }).pipe(Effect.scoped, Effect.provide(CircuitBreaker.layerStoreMemory()))
1827
+ *
1828
+ * await Effect.runPromise(program) // => "Open"
1829
+ * ```
1830
+ *
1831
+ * @stability experimental
1832
+ * @category circuit breaking
1833
+ * @since 4.0.6
1834
+ */
1835
+ export const withCircuitBreaker: {
1836
+ /**
1837
+ * Guards requests with a `CircuitBreaker`.
1838
+ *
1839
+ * **Details**
1840
+ *
1841
+ * Requests are keyed by origin unless `key` is set, and classified with
1842
+ * `circuitBreakerClassifier` unless `classify` is set. A rejected request
1843
+ * fails with `CircuitBreakerError` without reaching the wrapped client.
1844
+ *
1845
+ * Apply it after `withRateLimiter` and `retryTransient`, so the breaker sees
1846
+ * one outcome per call and an open circuit skips the retry loop.
1847
+ * `retryTransient` never retries a `CircuitBreakerError`. A custom `classify`
1848
+ * can delegate the cases it doesn't handle to `circuitBreakerClassifier`.
1849
+ *
1850
+ * **Gotchas**
1851
+ *
1852
+ * - The breaker only sees the response headers. To count an error in the
1853
+ * body, lift it into the error channel below the breaker with
1854
+ * `transformResponse` and count it in `classify`.
1855
+ * - `withRateLimiter` retries `429` without limit by default, which can hold
1856
+ * the probe slot for minutes. Set its `times`.
1857
+ * - A rejected request has no client span. The rejection fails the caller's
1858
+ * span instead.
1859
+ *
1860
+ * **Example** (Guarding an API in the recommended order)
1861
+ *
1862
+ * ```ts import.meta.vitest
1863
+ * import { Effect, Layer, Ref, Schedule } from "effect"
1864
+ * import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http"
1865
+ * import { CircuitBreaker, RateLimiter } from "effect/persistence"
1866
+ *
1867
+ * const program = Effect.gen(function*() {
1868
+ * const requests = yield* Ref.make(0)
1869
+ * // A dependency that always answers 503.
1870
+ * const unavailable = HttpClient.make((request) =>
1871
+ * Effect.as(Ref.update(requests, (n) => n + 1), HttpClientResponse.fromWeb(request, new Response(null, { status: 503 })))
1872
+ * )
1873
+ *
1874
+ * const breaker = yield* CircuitBreaker.make({
1875
+ * tripPolicy: CircuitBreaker.consecutive(1),
1876
+ * openDuration: "30 seconds"
1877
+ * })
1878
+ * const client = unavailable.pipe(
1879
+ * HttpClient.withRateLimiter({
1880
+ * limiter: yield* RateLimiter.RateLimiter,
1881
+ * key: "inventory",
1882
+ * limit: 100,
1883
+ * window: "1 second",
1884
+ * times: 3
1885
+ * }),
1886
+ * HttpClient.retryTransient({ times: 2, schedule: Schedule.exponential("1 millis") }),
1887
+ * HttpClient.withCircuitBreaker({ breaker })
1888
+ * )
1889
+ *
1890
+ * // Three attempts, then the breaker records one failure and opens.
1891
+ * yield* client.execute(HttpClientRequest.get("http://inventory.test/items"))
1892
+ * // Rejected before the retry loop starts, so no further request is sent.
1893
+ * const rejected = yield* Effect.flip(client.execute(HttpClientRequest.get("http://inventory.test/items")))
1894
+ *
1895
+ * return [yield* Ref.get(requests), rejected._tag]
1896
+ * }).pipe(
1897
+ * Effect.scoped,
1898
+ * Effect.provide(Layer.merge(
1899
+ * CircuitBreaker.layerStoreMemory(),
1900
+ * RateLimiter.layer.pipe(Layer.provide(RateLimiter.layerStoreMemory))
1901
+ * ))
1902
+ * )
1903
+ *
1904
+ * await Effect.runPromise(program) // => [3, "CircuitBreakerError"]
1905
+ * ```
1906
+ *
1907
+ * **Example** (Counting an error in the body as a failure)
1908
+ *
1909
+ * This API answers `200` with `{ "status": "degraded" }` when it is failing.
1910
+ *
1911
+ * ```ts import.meta.vitest
1912
+ * import { Data, Effect, Exit, Option } from "effect"
1913
+ * import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http"
1914
+ * import { CircuitBreaker } from "effect/persistence"
1915
+ *
1916
+ * class Degraded extends Data.TaggedError("Degraded") {}
1917
+ *
1918
+ * const degraded = HttpClient.make((request) =>
1919
+ * Effect.succeed(HttpClientResponse.fromWeb(request, Response.json({ status: "degraded" })))
1920
+ * )
1921
+ *
1922
+ * const program = Effect.gen(function*() {
1923
+ * const breaker = yield* CircuitBreaker.make({
1924
+ * tripPolicy: CircuitBreaker.consecutive(1),
1925
+ * openDuration: "30 seconds"
1926
+ * })
1927
+ * const client = degraded.pipe(
1928
+ * HttpClient.transformResponse(Effect.flatMap((response) =>
1929
+ * Effect.flatMap(response.json, (body) =>
1930
+ * typeof body === "object" && body !== null && "status" in body && body.status === "degraded"
1931
+ * ? Effect.fail(new Degraded())
1932
+ * : Effect.succeed(response))
1933
+ * )),
1934
+ * HttpClient.withCircuitBreaker({
1935
+ * breaker,
1936
+ * classify: (exit) =>
1937
+ * Option.exists(Exit.findErrorOption(exit), (error) => error._tag === "Degraded")
1938
+ * ? CircuitBreaker.failure()
1939
+ * : HttpClient.circuitBreakerClassifier(exit)
1940
+ * })
1941
+ * )
1942
+ *
1943
+ * yield* Effect.flip(client.get("http://status.test/"))
1944
+ * const state = yield* breaker.state("http://status.test")
1945
+ * return state._tag
1946
+ * }).pipe(Effect.scoped, Effect.provide(CircuitBreaker.layerStoreMemory()))
1947
+ *
1948
+ * await Effect.runPromise(program) // => "Open"
1949
+ * ```
1950
+ *
1951
+ * @stability experimental
1952
+ * @category circuit breaking
1953
+ * @since 4.0.6
1954
+ */
1955
+ <E, R2 = never>(options: WithCircuitBreaker.Options<E, R2>): <R>(
1956
+ self: HttpClient.With<E, R>
1957
+ ) => HttpClient.With<E | CircuitBreaker.CircuitBreakerError, R | R2>
1958
+ /**
1959
+ * Guards requests with a `CircuitBreaker`.
1960
+ *
1961
+ * **Details**
1962
+ *
1963
+ * Requests are keyed by origin unless `key` is set, and classified with
1964
+ * `circuitBreakerClassifier` unless `classify` is set. A rejected request
1965
+ * fails with `CircuitBreakerError` without reaching the wrapped client.
1966
+ *
1967
+ * Apply it after `withRateLimiter` and `retryTransient`, so the breaker sees
1968
+ * one outcome per call and an open circuit skips the retry loop.
1969
+ * `retryTransient` never retries a `CircuitBreakerError`. A custom `classify`
1970
+ * can delegate the cases it doesn't handle to `circuitBreakerClassifier`.
1971
+ *
1972
+ * **Gotchas**
1973
+ *
1974
+ * - The breaker only sees the response headers. To count an error in the
1975
+ * body, lift it into the error channel below the breaker with
1976
+ * `transformResponse` and count it in `classify`.
1977
+ * - `withRateLimiter` retries `429` without limit by default, which can hold
1978
+ * the probe slot for minutes. Set its `times`.
1979
+ * - A rejected request has no client span. The rejection fails the caller's
1980
+ * span instead.
1981
+ *
1982
+ * **Example** (Guarding an API in the recommended order)
1983
+ *
1984
+ * ```ts import.meta.vitest
1985
+ * import { Effect, Layer, Ref, Schedule } from "effect"
1986
+ * import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http"
1987
+ * import { CircuitBreaker, RateLimiter } from "effect/persistence"
1988
+ *
1989
+ * const program = Effect.gen(function*() {
1990
+ * const requests = yield* Ref.make(0)
1991
+ * // A dependency that always answers 503.
1992
+ * const unavailable = HttpClient.make((request) =>
1993
+ * Effect.as(Ref.update(requests, (n) => n + 1), HttpClientResponse.fromWeb(request, new Response(null, { status: 503 })))
1994
+ * )
1995
+ *
1996
+ * const breaker = yield* CircuitBreaker.make({
1997
+ * tripPolicy: CircuitBreaker.consecutive(1),
1998
+ * openDuration: "30 seconds"
1999
+ * })
2000
+ * const client = unavailable.pipe(
2001
+ * HttpClient.withRateLimiter({
2002
+ * limiter: yield* RateLimiter.RateLimiter,
2003
+ * key: "inventory",
2004
+ * limit: 100,
2005
+ * window: "1 second",
2006
+ * times: 3
2007
+ * }),
2008
+ * HttpClient.retryTransient({ times: 2, schedule: Schedule.exponential("1 millis") }),
2009
+ * HttpClient.withCircuitBreaker({ breaker })
2010
+ * )
2011
+ *
2012
+ * // Three attempts, then the breaker records one failure and opens.
2013
+ * yield* client.execute(HttpClientRequest.get("http://inventory.test/items"))
2014
+ * // Rejected before the retry loop starts, so no further request is sent.
2015
+ * const rejected = yield* Effect.flip(client.execute(HttpClientRequest.get("http://inventory.test/items")))
2016
+ *
2017
+ * return [yield* Ref.get(requests), rejected._tag]
2018
+ * }).pipe(
2019
+ * Effect.scoped,
2020
+ * Effect.provide(Layer.merge(
2021
+ * CircuitBreaker.layerStoreMemory(),
2022
+ * RateLimiter.layer.pipe(Layer.provide(RateLimiter.layerStoreMemory))
2023
+ * ))
2024
+ * )
2025
+ *
2026
+ * await Effect.runPromise(program) // => [3, "CircuitBreakerError"]
2027
+ * ```
2028
+ *
2029
+ * **Example** (Counting an error in the body as a failure)
2030
+ *
2031
+ * This API answers `200` with `{ "status": "degraded" }` when it is failing.
2032
+ *
2033
+ * ```ts import.meta.vitest
2034
+ * import { Data, Effect, Exit, Option } from "effect"
2035
+ * import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http"
2036
+ * import { CircuitBreaker } from "effect/persistence"
2037
+ *
2038
+ * class Degraded extends Data.TaggedError("Degraded") {}
2039
+ *
2040
+ * const degraded = HttpClient.make((request) =>
2041
+ * Effect.succeed(HttpClientResponse.fromWeb(request, Response.json({ status: "degraded" })))
2042
+ * )
2043
+ *
2044
+ * const program = Effect.gen(function*() {
2045
+ * const breaker = yield* CircuitBreaker.make({
2046
+ * tripPolicy: CircuitBreaker.consecutive(1),
2047
+ * openDuration: "30 seconds"
2048
+ * })
2049
+ * const client = degraded.pipe(
2050
+ * HttpClient.transformResponse(Effect.flatMap((response) =>
2051
+ * Effect.flatMap(response.json, (body) =>
2052
+ * typeof body === "object" && body !== null && "status" in body && body.status === "degraded"
2053
+ * ? Effect.fail(new Degraded())
2054
+ * : Effect.succeed(response))
2055
+ * )),
2056
+ * HttpClient.withCircuitBreaker({
2057
+ * breaker,
2058
+ * classify: (exit) =>
2059
+ * Option.exists(Exit.findErrorOption(exit), (error) => error._tag === "Degraded")
2060
+ * ? CircuitBreaker.failure()
2061
+ * : HttpClient.circuitBreakerClassifier(exit)
2062
+ * })
2063
+ * )
2064
+ *
2065
+ * yield* Effect.flip(client.get("http://status.test/"))
2066
+ * const state = yield* breaker.state("http://status.test")
2067
+ * return state._tag
2068
+ * }).pipe(Effect.scoped, Effect.provide(CircuitBreaker.layerStoreMemory()))
2069
+ *
2070
+ * await Effect.runPromise(program) // => "Open"
2071
+ * ```
2072
+ *
2073
+ * @stability experimental
2074
+ * @category circuit breaking
2075
+ * @since 4.0.6
2076
+ */
2077
+ <E, R, R2 = never>(self: HttpClient.With<E, R>, options: WithCircuitBreaker.Options<E, R2>): HttpClient.With<E | CircuitBreaker.CircuitBreakerError, R | R2>
2078
+ } = dual(2, <E, R, R2>(
2079
+ self: HttpClient.With<E, R>,
2080
+ options: WithCircuitBreaker.Options<E, R2>
2081
+ ): HttpClient.With<E | CircuitBreaker.CircuitBreakerError, R | R2> => {
2082
+ const keyOption = options.key
2083
+ const resolveKey: (request: HttpClientRequest.HttpClientRequest) => string = typeof keyOption === "function"
2084
+ ? keyOption
2085
+ : keyOption === undefined
2086
+ ? requestOrigin
2087
+ : constant(keyOption)
2088
+ const classify = options.classify ?? circuitBreakerClassifier
2089
+ return transform(self, (effect, request) => options.breaker.execute(effect, { key: resolveKey(request), classify }))
2090
+ })
2091
+
2092
+ const requestOrigin = (request: HttpClientRequest.HttpClientRequest): string =>
2093
+ Option.match(HttpClientRequest.toUrl(request), {
2094
+ onNone: () => request.url,
2095
+ onSome: (url) => url.origin
2096
+ })
2097
+
2098
+ /**
2099
+ * The default `withCircuitBreaker` classifier.
2100
+ *
2101
+ * **Details**
2102
+ *
2103
+ * - Failure: status 408, 500, 502, 503 or 504, returned or wrapped in a
2104
+ * `StatusCodeError`, and any `TransportError` or `Cause.TimeoutError`.
2105
+ * - Success: any other response, including other 4xx, since the dependency
2106
+ * answered.
2107
+ * - Ignored: status 429 (left to `withRateLimiter`), `EncodeError`,
2108
+ * `InvalidUrlError`, `DecodeError`, `EmptyBodyError`, unknown typed errors
2109
+ * and defects. HttpClient errors are typed, so a defect here is a bug in
2110
+ * the caller.
2111
+ *
2112
+ * When a cause holds several errors, a failure beats a success and a success
2113
+ * beats an ignored outcome. A failure carries the longest `Retry-After` it
2114
+ * saw. The result is an `Effect` only because parsing an HTTP-date
2115
+ * `Retry-After` reads `Clock`.
2116
+ *
2117
+ * **Gotchas**
2118
+ *
2119
+ * `TransportError` also covers client-side refusals, which count as failures.
2120
+ *
2121
+ * @stability experimental
2122
+ * @category circuit breaking
2123
+ * @since 4.0.6
2124
+ */
2125
+ export const circuitBreakerClassifier = <E>(
2126
+ exit: Exit.Exit<HttpClientResponse.HttpClientResponse, E>
2127
+ ): Effect.Effect<CircuitBreaker.Outcome> =>
2128
+ Effect.clockWith((clock) => Effect.succeed(classifyCircuitBreakerExit(exit, clock.currentTimeMillisUnsafe())))
2129
+
2130
+ const classifyCircuitBreakerExit = <E>(
2131
+ exit: Exit.Exit<HttpClientResponse.HttpClientResponse, E>,
2132
+ nowMillis: number
2133
+ ): CircuitBreaker.Outcome => {
2134
+ if (Exit.isSuccess(exit)) {
2135
+ const outcome = circuitBreakerStatusOutcome(exit.value.status)
2136
+ return outcome === "Failure" ? circuitBreakerFailure(retryAfterOf(exit.value, nowMillis)) : { _tag: outcome }
2137
+ }
2138
+ let failed = false
2139
+ let succeeded = false
2140
+ let retryAfter: Duration.Duration | undefined
2141
+ for (const reason of exit.cause.reasons) {
2142
+ if (!Cause.isFailReason(reason)) {
2143
+ continue
2144
+ }
2145
+ const outcome = circuitBreakerErrorOutcome(reason.error)
2146
+ if (outcome === "Failure") {
2147
+ failed = true
2148
+ const hint = retryAfterOf(reason.error, nowMillis)
2149
+ if (hint !== undefined) {
2150
+ retryAfter = retryAfter === undefined ? hint : Duration.max(retryAfter, hint)
2151
+ }
2152
+ } else if (outcome === "Success") {
2153
+ succeeded = true
2154
+ }
2155
+ }
2156
+ return failed ? circuitBreakerFailure(retryAfter) : { _tag: succeeded ? "Success" : "Ignored" }
2157
+ }
2158
+
2159
+ const circuitBreakerFailure = (retryAfter: Duration.Duration | undefined): CircuitBreaker.Outcome => ({
2160
+ _tag: "Failure",
2161
+ retryAfter
2162
+ })
2163
+
2164
+ const circuitBreakerErrorOutcome = (error: unknown): CircuitBreaker.Outcome["_tag"] => {
2165
+ if (Cause.isTimeoutError(error)) {
2166
+ return "Failure"
2167
+ }
2168
+ if (!Error.isHttpClientError(error)) {
2169
+ return "Ignored"
2170
+ }
2171
+ switch (error.reason._tag) {
2172
+ case "TransportError":
2173
+ return "Failure"
2174
+ case "StatusCodeError":
2175
+ return circuitBreakerStatusOutcome(error.reason.response.status)
2176
+ default:
2177
+ return "Ignored"
2178
+ }
2179
+ }
2180
+
2181
+ const circuitBreakerStatusOutcome = (status: number): CircuitBreaker.Outcome["_tag"] =>
2182
+ status === 429
2183
+ ? "Ignored"
2184
+ : status === 408 || status === 500 || status === 502 || status === 503 || status === 504
2185
+ ? "Failure"
2186
+ : "Success"
2187
+
1681
2188
  interface RateLimiterHeaderNames {
1682
2189
  readonly limit: ReadonlyArray<string>
1683
2190
  readonly remaining: ReadonlyArray<string>
@@ -2187,13 +2694,31 @@ export const followRedirects: {
2187
2694
  ) {
2188
2695
  nextRequest = HttpClientRequest.setMethod(nextRequest, "GET")
2189
2696
  nextRequest = HttpClientRequest.setBody(nextRequest, HttpBody.empty)
2697
+ nextRequest = HttpClientRequest.removeHeader(nextRequest, "content-encoding")
2698
+ nextRequest = HttpClientRequest.removeHeader(nextRequest, "content-language")
2699
+ nextRequest = HttpClientRequest.removeHeader(nextRequest, "content-location")
2190
2700
  }
2191
2701
  if (url.origin !== new URL(response.request.url).origin) {
2192
2702
  nextRequest = HttpClientRequest.removeHeader(nextRequest, "authorization")
2193
2703
  nextRequest = HttpClientRequest.removeHeader(nextRequest, "proxy-authorization")
2194
2704
  nextRequest = HttpClientRequest.removeHeader(nextRequest, "cookie")
2195
2705
  }
2196
- return loop(Effect.succeed(HttpClientRequest.setUrl(nextRequest, url)), redirects + 1)
2706
+ // Request the Location as sent: setUrl with a URL object would re-encode its query
2707
+ const hash = url.hash === "" ? Option.none() : Option.some(url.hash.slice(1))
2708
+ url.hash = ""
2709
+ nextRequest = HttpClientRequest.makeWith(
2710
+ nextRequest.method,
2711
+ url.href,
2712
+ UrlParams.empty,
2713
+ hash,
2714
+ nextRequest.headers,
2715
+ nextRequest.body
2716
+ )
2717
+ // Abort the discarded response to release its connection without reading the body
2718
+ return Effect.andThen(
2719
+ Effect.sync(() => responseControllers.get(response)?.abort()),
2720
+ loop(Effect.succeed(nextRequest), redirects + 1)
2721
+ )
2197
2722
  }
2198
2723
  )
2199
2724
  })
@@ -2332,6 +2857,21 @@ const responseRegistry = (() => {
2332
2857
 
2333
2858
  const scopedRequests = new WeakMap<HttpClientRequest.HttpClientRequest, AbortController>()
2334
2859
 
2860
+ const responseControllers = new WeakMap<HttpClientResponse.HttpClientResponse, AbortController>()
2861
+
2862
+ const trackResponse = (
2863
+ response: HttpClientResponse.HttpClientResponse,
2864
+ controller: AbortController,
2865
+ scoped: boolean
2866
+ ): HttpClientResponse.HttpClientResponse => {
2867
+ if (!scoped) {
2868
+ responseRegistry.register(response, controller)
2869
+ response = new InterruptibleResponse(response, controller)
2870
+ }
2871
+ responseControllers.set(response, controller)
2872
+ return response
2873
+ }
2874
+
2335
2875
  class InterruptibleResponse implements HttpClientResponse.HttpClientResponse, Pipeable {
2336
2876
  readonly original: HttpClientResponse.HttpClientResponse
2337
2877
  readonly controller: AbortController
@@ -92,6 +92,15 @@ const formatMessage = (reason: string, description: string | undefined, info: st
92
92
  const formatMethodAndUrl = (request: HttpClientRequest.HttpClientRequest) =>
93
93
  `${request.method} ${UrlParams.redactUrl(request.url)}`
94
94
 
95
+ // Serialized reasons carry the same request and response information as the
96
+ // message, so headers, URL parameters and bodies stay out of logs. The full
97
+ // objects remain available through the `request` and `response` properties.
98
+ const reasonToJSON = (reason: HttpClientErrorReason, json: unknown) => ({
99
+ ...(json as object),
100
+ request: { _id: "HttpClientRequest", method: reason.request.method, url: UrlParams.redactUrl(reason.request.url) },
101
+ ...("response" in reason ? { response: { _id: "HttpClientResponse", status: reason.response.status } } : undefined)
102
+ })
103
+
95
104
  /**
96
105
  * Error describing transport-level failures that occur while sending an HTTP request.
97
106
  *
@@ -123,6 +132,10 @@ export class TransportError extends Data.TaggedError("TransportError")<{
123
132
  override get message() {
124
133
  return formatMessage(formatReason(this._tag), this.description, this.methodAndUrl)
125
134
  }
135
+
136
+ override toJSON(): unknown {
137
+ return reasonToJSON(this, super.toJSON())
138
+ }
126
139
  }
127
140
 
128
141
  /**
@@ -156,6 +169,10 @@ export class EncodeError extends Data.TaggedError("EncodeError")<{
156
169
  override get message() {
157
170
  return formatMessage(formatReason(this._tag), this.description, this.methodAndUrl)
158
171
  }
172
+
173
+ override toJSON(): unknown {
174
+ return reasonToJSON(this, super.toJSON())
175
+ }
159
176
  }
160
177
 
161
178
  /**
@@ -189,6 +206,10 @@ export class InvalidUrlError extends Data.TaggedError("InvalidUrlError")<{
189
206
  override get message() {
190
207
  return formatMessage(formatReason(this._tag), this.description, this.methodAndUrl)
191
208
  }
209
+
210
+ override toJSON(): unknown {
211
+ return reasonToJSON(this, super.toJSON())
212
+ }
192
213
  }
193
214
 
194
215
  /**
@@ -224,10 +245,15 @@ export class StatusCodeError extends Data.TaggedError("StatusCodeError")<{
224
245
  const info = `${this.response.status} ${this.methodAndUrl}`
225
246
  return formatMessage(formatReason(this._tag), this.description, info)
226
247
  }
248
+
249
+ override toJSON(): unknown {
250
+ return reasonToJSON(this, super.toJSON())
251
+ }
227
252
  }
228
253
 
229
254
  /**
230
- * Response error for failures while decoding an HTTP response body.
255
+ * Response error for failures while decoding an HTTP response, including a
256
+ * response with an undeclared status.
231
257
  *
232
258
  * @stability unstable
233
259
  * @category errors
@@ -259,6 +285,10 @@ export class DecodeError extends Data.TaggedError("DecodeError")<{
259
285
  const info = `${this.response.status} ${this.methodAndUrl}`
260
286
  return formatMessage(formatReason(this._tag), this.description, info)
261
287
  }
288
+
289
+ override toJSON(): unknown {
290
+ return reasonToJSON(this, super.toJSON())
291
+ }
262
292
  }
263
293
 
264
294
  /**
@@ -294,6 +324,10 @@ export class EmptyBodyError extends Data.TaggedError("EmptyBodyError")<{
294
324
  const info = `${this.response.status} ${this.methodAndUrl}`
295
325
  return formatMessage(formatReason(this._tag), this.description, info)
296
326
  }
327
+
328
+ override toJSON(): unknown {
329
+ return reasonToJSON(this, super.toJSON())
330
+ }
297
331
  }
298
332
 
299
333
  /**