effect 4.1.0 → 4.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (354) hide show
  1. package/README.md +30 -0
  2. package/THIRD_PARTY_NOTICES.md +62 -0
  3. package/dist/BigDecimal.d.ts +139 -7
  4. package/dist/BigDecimal.d.ts.map +1 -1
  5. package/dist/BigDecimal.js +83 -14
  6. package/dist/BigDecimal.js.map +1 -1
  7. package/dist/Equal.d.ts +2 -2
  8. package/dist/Equal.d.ts.map +1 -1
  9. package/dist/Equal.js +3 -3
  10. package/dist/Equal.js.map +1 -1
  11. package/dist/Hash.d.ts +3 -2
  12. package/dist/Hash.d.ts.map +1 -1
  13. package/dist/Hash.js +5 -4
  14. package/dist/Hash.js.map +1 -1
  15. package/dist/Iterable.d.ts.map +1 -1
  16. package/dist/Iterable.js +11 -8
  17. package/dist/Iterable.js.map +1 -1
  18. package/dist/Path.d.ts.map +1 -1
  19. package/dist/Path.js +5 -1
  20. package/dist/Path.js.map +1 -1
  21. package/dist/Pool.d.ts.map +1 -1
  22. package/dist/Pool.js +2 -1
  23. package/dist/Pool.js.map +1 -1
  24. package/dist/Schema.d.ts +2 -1
  25. package/dist/Schema.d.ts.map +1 -1
  26. package/dist/Schema.js +2 -1
  27. package/dist/Schema.js.map +1 -1
  28. package/dist/SchemaRepresentation.d.ts +4 -2
  29. package/dist/SchemaRepresentation.d.ts.map +1 -1
  30. package/dist/SchemaRepresentation.js +4 -2
  31. package/dist/SchemaRepresentation.js.map +1 -1
  32. package/dist/SchemaTransformation.d.ts +2 -2
  33. package/dist/SchemaTransformation.js +2 -2
  34. package/dist/ai/McpClient.d.ts +171 -19
  35. package/dist/ai/McpClient.d.ts.map +1 -1
  36. package/dist/ai/McpClient.js +277 -66
  37. package/dist/ai/McpClient.js.map +1 -1
  38. package/dist/ai/McpSchema.d.ts +108 -0
  39. package/dist/ai/McpSchema.d.ts.map +1 -1
  40. package/dist/ai/McpSchema.js +99 -0
  41. package/dist/ai/McpSchema.js.map +1 -1
  42. package/dist/ai/McpServer.d.ts +120 -6
  43. package/dist/ai/McpServer.d.ts.map +1 -1
  44. package/dist/ai/McpServer.js +215 -34
  45. package/dist/ai/McpServer.js.map +1 -1
  46. package/dist/ai/Prompt.d.ts.map +1 -1
  47. package/dist/ai/Prompt.js +20 -11
  48. package/dist/ai/Prompt.js.map +1 -1
  49. package/dist/ai/Tool.d.ts.map +1 -1
  50. package/dist/ai/Tool.js +5 -7
  51. package/dist/ai/Tool.js.map +1 -1
  52. package/dist/ai/internal/mcpCore.js +72 -3
  53. package/dist/ai/internal/mcpCore.js.map +1 -1
  54. package/dist/ai/internal/mcpProtocol/v2024_11_05.js +3 -1
  55. package/dist/ai/internal/mcpProtocol/v2024_11_05.js.map +1 -1
  56. package/dist/ai/internal/mcpProtocol/v2025_03_26.js +3 -1
  57. package/dist/ai/internal/mcpProtocol/v2025_03_26.js.map +1 -1
  58. package/dist/ai/internal/mcpProtocol/v2025_06_18.js +3 -1
  59. package/dist/ai/internal/mcpProtocol/v2025_06_18.js.map +1 -1
  60. package/dist/ai/internal/mcpProtocol/v2025_11_25.js +3 -1
  61. package/dist/ai/internal/mcpProtocol/v2025_11_25.js.map +1 -1
  62. package/dist/ai/internal/mcpProtocol/v2026_07_28.js +42 -7
  63. package/dist/ai/internal/mcpProtocol/v2026_07_28.js.map +1 -1
  64. package/dist/ai/internal/mcpProtocol.js +12 -0
  65. package/dist/ai/internal/mcpProtocol.js.map +1 -1
  66. package/dist/ai/internal/mcpRuntime.js +3 -3
  67. package/dist/ai/internal/mcpRuntime.js.map +1 -1
  68. package/dist/ai/internal/mcpSkills.d.ts +2 -0
  69. package/dist/ai/internal/mcpSkills.d.ts.map +1 -0
  70. package/dist/ai/internal/mcpSkills.js +428 -0
  71. package/dist/ai/internal/mcpSkills.js.map +1 -0
  72. package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
  73. package/dist/cluster/ClusterWorkflowEngine.js +15 -5
  74. package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
  75. package/dist/cluster/Reply.d.ts +1 -1
  76. package/dist/cluster/Reply.d.ts.map +1 -1
  77. package/dist/cluster/Reply.js.map +1 -1
  78. package/dist/cluster/Sharding.d.ts.map +1 -1
  79. package/dist/cluster/Sharding.js +4 -1
  80. package/dist/cluster/Sharding.js.map +1 -1
  81. package/dist/cluster/internal/entityManager.js +15 -7
  82. package/dist/cluster/internal/entityManager.js.map +1 -1
  83. package/dist/crypto/Aead.d.ts +2 -1
  84. package/dist/crypto/Aead.d.ts.map +1 -1
  85. package/dist/crypto/Aead.js +2 -2
  86. package/dist/crypto/Aead.js.map +1 -1
  87. package/dist/crypto/Cipher.d.ts +2 -1
  88. package/dist/crypto/Cipher.d.ts.map +1 -1
  89. package/dist/crypto/Cipher.js +2 -2
  90. package/dist/crypto/Cipher.js.map +1 -1
  91. package/dist/crypto/KeyAgreement.d.ts +3 -2
  92. package/dist/crypto/KeyAgreement.d.ts.map +1 -1
  93. package/dist/crypto/KeyAgreement.js +2 -2
  94. package/dist/crypto/KeyAgreement.js.map +1 -1
  95. package/dist/crypto/KeyFormat.d.ts +33 -1
  96. package/dist/crypto/KeyFormat.d.ts.map +1 -1
  97. package/dist/crypto/KeyFormat.js.map +1 -1
  98. package/dist/crypto/KeyWrap.d.ts +4 -3
  99. package/dist/crypto/KeyWrap.d.ts.map +1 -1
  100. package/dist/crypto/KeyWrap.js +2 -2
  101. package/dist/crypto/KeyWrap.js.map +1 -1
  102. package/dist/crypto/Mac.d.ts +2 -1
  103. package/dist/crypto/Mac.d.ts.map +1 -1
  104. package/dist/crypto/Mac.js +2 -2
  105. package/dist/crypto/Mac.js.map +1 -1
  106. package/dist/crypto/Signature.d.ts +3 -2
  107. package/dist/crypto/Signature.d.ts.map +1 -1
  108. package/dist/crypto/Signature.js +2 -2
  109. package/dist/crypto/Signature.js.map +1 -1
  110. package/dist/crypto/WebCrypto.d.ts +19 -0
  111. package/dist/crypto/WebCrypto.d.ts.map +1 -1
  112. package/dist/crypto/WebCrypto.js.map +1 -1
  113. package/dist/crypto/internal/asymmetric.js.map +1 -1
  114. package/dist/crypto/internal/key.js +3 -2
  115. package/dist/crypto/internal/key.js.map +1 -1
  116. package/dist/encoding/Base64Url.d.ts.map +1 -1
  117. package/dist/encoding/Base64Url.js +26 -3
  118. package/dist/encoding/Base64Url.js.map +1 -1
  119. package/dist/encoding/Ndjson.d.ts +5 -4
  120. package/dist/encoding/Ndjson.d.ts.map +1 -1
  121. package/dist/encoding/Ndjson.js +6 -5
  122. package/dist/encoding/Ndjson.js.map +1 -1
  123. package/dist/encoding/Sse.d.ts +3 -1
  124. package/dist/encoding/Sse.d.ts.map +1 -1
  125. package/dist/encoding/Sse.js +5 -3
  126. package/dist/encoding/Sse.js.map +1 -1
  127. package/dist/eventlog/EventLog.d.ts +7 -0
  128. package/dist/eventlog/EventLog.d.ts.map +1 -1
  129. package/dist/eventlog/EventLog.js +7 -0
  130. package/dist/eventlog/EventLog.js.map +1 -1
  131. package/dist/eventlog/EventLogServer.d.ts +7 -1
  132. package/dist/eventlog/EventLogServer.d.ts.map +1 -1
  133. package/dist/eventlog/EventLogServer.js +27 -12
  134. package/dist/eventlog/EventLogServer.js.map +1 -1
  135. package/dist/eventlog/EventLogServerEncrypted.d.ts +10 -0
  136. package/dist/eventlog/EventLogServerEncrypted.d.ts.map +1 -1
  137. package/dist/eventlog/EventLogServerEncrypted.js.map +1 -1
  138. package/dist/eventlog/EventLogServerUnencrypted.d.ts +17 -0
  139. package/dist/eventlog/EventLogServerUnencrypted.d.ts.map +1 -1
  140. package/dist/eventlog/EventLogServerUnencrypted.js +14 -2
  141. package/dist/eventlog/EventLogServerUnencrypted.js.map +1 -1
  142. package/dist/eventlog/EventLogSessionAuth.d.ts +21 -0
  143. package/dist/eventlog/EventLogSessionAuth.d.ts.map +1 -1
  144. package/dist/eventlog/EventLogSessionAuth.js +22 -0
  145. package/dist/eventlog/EventLogSessionAuth.js.map +1 -1
  146. package/dist/graphql/GraphQLClient.d.ts +3 -1
  147. package/dist/graphql/GraphQLClient.d.ts.map +1 -1
  148. package/dist/graphql/GraphQLClient.js.map +1 -1
  149. package/dist/graphql/GraphQLClientError.d.ts +14 -9
  150. package/dist/graphql/GraphQLClientError.d.ts.map +1 -1
  151. package/dist/graphql/GraphQLClientError.js +14 -21
  152. package/dist/graphql/GraphQLClientError.js.map +1 -1
  153. package/dist/graphql/GraphQLProtocol.d.ts +12 -3
  154. package/dist/graphql/GraphQLProtocol.d.ts.map +1 -1
  155. package/dist/graphql/GraphQLProtocol.js +4 -1
  156. package/dist/graphql/GraphQLProtocol.js.map +1 -1
  157. package/dist/http/HttpClient.d.ts +189 -7
  158. package/dist/http/HttpClient.d.ts.map +1 -1
  159. package/dist/http/HttpClient.js +75 -2
  160. package/dist/http/HttpClient.js.map +1 -1
  161. package/dist/http/HttpServerRequest.d.ts.map +1 -1
  162. package/dist/http/HttpServerRequest.js +38 -22
  163. package/dist/http/HttpServerRequest.js.map +1 -1
  164. package/dist/http/internal/mimeTypes.d.ts +4 -1
  165. package/dist/http/internal/mimeTypes.d.ts.map +1 -1
  166. package/dist/http/internal/mimeTypes.js +4 -1
  167. package/dist/http/internal/mimeTypes.js.map +1 -1
  168. package/dist/http-api/HttpApiSchema.js +1 -1
  169. package/dist/http-api/HttpApiSchema.js.map +1 -1
  170. package/dist/internal/dateTime.js +49 -24
  171. package/dist/internal/dateTime.js.map +1 -1
  172. package/dist/internal/effect.js +10 -0
  173. package/dist/internal/effect.js.map +1 -1
  174. package/dist/internal/glob.js +234 -56
  175. package/dist/internal/glob.js.map +1 -1
  176. package/dist/internal/graphql.js +21 -7
  177. package/dist/internal/graphql.js.map +1 -1
  178. package/dist/internal/graphqlHeaders.d.ts +7 -0
  179. package/dist/internal/graphqlHeaders.d.ts.map +1 -1
  180. package/dist/internal/graphqlHeaders.js +11 -0
  181. package/dist/internal/graphqlHeaders.js.map +1 -1
  182. package/dist/internal/request.js +29 -42
  183. package/dist/internal/request.js.map +1 -1
  184. package/dist/internal/schema/fromJsonSchemaDocument.js +7 -8
  185. package/dist/internal/schema/fromJsonSchemaDocument.js.map +1 -1
  186. package/dist/internal/version.js +1 -1
  187. package/dist/jose/JoseError.d.ts +285 -0
  188. package/dist/jose/JoseError.d.ts.map +1 -0
  189. package/dist/jose/JoseError.js +269 -0
  190. package/dist/jose/JoseError.js.map +1 -0
  191. package/dist/jose/Jwe.d.ts +128 -0
  192. package/dist/jose/Jwe.d.ts.map +1 -0
  193. package/dist/jose/Jwe.js +134 -0
  194. package/dist/jose/Jwe.js.map +1 -0
  195. package/dist/jose/Jwk.d.ts +597 -0
  196. package/dist/jose/Jwk.d.ts.map +1 -0
  197. package/dist/jose/Jwk.js +503 -0
  198. package/dist/jose/Jwk.js.map +1 -0
  199. package/dist/jose/Jwks.d.ts +236 -0
  200. package/dist/jose/Jwks.d.ts.map +1 -0
  201. package/dist/jose/Jwks.js +306 -0
  202. package/dist/jose/Jwks.js.map +1 -0
  203. package/dist/jose/Jws.d.ts +177 -0
  204. package/dist/jose/Jws.d.ts.map +1 -0
  205. package/dist/jose/Jws.js +183 -0
  206. package/dist/jose/Jws.js.map +1 -0
  207. package/dist/jose/Jwt.d.ts +270 -0
  208. package/dist/jose/Jwt.d.ts.map +1 -0
  209. package/dist/jose/Jwt.js +293 -0
  210. package/dist/jose/Jwt.js.map +1 -0
  211. package/dist/jose/index.d.ts +51 -0
  212. package/dist/jose/index.d.ts.map +1 -0
  213. package/dist/jose/index.js +52 -0
  214. package/dist/jose/index.js.map +1 -0
  215. package/dist/jose/internal/compact.d.ts +2 -0
  216. package/dist/jose/internal/compact.d.ts.map +1 -0
  217. package/dist/jose/internal/compact.js +179 -0
  218. package/dist/jose/internal/compact.js.map +1 -0
  219. package/dist/net/Host.d.ts.map +1 -1
  220. package/dist/net/Host.js +5 -10
  221. package/dist/net/Host.js.map +1 -1
  222. package/dist/observability/OtlpSerialization.d.ts +1 -1
  223. package/dist/observability/OtlpSerialization.d.ts.map +1 -1
  224. package/dist/observability/OtlpSerialization.js +10 -4
  225. package/dist/observability/OtlpSerialization.js.map +1 -1
  226. package/dist/observability/internal/otlpProtobuf.js +3 -3
  227. package/dist/observability/internal/otlpProtobuf.js.map +1 -1
  228. package/dist/observability/internal/protobuf.js +6 -0
  229. package/dist/observability/internal/protobuf.js.map +1 -1
  230. package/dist/persistence/CircuitBreaker.d.ts +98 -38
  231. package/dist/persistence/CircuitBreaker.d.ts.map +1 -1
  232. package/dist/persistence/CircuitBreaker.js +67 -29
  233. package/dist/persistence/CircuitBreaker.js.map +1 -1
  234. package/dist/persistence/RateLimiter.d.ts +8 -0
  235. package/dist/persistence/RateLimiter.d.ts.map +1 -1
  236. package/dist/persistence/RateLimiter.js +63 -12
  237. package/dist/persistence/RateLimiter.js.map +1 -1
  238. package/dist/persistence/index.d.ts +1 -1
  239. package/dist/persistence/index.js +1 -1
  240. package/dist/reactivity/AtomRegistry.js +17 -7
  241. package/dist/reactivity/AtomRegistry.js.map +1 -1
  242. package/dist/rpc/Rpc.d.ts +1 -1
  243. package/dist/rpc/Rpc.d.ts.map +1 -1
  244. package/dist/rpc/Rpc.js.map +1 -1
  245. package/dist/rpc/RpcClient.d.ts +14 -2
  246. package/dist/rpc/RpcClient.d.ts.map +1 -1
  247. package/dist/rpc/RpcClient.js +38 -21
  248. package/dist/rpc/RpcClient.js.map +1 -1
  249. package/dist/rpc/RpcMessage.d.ts +3 -2
  250. package/dist/rpc/RpcMessage.d.ts.map +1 -1
  251. package/dist/rpc/RpcMessage.js.map +1 -1
  252. package/dist/sql/Migrator.d.ts +9 -1
  253. package/dist/sql/Migrator.d.ts.map +1 -1
  254. package/dist/sql/Migrator.js +18 -6
  255. package/dist/sql/Migrator.js.map +1 -1
  256. package/dist/sql/SqlClient.d.ts +38 -3
  257. package/dist/sql/SqlClient.d.ts.map +1 -1
  258. package/dist/sql/SqlClient.js +4 -3
  259. package/dist/sql/SqlClient.js.map +1 -1
  260. package/dist/sql/Statement.d.ts +41 -3
  261. package/dist/sql/Statement.d.ts.map +1 -1
  262. package/dist/sql/Statement.js +24 -20
  263. package/dist/sql/Statement.js.map +1 -1
  264. package/dist/workflow/Workflow.d.ts +4 -0
  265. package/dist/workflow/Workflow.d.ts.map +1 -1
  266. package/dist/workflow/Workflow.js.map +1 -1
  267. package/dist/workflow/WorkflowEngine.d.ts.map +1 -1
  268. package/dist/workflow/WorkflowEngine.js +5 -0
  269. package/dist/workflow/WorkflowEngine.js.map +1 -1
  270. package/package.json +5 -1
  271. package/src/BigDecimal.ts +170 -16
  272. package/src/Equal.ts +3 -3
  273. package/src/Hash.ts +5 -4
  274. package/src/Iterable.ts +8 -5
  275. package/src/Path.ts +6 -1
  276. package/src/Pool.ts +2 -1
  277. package/src/Schema.ts +3 -2
  278. package/src/SchemaRepresentation.ts +4 -2
  279. package/src/SchemaTransformation.ts +2 -2
  280. package/src/ai/McpClient.ts +488 -91
  281. package/src/ai/McpSchema.ts +119 -0
  282. package/src/ai/McpServer.ts +261 -38
  283. package/src/ai/Prompt.ts +16 -11
  284. package/src/ai/Tool.ts +5 -10
  285. package/src/ai/internal/mcpCore.ts +165 -12
  286. package/src/ai/internal/mcpProtocol/v2024_11_05.ts +3 -1
  287. package/src/ai/internal/mcpProtocol/v2025_03_26.ts +3 -1
  288. package/src/ai/internal/mcpProtocol/v2025_06_18.ts +3 -1
  289. package/src/ai/internal/mcpProtocol/v2025_11_25.ts +3 -1
  290. package/src/ai/internal/mcpProtocol/v2026_07_28.ts +41 -7
  291. package/src/ai/internal/mcpProtocol.ts +15 -0
  292. package/src/ai/internal/mcpRuntime.ts +6 -3
  293. package/src/ai/internal/mcpSkills.ts +480 -0
  294. package/src/cluster/ClusterWorkflowEngine.ts +22 -8
  295. package/src/cluster/Reply.ts +1 -1
  296. package/src/cluster/Sharding.ts +4 -1
  297. package/src/cluster/internal/entityManager.ts +24 -10
  298. package/src/crypto/Aead.ts +3 -3
  299. package/src/crypto/Cipher.ts +3 -3
  300. package/src/crypto/KeyAgreement.ts +4 -4
  301. package/src/crypto/KeyFormat.ts +30 -1
  302. package/src/crypto/KeyWrap.ts +6 -6
  303. package/src/crypto/Mac.ts +3 -3
  304. package/src/crypto/Signature.ts +4 -4
  305. package/src/crypto/WebCrypto.ts +20 -0
  306. package/src/crypto/internal/asymmetric.ts +2 -1
  307. package/src/crypto/internal/key.ts +12 -5
  308. package/src/encoding/Base64Url.ts +27 -3
  309. package/src/encoding/Ndjson.ts +6 -5
  310. package/src/encoding/Sse.ts +5 -3
  311. package/src/eventlog/EventLog.ts +7 -0
  312. package/src/eventlog/EventLogServer.ts +31 -12
  313. package/src/eventlog/EventLogServerEncrypted.ts +5 -0
  314. package/src/eventlog/EventLogServerUnencrypted.ts +19 -2
  315. package/src/eventlog/EventLogSessionAuth.ts +26 -0
  316. package/src/graphql/GraphQLClient.ts +3 -1
  317. package/src/graphql/GraphQLClientError.ts +15 -22
  318. package/src/graphql/GraphQLProtocol.ts +12 -3
  319. package/src/http/HttpClient.ts +210 -11
  320. package/src/http/HttpServerRequest.ts +61 -23
  321. package/src/http/internal/mimeTypes.ts +4 -1
  322. package/src/http-api/HttpApiSchema.ts +1 -1
  323. package/src/internal/dateTime.ts +54 -24
  324. package/src/internal/effect.ts +6 -0
  325. package/src/internal/glob.ts +279 -63
  326. package/src/internal/graphql.ts +27 -9
  327. package/src/internal/graphqlHeaders.ts +13 -0
  328. package/src/internal/request.ts +51 -58
  329. package/src/internal/schema/fromJsonSchemaDocument.ts +11 -10
  330. package/src/internal/version.ts +1 -1
  331. package/src/jose/JoseError.ts +329 -0
  332. package/src/jose/Jwe.ts +196 -0
  333. package/src/jose/Jwk.ts +777 -0
  334. package/src/jose/Jwks.ts +418 -0
  335. package/src/jose/Jws.ts +312 -0
  336. package/src/jose/Jwt.ts +493 -0
  337. package/src/jose/index.ts +58 -0
  338. package/src/jose/internal/compact.ts +195 -0
  339. package/src/net/Host.ts +5 -10
  340. package/src/observability/OtlpSerialization.ts +13 -5
  341. package/src/observability/internal/otlpProtobuf.ts +6 -6
  342. package/src/observability/internal/protobuf.ts +10 -0
  343. package/src/persistence/CircuitBreaker.ts +113 -48
  344. package/src/persistence/RateLimiter.ts +84 -15
  345. package/src/persistence/index.ts +1 -1
  346. package/src/reactivity/AtomRegistry.ts +19 -8
  347. package/src/rpc/Rpc.ts +3 -1
  348. package/src/rpc/RpcClient.ts +44 -24
  349. package/src/rpc/RpcMessage.ts +3 -2
  350. package/src/sql/Migrator.ts +35 -18
  351. package/src/sql/SqlClient.ts +43 -8
  352. package/src/sql/Statement.ts +52 -22
  353. package/src/workflow/Workflow.ts +4 -0
  354. package/src/workflow/WorkflowEngine.ts +5 -0
@@ -6,11 +6,10 @@
6
6
  * @since 4.0.0
7
7
  */
8
8
  import type * as Duration from "../Duration.ts"
9
- import * as Headers from "../http/Headers.ts"
9
+ import type * as Headers from "../http/Headers.ts"
10
10
  import type * as HttpClientError from "../http/HttpClientError.ts"
11
- import { HeadersSchema } from "../internal/graphqlHeaders.ts"
11
+ import { HeadersSchema, parseRetryAfter } from "../internal/graphqlHeaders.ts"
12
12
  import { hasProperty } from "../Predicate.ts"
13
- import * as Result from "../Result.ts"
14
13
  import * as Schema from "../Schema.ts"
15
14
 
16
15
  const TypeId = "~effect/graphql/GraphQLClientError"
@@ -74,8 +73,9 @@ export type GraphQLError = typeof GraphQLError.Type
74
73
  * `{ partial: true }` to receive decoded `{ data, errors }` instead.
75
74
  *
76
75
  * On this error, `data` is raw. `GraphQLError.path[0]` identifies the response
77
- * key (or alias). Non-2xx HTTP responses with a GraphQL body also use this
78
- * reason rather than `TransportError`.
76
+ * key (or alias). Non-2xx HTTP responses with a GraphQL body and `errors`
77
+ * also use this reason rather than `TransportError`, even when they carry
78
+ * `data` and the call used `{ partial: true }`.
79
79
  *
80
80
  * `status` and `headers` are the HTTP status and response headers, as the
81
81
  * transport reported them and middleware left them. Headers use
@@ -220,27 +220,18 @@ export const isFatalCloseCode = (code: number): boolean =>
220
220
 
221
221
  const isRetryableStatus = (status: number): boolean => status === 429 || (status >= 500 && status < 600)
222
222
 
223
- /**
224
- * Parses a `Retry-After` header value, either whole seconds or an HTTP date,
225
- * into a `Duration` measured from `now` (epoch milliseconds). Anything else,
226
- * such as `1.5` or `-1`, yields `undefined`.
227
- */
228
- const parseRetryAfter = (value: string | undefined, now: number): Duration.Duration | undefined => {
229
- if (value === undefined) return undefined
230
- const retryAfter = Headers.parseRetryAfter(value)
231
- return Result.isSuccess(retryAfter) ? Headers.retryAfterDelay(retryAfter.success, now) : undefined
232
- }
233
-
234
223
  /**
235
224
  * The client could not get a GraphQL response from the server: a network
236
- * failure, an HTTP response that is not a GraphQL response, or a closed
237
- * WebSocket connection.
225
+ * failure, an HTTP response that is not a GraphQL response, a non-2xx HTTP
226
+ * response whose GraphQL body has no `errors`, or a closed WebSocket
227
+ * connection.
238
228
  *
239
229
  * **Details**
240
230
  *
241
231
  * - `status` and `headers` are only set for an HTTP response that is not a
242
- * GraphQL response. Headers use `Headers.Headers` at runtime and encode
243
- * as a plain string record; decoding restores the header collection.
232
+ * GraphQL response, or a non-2xx GraphQL response without `errors`.
233
+ * Headers use `Headers.Headers` at runtime and encode as a plain string
234
+ * record; decoding restores the header collection.
244
235
  * - `retryAfter` comes from the `Retry-After` header (whole seconds or an
245
236
  * HTTP date) and is encoded as milliseconds. When it is set, the error is
246
237
  * retryable at any status, unless the close code is fatal.
@@ -360,8 +351,10 @@ export class EncodeError
360
351
  *
361
352
  * **Details**
362
353
  *
363
- * `data: null` without `errors` also produces a `DecodeError`, since
364
- * `ResponseError` requires a non-empty errors array.
354
+ * `data: null` without `errors` also produces a `DecodeError` for a 2xx
355
+ * response or a result without an HTTP status, since `ResponseError`
356
+ * requires a non-empty errors array. On a non-2xx response it is a
357
+ * `TransportError`.
365
358
  *
366
359
  * @stability experimental
367
360
  * @category errors
@@ -522,7 +522,10 @@ export const makeHttp: {
522
522
  * (or `null`). Media types match case-insensitively. Anything else
523
523
  * is a `TransportError` with the response `status` and `headers`, and a
524
524
  * `Retry-After` header (whole seconds or an HTTP date, measured from when the
525
- * response arrived) becomes `retryAfter`.
525
+ * response arrived) becomes `retryAfter`. A non-2xx GraphQL response is passed
526
+ * to the client, which never treats it as a success: it fails with a
527
+ * `ResponseError` when the body has `errors`, and with a `TransportError`
528
+ * carrying the same metadata otherwise.
526
529
  *
527
530
  * A subscription is a `POST` with `Accept: text/event-stream`. Each `next`
528
531
  * event is emitted with the response headers but no status, and the stream
@@ -738,7 +741,10 @@ export const layerHttp: {
738
741
  * (or `null`). Media types match case-insensitively. Anything else
739
742
  * is a `TransportError` with the response `status` and `headers`, and a
740
743
  * `Retry-After` header (whole seconds or an HTTP date, measured from when the
741
- * response arrived) becomes `retryAfter`.
744
+ * response arrived) becomes `retryAfter`. A non-2xx GraphQL response is passed
745
+ * to the client, which never treats it as a success: it fails with a
746
+ * `ResponseError` when the body has `errors`, and with a `TransportError`
747
+ * carrying the same metadata otherwise.
742
748
  *
743
749
  * A subscription is a `POST` with `Accept: text/event-stream`. Each `next`
744
750
  * event is emitted with the response headers but no status, and the stream
@@ -969,7 +975,10 @@ export const layerHttp: {
969
975
  * (or `null`). Media types match case-insensitively. Anything else
970
976
  * is a `TransportError` with the response `status` and `headers`, and a
971
977
  * `Retry-After` header (whole seconds or an HTTP date, measured from when the
972
- * response arrived) becomes `retryAfter`.
978
+ * response arrived) becomes `retryAfter`. A non-2xx GraphQL response is passed
979
+ * to the client, which never treats it as a success: it fails with a
980
+ * `ResponseError` when the body has `errors`, and with a `TransportError`
981
+ * carrying the same metadata otherwise.
973
982
  *
974
983
  * A subscription is a `POST` with `Accept: text/event-stream`. Each `next`
975
984
  * event is emitted with the response headers but no status, and the stream
@@ -1335,6 +1335,208 @@ export const retryTransient: {
1335
1335
  }
1336
1336
  )
1337
1337
 
1338
+ /**
1339
+ * Fails requests that do not receive a response within the given duration.
1340
+ *
1341
+ * **When to use**
1342
+ *
1343
+ * Use to configure a timeout once on the client, for example when providing
1344
+ * the `HttpClient` service, while keeping the standard `HttpClientError` error
1345
+ * model.
1346
+ *
1347
+ * **Details**
1348
+ *
1349
+ * A timed out request is interrupted and fails with an `HttpClientError` whose
1350
+ * reason is a `TransportError` with a `Cause.TimeoutError` cause.
1351
+ * `retryTransient` treats it as transient. Interrupting a request aborts the
1352
+ * underlying transport, unless the request is attached to a scope with
1353
+ * `withScope`, in which case it stays open until the scope closes.
1354
+ *
1355
+ * The timer starts after request preprocessing and covers everything the
1356
+ * wrapped client does to produce a response. For a plain client this ends when
1357
+ * the response headers arrive, but response middleware applied before
1358
+ * `timeout`, such as `tap` or `retryTransient`, runs inside the budget,
1359
+ * including any body reads it performs. Composition order therefore decides
1360
+ * how it interacts with retries: applying `timeout` before `retryTransient`
1361
+ * gives each attempt its own budget, while applying it after bounds the whole
1362
+ * retry loop.
1363
+ *
1364
+ * **Gotchas**
1365
+ *
1366
+ * Body reads outside the timed client are not covered, including those made
1367
+ * by response middleware applied after `timeout` and by consumers of the
1368
+ * `HttpClient` service. Apply a separate timeout to body reads such as
1369
+ * `response.json` or `response.stream` when needed.
1370
+ *
1371
+ * **Example** (Timing out each attempt)
1372
+ *
1373
+ * ```ts
1374
+ * import { Effect, Layer } from "effect"
1375
+ * import { FetchHttpClient, HttpClient } from "effect/http"
1376
+ *
1377
+ * const TimedHttpClient = Layer.effect(
1378
+ * HttpClient.HttpClient,
1379
+ * Effect.map(
1380
+ * HttpClient.HttpClient,
1381
+ * HttpClient.timeout("5 seconds")
1382
+ * )
1383
+ * ).pipe(Layer.provide(FetchHttpClient.layer))
1384
+ *
1385
+ * const program = Effect.gen(function*() {
1386
+ * const client = (yield* HttpClient.HttpClient).pipe(
1387
+ * HttpClient.retryTransient({ times: 3 })
1388
+ * )
1389
+ * return yield* client.get("https://example.com")
1390
+ * }).pipe(Effect.provide(TimedHttpClient))
1391
+ * ```
1392
+ *
1393
+ * @stability unstable
1394
+ * @category error handling
1395
+ * @since 4.1.0
1396
+ */
1397
+ export const timeout: {
1398
+ /**
1399
+ * Fails requests that do not receive a response within the given duration.
1400
+ *
1401
+ * **When to use**
1402
+ *
1403
+ * Use to configure a timeout once on the client, for example when providing
1404
+ * the `HttpClient` service, while keeping the standard `HttpClientError` error
1405
+ * model.
1406
+ *
1407
+ * **Details**
1408
+ *
1409
+ * A timed out request is interrupted and fails with an `HttpClientError` whose
1410
+ * reason is a `TransportError` with a `Cause.TimeoutError` cause.
1411
+ * `retryTransient` treats it as transient. Interrupting a request aborts the
1412
+ * underlying transport, unless the request is attached to a scope with
1413
+ * `withScope`, in which case it stays open until the scope closes.
1414
+ *
1415
+ * The timer starts after request preprocessing and covers everything the
1416
+ * wrapped client does to produce a response. For a plain client this ends when
1417
+ * the response headers arrive, but response middleware applied before
1418
+ * `timeout`, such as `tap` or `retryTransient`, runs inside the budget,
1419
+ * including any body reads it performs. Composition order therefore decides
1420
+ * how it interacts with retries: applying `timeout` before `retryTransient`
1421
+ * gives each attempt its own budget, while applying it after bounds the whole
1422
+ * retry loop.
1423
+ *
1424
+ * **Gotchas**
1425
+ *
1426
+ * Body reads outside the timed client are not covered, including those made
1427
+ * by response middleware applied after `timeout` and by consumers of the
1428
+ * `HttpClient` service. Apply a separate timeout to body reads such as
1429
+ * `response.json` or `response.stream` when needed.
1430
+ *
1431
+ * **Example** (Timing out each attempt)
1432
+ *
1433
+ * ```ts
1434
+ * import { Effect, Layer } from "effect"
1435
+ * import { FetchHttpClient, HttpClient } from "effect/http"
1436
+ *
1437
+ * const TimedHttpClient = Layer.effect(
1438
+ * HttpClient.HttpClient,
1439
+ * Effect.map(
1440
+ * HttpClient.HttpClient,
1441
+ * HttpClient.timeout("5 seconds")
1442
+ * )
1443
+ * ).pipe(Layer.provide(FetchHttpClient.layer))
1444
+ *
1445
+ * const program = Effect.gen(function*() {
1446
+ * const client = (yield* HttpClient.HttpClient).pipe(
1447
+ * HttpClient.retryTransient({ times: 3 })
1448
+ * )
1449
+ * return yield* client.get("https://example.com")
1450
+ * }).pipe(Effect.provide(TimedHttpClient))
1451
+ * ```
1452
+ *
1453
+ * @stability unstable
1454
+ * @category error handling
1455
+ * @since 4.1.0
1456
+ */
1457
+ (duration: Duration.Input): <E, R>(self: HttpClient.With<E, R>) => HttpClient.With<E | Error.HttpClientError, R>
1458
+ /**
1459
+ * Fails requests that do not receive a response within the given duration.
1460
+ *
1461
+ * **When to use**
1462
+ *
1463
+ * Use to configure a timeout once on the client, for example when providing
1464
+ * the `HttpClient` service, while keeping the standard `HttpClientError` error
1465
+ * model.
1466
+ *
1467
+ * **Details**
1468
+ *
1469
+ * A timed out request is interrupted and fails with an `HttpClientError` whose
1470
+ * reason is a `TransportError` with a `Cause.TimeoutError` cause.
1471
+ * `retryTransient` treats it as transient. Interrupting a request aborts the
1472
+ * underlying transport, unless the request is attached to a scope with
1473
+ * `withScope`, in which case it stays open until the scope closes.
1474
+ *
1475
+ * The timer starts after request preprocessing and covers everything the
1476
+ * wrapped client does to produce a response. For a plain client this ends when
1477
+ * the response headers arrive, but response middleware applied before
1478
+ * `timeout`, such as `tap` or `retryTransient`, runs inside the budget,
1479
+ * including any body reads it performs. Composition order therefore decides
1480
+ * how it interacts with retries: applying `timeout` before `retryTransient`
1481
+ * gives each attempt its own budget, while applying it after bounds the whole
1482
+ * retry loop.
1483
+ *
1484
+ * **Gotchas**
1485
+ *
1486
+ * Body reads outside the timed client are not covered, including those made
1487
+ * by response middleware applied after `timeout` and by consumers of the
1488
+ * `HttpClient` service. Apply a separate timeout to body reads such as
1489
+ * `response.json` or `response.stream` when needed.
1490
+ *
1491
+ * **Example** (Timing out each attempt)
1492
+ *
1493
+ * ```ts
1494
+ * import { Effect, Layer } from "effect"
1495
+ * import { FetchHttpClient, HttpClient } from "effect/http"
1496
+ *
1497
+ * const TimedHttpClient = Layer.effect(
1498
+ * HttpClient.HttpClient,
1499
+ * Effect.map(
1500
+ * HttpClient.HttpClient,
1501
+ * HttpClient.timeout("5 seconds")
1502
+ * )
1503
+ * ).pipe(Layer.provide(FetchHttpClient.layer))
1504
+ *
1505
+ * const program = Effect.gen(function*() {
1506
+ * const client = (yield* HttpClient.HttpClient).pipe(
1507
+ * HttpClient.retryTransient({ times: 3 })
1508
+ * )
1509
+ * return yield* client.get("https://example.com")
1510
+ * }).pipe(Effect.provide(TimedHttpClient))
1511
+ * ```
1512
+ *
1513
+ * @stability unstable
1514
+ * @category error handling
1515
+ * @since 4.1.0
1516
+ */
1517
+ <E, R>(self: HttpClient.With<E, R>, duration: Duration.Input): HttpClient.With<E | Error.HttpClientError, R>
1518
+ } = dual(
1519
+ 2,
1520
+ <E, R>(self: HttpClient.With<E, R>, duration: Duration.Input): HttpClient.With<E | Error.HttpClientError, R> => {
1521
+ const decoded = Duration.fromInputUnsafe(duration)
1522
+ const description = `timed out after ${Duration.format(decoded)}`
1523
+ return transform(self, (effect, request) =>
1524
+ Effect.timeoutOrElse(effect, {
1525
+ duration: decoded,
1526
+ orElse: () =>
1527
+ Effect.fail(
1528
+ new Error.HttpClientError({
1529
+ reason: new Error.TransportError({
1530
+ request,
1531
+ cause: new Cause.TimeoutError(`Operation ${description}`),
1532
+ description
1533
+ })
1534
+ })
1535
+ )
1536
+ }))
1537
+ }
1538
+ )
1539
+
1338
1540
  /**
1339
1541
  * Namespace containing configuration types for `withRateLimiter`.
1340
1542
  *
@@ -1680,7 +1882,7 @@ export const withRateLimiter: {
1680
1882
  * Namespace containing configuration types for `withCircuitBreaker`.
1681
1883
  *
1682
1884
  * @stability experimental
1683
- * @since 4.0.6
1885
+ * @since 4.0.7
1684
1886
  */
1685
1887
  export declare namespace WithCircuitBreaker {
1686
1888
  /**
@@ -1688,7 +1890,7 @@ export declare namespace WithCircuitBreaker {
1688
1890
  *
1689
1891
  * @stability experimental
1690
1892
  * @category circuit breaking
1691
- * @since 4.0.6
1893
+ * @since 4.0.7
1692
1894
  */
1693
1895
  export interface Options<E, R2 = never> {
1694
1896
  /**
@@ -1703,13 +1905,10 @@ export declare namespace WithCircuitBreaker {
1703
1905
  readonly key?: string | ((request: HttpClientRequest.HttpClientRequest) => string) | undefined
1704
1906
  /**
1705
1907
  * Classifies the `Exit` of each request that the breaker admitted.
1908
+ * `context.probe` is `true` when the request is the HalfOpen probe.
1706
1909
  * Defaults to `circuitBreakerClassifier`.
1707
1910
  */
1708
- readonly classify?:
1709
- | ((
1710
- exit: Exit.Exit<HttpClientResponse.HttpClientResponse, E>
1711
- ) => CircuitBreaker.Outcome | Effect.Effect<CircuitBreaker.Outcome, never, R2>)
1712
- | undefined
1911
+ readonly classify?: CircuitBreaker.Classifier<HttpClientResponse.HttpClientResponse, E, R2> | undefined
1713
1912
  }
1714
1913
  }
1715
1914
 
@@ -1830,7 +2029,7 @@ export declare namespace WithCircuitBreaker {
1830
2029
  *
1831
2030
  * @stability experimental
1832
2031
  * @category circuit breaking
1833
- * @since 4.0.6
2032
+ * @since 4.0.7
1834
2033
  */
1835
2034
  export const withCircuitBreaker: {
1836
2035
  /**
@@ -1950,7 +2149,7 @@ export const withCircuitBreaker: {
1950
2149
  *
1951
2150
  * @stability experimental
1952
2151
  * @category circuit breaking
1953
- * @since 4.0.6
2152
+ * @since 4.0.7
1954
2153
  */
1955
2154
  <E, R2 = never>(options: WithCircuitBreaker.Options<E, R2>): <R>(
1956
2155
  self: HttpClient.With<E, R>
@@ -2072,7 +2271,7 @@ export const withCircuitBreaker: {
2072
2271
  *
2073
2272
  * @stability experimental
2074
2273
  * @category circuit breaking
2075
- * @since 4.0.6
2274
+ * @since 4.0.7
2076
2275
  */
2077
2276
  <E, R, R2 = never>(self: HttpClient.With<E, R>, options: WithCircuitBreaker.Options<E, R2>): HttpClient.With<E | CircuitBreaker.CircuitBreakerError, R | R2>
2078
2277
  } = dual(2, <E, R, R2>(
@@ -2120,7 +2319,7 @@ const requestOrigin = (request: HttpClientRequest.HttpClientRequest): string =>
2120
2319
  *
2121
2320
  * @stability experimental
2122
2321
  * @category circuit breaking
2123
- * @since 4.0.6
2322
+ * @since 4.0.7
2124
2323
  */
2125
2324
  export const circuitBreakerClassifier = <E>(
2126
2325
  exit: Exit.Exit<HttpClientResponse.HttpClientResponse, E>
@@ -836,32 +836,37 @@ class ClientRequestImpl extends Inspectable.Class implements HttpServerRequest {
836
836
  if (this.bytesEffect) {
837
837
  return this.bytesEffect
838
838
  }
839
+ this.bytesEffect = Effect.withFiber((fiber) => {
840
+ const maxBodySize = fiber.getRef(HttpIncomingMessage.MaxBodySize)
841
+ return this.readBytes(maxBodySize === undefined ? undefined : Number(maxBodySize))
842
+ }).pipe(
843
+ Effect.cached,
844
+ Effect.runSync
845
+ )
846
+ return this.bytesEffect
847
+ }
848
+
849
+ private readBytes(maxBytes: number | undefined): Effect.Effect<Uint8Array, HttpServerError> {
839
850
  const body = this.source.body
840
- let effect: Effect.Effect<Uint8Array, HttpServerError>
841
851
  switch (body._tag) {
842
852
  case "Empty": {
843
- effect = Effect.succeed(new Uint8Array(0))
844
- break
853
+ return Effect.succeed(new Uint8Array(0))
845
854
  }
846
855
  case "Uint8Array": {
847
- effect = Effect.succeed(body.body)
848
- break
856
+ return maxBytes !== undefined && body.body.byteLength > maxBytes
857
+ ? Effect.fail(bodyTooLargeError(this, new BodyTooLargeError(maxBytes)))
858
+ : Effect.succeed(body.body)
849
859
  }
850
860
  case "FormData": {
851
- effect = bytesFromBodyInit(this, body.formData)
852
- break
861
+ return bytesFromWeb(this, () => new Response(body.formData), maxBytes)
853
862
  }
854
863
  case "Stream": {
855
- effect = Stream.mkUint8Array(this.stream)
856
- break
864
+ return Stream.mkUint8Array(maxBytes === undefined ? this.stream : limitStream(this, this.stream, maxBytes))
857
865
  }
858
866
  case "Raw": {
859
- effect = rawBodyBytes(this, body.body)
860
- break
867
+ return rawBodyBytes(this, body.body, maxBytes)
861
868
  }
862
869
  }
863
- this.bytesEffect = Effect.runSync(Effect.cached(effect))
864
- return this.bytesEffect
865
870
  }
866
871
 
867
872
  get text(): Effect.Effect<string, HttpServerError> {
@@ -962,23 +967,38 @@ const rawBodyStream = (request: HttpServerRequest, body: unknown): Stream.Stream
962
967
  return Stream.fail(requestParseError(request, "Unsupported body type"))
963
968
  }
964
969
 
965
- const rawBodyBytes = (request: HttpServerRequest, body: unknown): Effect.Effect<Uint8Array, HttpServerError> => {
970
+ const rawBodyBytes = (
971
+ request: HttpServerRequest,
972
+ body: unknown,
973
+ maxBytes: number | undefined
974
+ ): Effect.Effect<Uint8Array, HttpServerError> => {
966
975
  if (body instanceof Request) {
967
- return Effect.tryPromise({
968
- try: () => body.arrayBuffer().then((buffer) => new Uint8Array(buffer)),
969
- catch: (cause) => requestParseError(request, undefined, cause)
970
- })
976
+ return bytesFromWeb(request, () => body, maxBytes)
971
977
  }
972
978
  if (isBodyInit(body)) {
973
- return bytesFromBodyInit(request, body)
979
+ return bytesFromWeb(request, () => new Response(body), maxBytes)
974
980
  }
975
981
  return Effect.fail(requestParseError(request, "Unsupported body type"))
976
982
  }
977
983
 
978
- const bytesFromBodyInit = (request: HttpServerRequest, body: BodyInit): Effect.Effect<Uint8Array, HttpServerError> =>
984
+ const bytesFromWeb = (
985
+ request: HttpServerRequest,
986
+ // Evaluated inside `try`, as wrapping an unreadable body in a `Response` throws.
987
+ evaluate: () => Request | Response,
988
+ maxBytes: number | undefined
989
+ ): Effect.Effect<Uint8Array, HttpServerError> =>
979
990
  Effect.tryPromise({
980
- try: () => new Response(body).arrayBuffer().then((buffer) => new Uint8Array(buffer)),
981
- catch: (cause) => requestParseError(request, undefined, cause)
991
+ try: async (signal) => {
992
+ const source = evaluate()
993
+ const buffer = maxBytes === undefined
994
+ ? await source.arrayBuffer()
995
+ : await readArrayBufferLimited(source, maxBytes, signal)
996
+ return new Uint8Array(buffer)
997
+ },
998
+ catch: (cause) =>
999
+ cause instanceof BodyTooLargeError
1000
+ ? bodyTooLargeError(request, cause)
1001
+ : requestParseError(request, undefined, cause)
982
1002
  })
983
1003
 
984
1004
  const streamFromReadable = (
@@ -1005,6 +1025,24 @@ const requestParseError = (
1005
1025
  })
1006
1026
  })
1007
1027
 
1028
+ const limitStream = (
1029
+ request: HttpServerRequest,
1030
+ stream: Stream.Stream<Uint8Array, HttpServerError>,
1031
+ maxBytes: number
1032
+ ): Stream.Stream<Uint8Array, HttpServerError> =>
1033
+ Stream.suspend(() => {
1034
+ let bytes = 0
1035
+ return Stream.mapEffect(stream, (chunk) => {
1036
+ bytes += chunk.byteLength
1037
+ return bytes > maxBytes
1038
+ ? Effect.fail(bodyTooLargeError(request, new BodyTooLargeError(maxBytes)))
1039
+ : Effect.succeed(chunk)
1040
+ })
1041
+ })
1042
+
1043
+ const bodyTooLargeError = (request: HttpServerRequest, cause: BodyTooLargeError) =>
1044
+ new HttpServerError({ reason: new RequestParseError({ request, reason: "BodyTooLarge", cause }) })
1045
+
1008
1046
  const formDataToParts = (formData: FormData): Array<Multipart.Part> => {
1009
1047
  const parts: Array<Multipart.Part> = []
1010
1048
  for (const [key, value] of formData.entries()) {
@@ -1102,7 +1140,7 @@ class BodyTooLargeError extends Error {
1102
1140
  }
1103
1141
 
1104
1142
  const readArrayBufferLimited = async (
1105
- source: Request,
1143
+ source: Request | Response,
1106
1144
  maxBytes: number,
1107
1145
  signal: AbortSignal
1108
1146
  ): Promise<ArrayBuffer> => {
@@ -1,5 +1,6 @@
1
1
  /**
2
- * Standard MIME type data copied from mime 4.1.0.
2
+ * Standard MIME type data copied from mime 4.1.0, plus `text/x-python` and
3
+ * `text/x-shellscript` for `py` and `sh` scripts.
3
4
  *
4
5
  * MIT License
5
6
  *
@@ -370,6 +371,8 @@ const types = {
370
371
  "text/vcard": ["vcard"],
371
372
  "text/vtt": ["vtt"],
372
373
  "text/wgsl": ["wgsl"],
374
+ "text/x-python": ["py"],
375
+ "text/x-shellscript": ["sh"],
373
376
  "text/xml": ["*xml"],
374
377
  "text/yaml": ["yaml", "yml"],
375
378
  "video/3gpp": ["3gp", "3gpp"],
@@ -600,7 +600,7 @@ export const StreamSse: {
600
600
  }): StreamSse<Sse.EventCodec, Schema.Top, unknown> => {
601
601
  const events = options.events ?? (options.data === undefined ? undefined : Schema.Struct({
602
602
  ...Sse.EventEncoded.fields,
603
- data: Schema.fromJsonString(options.data)
603
+ data: Schema.fromJsonString(Schema.toCodecJson(options.data))
604
604
  }))
605
605
  if (events === undefined) {
606
606
  throw new Error("StreamSse requires either an events schema or a data schema")
@@ -113,6 +113,51 @@ const ProtoTimeZoneOffset = {
113
113
  }
114
114
  }
115
115
 
116
+ type CacheKey = "partsUtc" | "adjustedEpochMilliseconds" | "partsAdjusted"
117
+
118
+ type Caches = { [K in CacheKey]?: DateTime.Zoned[K] }
119
+
120
+ const cacheSlot: PropertyDescriptor = { value: undefined, enumerable: false, writable: true }
121
+
122
+ // Instances sealed or frozen before their first cache write cannot receive own
123
+ // slots, so their caches live here instead.
124
+ const sealedCaches = new WeakMap<object, Caches>()
125
+
126
+ // Until an instance has its own slots, every cache read and write, including
127
+ // writes through the public fields from other copies of effect, reaches these
128
+ // accessors. The first write defines all of the instance's slots at once and in
129
+ // a fixed order, so construction avoids `Object.defineProperty` and instances
130
+ // keep few shapes.
131
+ const cacheAccessor = <K extends CacheKey>(key: K, slots: ReadonlyArray<CacheKey>): PropertyDescriptor => ({
132
+ get(this: object): Caches[K] {
133
+ return Object.isExtensible(this) ? undefined : sealedCaches.get(this)?.[key]
134
+ },
135
+ set(this: Caches, value: Caches[K]) {
136
+ if (Object.isExtensible(this)) {
137
+ for (const slot of slots) {
138
+ Object.defineProperty(this, slot, cacheSlot)
139
+ }
140
+ this[key] = value
141
+ } else {
142
+ let caches = sealedCaches.get(this)
143
+ if (caches === undefined) {
144
+ caches = {}
145
+ sealedCaches.set(this, caches)
146
+ }
147
+ caches[key] = value
148
+ }
149
+ }
150
+ })
151
+
152
+ const zonedSlots: ReadonlyArray<CacheKey> = ["partsUtc", "adjustedEpochMilliseconds", "partsAdjusted"]
153
+
154
+ Object.defineProperty(ProtoUtc, "partsUtc", cacheAccessor("partsUtc", ["partsUtc"]))
155
+ Object.defineProperties(ProtoZoned, {
156
+ partsUtc: cacheAccessor("partsUtc", zonedSlots),
157
+ adjustedEpochMilliseconds: cacheAccessor("adjustedEpochMilliseconds", zonedSlots),
158
+ partsAdjusted: cacheAccessor("partsAdjusted", zonedSlots)
159
+ })
160
+
116
161
  /** @internal */
117
162
  export const makeZonedProto = (
118
163
  epochMillis: number,
@@ -122,21 +167,9 @@ export const makeZonedProto = (
122
167
  const self = Object.create(ProtoZoned)
123
168
  self.epochMilliseconds = epochMillis
124
169
  self.zone = zone
125
- Object.defineProperty(self, "partsUtc", {
126
- value: partsUtc,
127
- enumerable: false,
128
- writable: true
129
- })
130
- Object.defineProperty(self, "adjustedEpochMillis", {
131
- value: undefined,
132
- enumerable: false,
133
- writable: true
134
- })
135
- Object.defineProperty(self, "partsAdjusted", {
136
- value: undefined,
137
- enumerable: false,
138
- writable: true
139
- })
170
+ if (partsUtc !== undefined) {
171
+ self.partsUtc = partsUtc
172
+ }
140
173
  return self
141
174
  }
142
175
 
@@ -196,11 +229,6 @@ export const clamp: {
196
229
  const makeUtc = (epochMillis: number): DateTime.Utc => {
197
230
  const self = Object.create(ProtoUtc)
198
231
  self.epochMilliseconds = epochMillis
199
- Object.defineProperty(self, "partsUtc", {
200
- value: undefined,
201
- enumerable: false,
202
- writable: true
203
- })
204
232
  return self
205
233
  }
206
234
 
@@ -654,8 +682,9 @@ export const toParts = (self: DateTime.DateTime): DateTime.DateTime.PartsWithWee
654
682
  } else if (self.partsAdjusted !== undefined) {
655
683
  return self.partsAdjusted
656
684
  }
657
- self.partsAdjusted = withDate(self, dateToParts)
658
- return self.partsAdjusted
685
+ const parts = withDate(self, dateToParts)
686
+ self.partsAdjusted = parts
687
+ return parts
659
688
  }
660
689
 
661
690
  /** @internal */
@@ -663,8 +692,9 @@ export const toPartsUtc = (self: DateTime.DateTime): DateTime.DateTime.PartsWith
663
692
  if (self.partsUtc !== undefined) {
664
693
  return self.partsUtc
665
694
  }
666
- self.partsUtc = withDateUtc(self, dateToParts)
667
- return self.partsUtc
695
+ const parts = withDateUtc(self, dateToParts)
696
+ self.partsUtc = parts
697
+ return parts
668
698
  }
669
699
 
670
700
  /** @internal */
@@ -661,6 +661,12 @@ export class FiberImpl<A = any, E = any> implements Fiber.Fiber<A, E> {
661
661
  this._stack.length = 0
662
662
  this._children = undefined
663
663
  this.context = Context.empty()
664
+ // The cache is shared with other fibers, so replace it rather than mutate
665
+ // it, letting the ended span and its parents be collected
666
+ const cache = this.cache
667
+ if (cache.span !== undefined || cache.stackFrame !== undefined) {
668
+ this.cache = { ...cache, span: undefined, stackFrame: undefined }
669
+ }
664
670
  }
665
671
  runLoop(effect: Primitive): Exit.Exit<A, E> | Yield {
666
672
  const prevFiber = (globalThis as any)[currentFiberTypeId]