effect 4.0.2 → 4.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (389) hide show
  1. package/AGENTS.md +24 -0
  2. package/CLAUDE.md +24 -0
  3. package/ai-docs/package.json +2 -2
  4. package/ai-docs/src/52_graphql/10_basics.ts +111 -0
  5. package/ai-docs/src/52_graphql/20_testing.ts +45 -0
  6. package/ai-docs/src/52_graphql/30_batching.ts +116 -0
  7. package/ai-docs/src/52_graphql/40_aliased-batching.ts +122 -0
  8. package/ai-docs/src/52_graphql/50_errors-and-retries.ts +74 -0
  9. package/ai-docs/src/52_graphql/index.md +6 -0
  10. package/dist/Context.d.ts.map +1 -1
  11. package/dist/Context.js +12 -3
  12. package/dist/Context.js.map +1 -1
  13. package/dist/Crypto.d.ts +33 -5
  14. package/dist/Crypto.d.ts.map +1 -1
  15. package/dist/Crypto.js +8 -2
  16. package/dist/Crypto.js.map +1 -1
  17. package/dist/DateTime.d.ts +9 -6
  18. package/dist/DateTime.d.ts.map +1 -1
  19. package/dist/DateTime.js +9 -6
  20. package/dist/DateTime.js.map +1 -1
  21. package/dist/Duration.d.ts +6 -6
  22. package/dist/Duration.d.ts.map +1 -1
  23. package/dist/Duration.js +27 -8
  24. package/dist/Duration.js.map +1 -1
  25. package/dist/FileSystem.d.ts +44 -2
  26. package/dist/FileSystem.d.ts.map +1 -1
  27. package/dist/FileSystem.js.map +1 -1
  28. package/dist/RequestResolver.d.ts.map +1 -1
  29. package/dist/RequestResolver.js +4 -10
  30. package/dist/RequestResolver.js.map +1 -1
  31. package/dist/Scheduler.d.ts +9 -0
  32. package/dist/Scheduler.d.ts.map +1 -1
  33. package/dist/Scheduler.js +9 -0
  34. package/dist/Scheduler.js.map +1 -1
  35. package/dist/Schema.d.ts +481 -1
  36. package/dist/Schema.d.ts.map +1 -1
  37. package/dist/Schema.js +362 -4
  38. package/dist/Schema.js.map +1 -1
  39. package/dist/SchemaGetter.d.ts +4 -0
  40. package/dist/SchemaGetter.d.ts.map +1 -1
  41. package/dist/SchemaGetter.js +52 -33
  42. package/dist/SchemaGetter.js.map +1 -1
  43. package/dist/Sink.d.ts.map +1 -1
  44. package/dist/Sink.js +38 -17
  45. package/dist/Sink.js.map +1 -1
  46. package/dist/Stdio.d.ts +7 -1
  47. package/dist/Stdio.d.ts.map +1 -1
  48. package/dist/Stdio.js +1 -0
  49. package/dist/Stdio.js.map +1 -1
  50. package/dist/Stream.d.ts +22 -11
  51. package/dist/Stream.d.ts.map +1 -1
  52. package/dist/Stream.js +21 -6
  53. package/dist/Stream.js.map +1 -1
  54. package/dist/Utils.js +8 -3
  55. package/dist/Utils.js.map +1 -1
  56. package/dist/ai/AnthropicStructuredOutput.js +0 -2
  57. package/dist/ai/AnthropicStructuredOutput.js.map +1 -1
  58. package/dist/ai/Chat.d.ts +2 -2
  59. package/dist/ai/Chat.d.ts.map +1 -1
  60. package/dist/ai/LanguageModel.d.ts +38 -7
  61. package/dist/ai/LanguageModel.d.ts.map +1 -1
  62. package/dist/ai/LanguageModel.js +25 -7
  63. package/dist/ai/LanguageModel.js.map +1 -1
  64. package/dist/ai/McpServer.d.ts +61 -0
  65. package/dist/ai/McpServer.d.ts.map +1 -1
  66. package/dist/ai/McpServer.js +196 -44
  67. package/dist/ai/McpServer.js.map +1 -1
  68. package/dist/ai/Prompt.d.ts.map +1 -1
  69. package/dist/ai/Prompt.js +28 -5
  70. package/dist/ai/Prompt.js.map +1 -1
  71. package/dist/ai/Response.d.ts +4 -3
  72. package/dist/ai/Response.d.ts.map +1 -1
  73. package/dist/ai/Response.js.map +1 -1
  74. package/dist/ai/internal/mcpProtocol/v2026_07_28.js +5 -0
  75. package/dist/ai/internal/mcpProtocol/v2026_07_28.js.map +1 -1
  76. package/dist/ai/internal/mcpProtocol.js.map +1 -1
  77. package/dist/ai/internal/mcpRuntime.js +1 -0
  78. package/dist/ai/internal/mcpRuntime.js.map +1 -1
  79. package/dist/cli/CliOutput.d.ts +27 -0
  80. package/dist/cli/CliOutput.d.ts.map +1 -1
  81. package/dist/cli/CliOutput.js +33 -10
  82. package/dist/cli/CliOutput.js.map +1 -1
  83. package/dist/cli/Command.d.ts.map +1 -1
  84. package/dist/cli/Command.js +6 -3
  85. package/dist/cli/Command.js.map +1 -1
  86. package/dist/cli/Completions.d.ts +3 -3
  87. package/dist/cli/Completions.d.ts.map +1 -1
  88. package/dist/cli/Completions.js +8 -5
  89. package/dist/cli/Completions.js.map +1 -1
  90. package/dist/cli/GlobalFlag.d.ts +5 -4
  91. package/dist/cli/GlobalFlag.d.ts.map +1 -1
  92. package/dist/cli/GlobalFlag.js +3 -3
  93. package/dist/cli/GlobalFlag.js.map +1 -1
  94. package/dist/cli/Prompt.d.ts +17 -1
  95. package/dist/cli/Prompt.d.ts.map +1 -1
  96. package/dist/cli/Prompt.js +119 -114
  97. package/dist/cli/Prompt.js.map +1 -1
  98. package/dist/cli/internal/ansi.d.ts +0 -1
  99. package/dist/cli/internal/ansi.d.ts.map +1 -1
  100. package/dist/cli/internal/ansi.js +20 -3
  101. package/dist/cli/internal/ansi.js.map +1 -1
  102. package/dist/cli/internal/completions/powershell.d.ts +2 -0
  103. package/dist/cli/internal/completions/powershell.d.ts.map +1 -0
  104. package/dist/cli/internal/completions/powershell.js +273 -0
  105. package/dist/cli/internal/completions/powershell.js.map +1 -0
  106. package/dist/cli/internal/completions/zsh.js +3 -2
  107. package/dist/cli/internal/completions/zsh.js.map +1 -1
  108. package/dist/cli/internal/wizard.d.ts +3 -3
  109. package/dist/cli/internal/wizard.d.ts.map +1 -1
  110. package/dist/cli/internal/wizard.js +21 -18
  111. package/dist/cli/internal/wizard.js.map +1 -1
  112. package/dist/cluster/ClusterSchema.d.ts +28 -0
  113. package/dist/cluster/ClusterSchema.d.ts.map +1 -1
  114. package/dist/cluster/ClusterSchema.js +30 -0
  115. package/dist/cluster/ClusterSchema.js.map +1 -1
  116. package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
  117. package/dist/cluster/ClusterWorkflowEngine.js +56 -26
  118. package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
  119. package/dist/cluster/MessageStorage.d.ts +18 -3
  120. package/dist/cluster/MessageStorage.d.ts.map +1 -1
  121. package/dist/cluster/MessageStorage.js +31 -11
  122. package/dist/cluster/MessageStorage.js.map +1 -1
  123. package/dist/cluster/Runners.d.ts.map +1 -1
  124. package/dist/cluster/Runners.js +8 -2
  125. package/dist/cluster/Runners.js.map +1 -1
  126. package/dist/cluster/Sharding.d.ts.map +1 -1
  127. package/dist/cluster/Sharding.js +187 -66
  128. package/dist/cluster/Sharding.js.map +1 -1
  129. package/dist/cluster/SqlMessageStorage.d.ts +59 -19
  130. package/dist/cluster/SqlMessageStorage.d.ts.map +1 -1
  131. package/dist/cluster/SqlMessageStorage.js +84 -55
  132. package/dist/cluster/SqlMessageStorage.js.map +1 -1
  133. package/dist/cluster/SqlRunnerStorage.d.ts +68 -19
  134. package/dist/cluster/SqlRunnerStorage.d.ts.map +1 -1
  135. package/dist/cluster/SqlRunnerStorage.js +191 -113
  136. package/dist/cluster/SqlRunnerStorage.js.map +1 -1
  137. package/dist/cluster/internal/entityManager.js +104 -37
  138. package/dist/cluster/internal/entityManager.js.map +1 -1
  139. package/dist/encoding/Sse.d.ts +6 -0
  140. package/dist/encoding/Sse.d.ts.map +1 -1
  141. package/dist/encoding/Sse.js +62 -70
  142. package/dist/encoding/Sse.js.map +1 -1
  143. package/dist/graphql/GraphQL.d.ts +349 -0
  144. package/dist/graphql/GraphQL.d.ts.map +1 -0
  145. package/dist/graphql/GraphQL.js +207 -0
  146. package/dist/graphql/GraphQL.js.map +1 -0
  147. package/dist/graphql/GraphQLClient.d.ts +562 -0
  148. package/dist/graphql/GraphQLClient.d.ts.map +1 -0
  149. package/dist/graphql/GraphQLClient.js +498 -0
  150. package/dist/graphql/GraphQLClient.js.map +1 -0
  151. package/dist/graphql/GraphQLClientError.d.ts +445 -0
  152. package/dist/graphql/GraphQLClientError.d.ts.map +1 -0
  153. package/dist/graphql/GraphQLClientError.js +479 -0
  154. package/dist/graphql/GraphQLClientError.js.map +1 -0
  155. package/dist/graphql/GraphQLGroup.d.ts +118 -0
  156. package/dist/graphql/GraphQLGroup.d.ts.map +1 -0
  157. package/dist/graphql/GraphQLGroup.js +109 -0
  158. package/dist/graphql/GraphQLGroup.js.map +1 -0
  159. package/dist/graphql/GraphQLMiddleware.d.ts +249 -0
  160. package/dist/graphql/GraphQLMiddleware.d.ts.map +1 -0
  161. package/dist/graphql/GraphQLMiddleware.js +130 -0
  162. package/dist/graphql/GraphQLMiddleware.js.map +1 -0
  163. package/dist/graphql/GraphQLProtocol.d.ts +731 -0
  164. package/dist/graphql/GraphQLProtocol.d.ts.map +1 -0
  165. package/dist/graphql/GraphQLProtocol.js +719 -0
  166. package/dist/graphql/GraphQLProtocol.js.map +1 -0
  167. package/dist/graphql/GraphQLResolver.d.ts +453 -0
  168. package/dist/graphql/GraphQLResolver.d.ts.map +1 -0
  169. package/dist/graphql/GraphQLResolver.js +552 -0
  170. package/dist/graphql/GraphQLResolver.js.map +1 -0
  171. package/dist/graphql/index.d.ts +40 -0
  172. package/dist/graphql/index.d.ts.map +1 -0
  173. package/dist/graphql/index.js +41 -0
  174. package/dist/graphql/index.js.map +1 -0
  175. package/dist/http/FindMyWay/internal/router.js +3 -6
  176. package/dist/http/FindMyWay/internal/router.js.map +1 -1
  177. package/dist/http/HttpClient.d.ts +21 -0
  178. package/dist/http/HttpClient.d.ts.map +1 -1
  179. package/dist/http/HttpClient.js +63 -12
  180. package/dist/http/HttpClient.js.map +1 -1
  181. package/dist/http/HttpEffect.d.ts.map +1 -1
  182. package/dist/http/HttpEffect.js +14 -7
  183. package/dist/http/HttpEffect.js.map +1 -1
  184. package/dist/http/HttpMiddleware.d.ts.map +1 -1
  185. package/dist/http/HttpMiddleware.js +31 -32
  186. package/dist/http/HttpMiddleware.js.map +1 -1
  187. package/dist/http/HttpRouter.d.ts +35 -0
  188. package/dist/http/HttpRouter.d.ts.map +1 -1
  189. package/dist/http/HttpRouter.js +35 -0
  190. package/dist/http/HttpRouter.js.map +1 -1
  191. package/dist/http/HttpServerResponse.d.ts +8 -6
  192. package/dist/http/HttpServerResponse.d.ts.map +1 -1
  193. package/dist/http/HttpServerResponse.js +27 -16
  194. package/dist/http/HttpServerResponse.js.map +1 -1
  195. package/dist/http/HttpTraceContext.d.ts.map +1 -1
  196. package/dist/http/HttpTraceContext.js +4 -2
  197. package/dist/http/HttpTraceContext.js.map +1 -1
  198. package/dist/http/Multipart.d.ts.map +1 -1
  199. package/dist/http/Multipart.js +15 -1
  200. package/dist/http/Multipart.js.map +1 -1
  201. package/dist/http-api/HttpApiScalar.d.ts +5 -0
  202. package/dist/http-api/HttpApiScalar.d.ts.map +1 -1
  203. package/dist/http-api/HttpApiScalar.js.map +1 -1
  204. package/dist/internal/dateTime.js +40 -35
  205. package/dist/internal/dateTime.js.map +1 -1
  206. package/dist/internal/effect.js +19 -9
  207. package/dist/internal/effect.js.map +1 -1
  208. package/dist/internal/graphql.d.ts +2 -0
  209. package/dist/internal/graphql.d.ts.map +1 -0
  210. package/dist/internal/graphql.js +195 -0
  211. package/dist/internal/graphql.js.map +1 -0
  212. package/dist/internal/graphqlHeaders.d.ts +4 -0
  213. package/dist/internal/graphqlHeaders.d.ts.map +1 -0
  214. package/dist/internal/graphqlHeaders.js +11 -0
  215. package/dist/internal/graphqlHeaders.js.map +1 -0
  216. package/dist/internal/request.js +20 -1
  217. package/dist/internal/request.js.map +1 -1
  218. package/dist/internal/schema/toCodeDocument.js +4 -1
  219. package/dist/internal/schema/toCodeDocument.js.map +1 -1
  220. package/dist/internal/schema/toJsonSchemaDocument.js +29 -5
  221. package/dist/internal/schema/toJsonSchemaDocument.js.map +1 -1
  222. package/dist/internal/version.js +1 -1
  223. package/dist/net/AddressResolver.d.ts +145 -0
  224. package/dist/net/AddressResolver.d.ts.map +1 -0
  225. package/dist/net/AddressResolver.js +114 -0
  226. package/dist/net/AddressResolver.js.map +1 -0
  227. package/dist/net/Dns.d.ts +596 -0
  228. package/dist/net/Dns.d.ts.map +1 -0
  229. package/dist/net/Dns.js +549 -0
  230. package/dist/net/Dns.js.map +1 -0
  231. package/dist/net/Host.d.ts +369 -0
  232. package/dist/net/Host.d.ts.map +1 -0
  233. package/dist/net/Host.js +397 -0
  234. package/dist/net/Host.js.map +1 -0
  235. package/dist/net/IpInterface.d.ts +76 -3
  236. package/dist/net/IpInterface.d.ts.map +1 -1
  237. package/dist/net/IpInterface.js +53 -4
  238. package/dist/net/IpInterface.js.map +1 -1
  239. package/dist/net/IpNetwork.d.ts +82 -8
  240. package/dist/net/IpNetwork.d.ts.map +1 -1
  241. package/dist/net/IpNetwork.js +60 -4
  242. package/dist/net/IpNetwork.js.map +1 -1
  243. package/dist/net/NetAddress.d.ts +396 -35
  244. package/dist/net/NetAddress.d.ts.map +1 -1
  245. package/dist/net/NetAddress.js +358 -34
  246. package/dist/net/NetAddress.js.map +1 -1
  247. package/dist/net/index.d.ts +15 -0
  248. package/dist/net/index.d.ts.map +1 -1
  249. package/dist/net/index.js +15 -0
  250. package/dist/net/index.js.map +1 -1
  251. package/dist/observability/OtlpMetrics.d.ts.map +1 -1
  252. package/dist/observability/OtlpMetrics.js +15 -21
  253. package/dist/observability/OtlpMetrics.js.map +1 -1
  254. package/dist/observability/PrometheusMetrics.js +1 -0
  255. package/dist/observability/PrometheusMetrics.js.map +1 -1
  256. package/dist/persistence/PersistedQueue.d.ts +32 -3
  257. package/dist/persistence/PersistedQueue.d.ts.map +1 -1
  258. package/dist/persistence/PersistedQueue.js +75 -16
  259. package/dist/persistence/PersistedQueue.js.map +1 -1
  260. package/dist/rpc/RpcClient.d.ts +22 -6
  261. package/dist/rpc/RpcClient.d.ts.map +1 -1
  262. package/dist/rpc/RpcClient.js +12 -5
  263. package/dist/rpc/RpcClient.js.map +1 -1
  264. package/dist/rpc/RpcServer.d.ts +6 -0
  265. package/dist/rpc/RpcServer.d.ts.map +1 -1
  266. package/dist/rpc/RpcServer.js +78 -29
  267. package/dist/rpc/RpcServer.js.map +1 -1
  268. package/dist/socket/DatagramSocket.d.ts +456 -0
  269. package/dist/socket/DatagramSocket.d.ts.map +1 -0
  270. package/dist/socket/DatagramSocket.js +535 -0
  271. package/dist/socket/DatagramSocket.js.map +1 -0
  272. package/dist/socket/Socket.d.ts +20 -1
  273. package/dist/socket/Socket.d.ts.map +1 -1
  274. package/dist/socket/Socket.js +9 -1
  275. package/dist/socket/Socket.js.map +1 -1
  276. package/dist/socket/index.d.ts +5 -0
  277. package/dist/socket/index.d.ts.map +1 -1
  278. package/dist/socket/index.js +5 -0
  279. package/dist/socket/index.js.map +1 -1
  280. package/dist/sql/Migrator.d.ts.map +1 -1
  281. package/dist/sql/Migrator.js +7 -2
  282. package/dist/sql/Migrator.js.map +1 -1
  283. package/dist/sql/SqlClient.d.ts +7 -1
  284. package/dist/sql/SqlClient.d.ts.map +1 -1
  285. package/dist/sql/SqlClient.js +31 -6
  286. package/dist/sql/SqlClient.js.map +1 -1
  287. package/dist/testing/TestCrypto.d.ts +73 -0
  288. package/dist/testing/TestCrypto.d.ts.map +1 -0
  289. package/dist/testing/TestCrypto.js +87 -0
  290. package/dist/testing/TestCrypto.js.map +1 -0
  291. package/dist/testing/index.d.ts +5 -0
  292. package/dist/testing/index.d.ts.map +1 -1
  293. package/dist/testing/index.js +5 -0
  294. package/dist/testing/index.js.map +1 -1
  295. package/dist/workflow/DurableDeferred.d.ts +54 -0
  296. package/dist/workflow/DurableDeferred.d.ts.map +1 -1
  297. package/dist/workflow/DurableDeferred.js +108 -50
  298. package/dist/workflow/DurableDeferred.js.map +1 -1
  299. package/dist/workflow/WorkflowEngine.d.ts +24 -2
  300. package/dist/workflow/WorkflowEngine.d.ts.map +1 -1
  301. package/dist/workflow/WorkflowEngine.js +13 -3
  302. package/dist/workflow/WorkflowEngine.js.map +1 -1
  303. package/package.json +6 -3
  304. package/src/Context.ts +12 -3
  305. package/src/Crypto.ts +43 -9
  306. package/src/DateTime.ts +9 -6
  307. package/src/Duration.ts +36 -16
  308. package/src/FileSystem.ts +48 -2
  309. package/src/RequestResolver.ts +4 -10
  310. package/src/Scheduler.ts +9 -0
  311. package/src/Schema.ts +677 -5
  312. package/src/SchemaGetter.ts +47 -35
  313. package/src/Sink.ts +45 -18
  314. package/src/Stdio.ts +9 -2
  315. package/src/Stream.ts +44 -15
  316. package/src/Utils.ts +8 -5
  317. package/src/ai/AnthropicStructuredOutput.ts +2 -2
  318. package/src/ai/Chat.ts +2 -2
  319. package/src/ai/LanguageModel.ts +96 -24
  320. package/src/ai/McpServer.ts +288 -94
  321. package/src/ai/Prompt.ts +24 -10
  322. package/src/ai/Response.ts +6 -3
  323. package/src/ai/internal/mcpProtocol/v2026_07_28.ts +5 -0
  324. package/src/ai/internal/mcpProtocol.ts +3 -0
  325. package/src/ai/internal/mcpRuntime.ts +2 -0
  326. package/src/cli/CliOutput.ts +33 -16
  327. package/src/cli/Command.ts +4 -3
  328. package/src/cli/Completions.ts +9 -6
  329. package/src/cli/GlobalFlag.ts +19 -11
  330. package/src/cli/Prompt.ts +159 -149
  331. package/src/cli/internal/ansi.ts +26 -3
  332. package/src/cli/internal/completions/powershell.ts +322 -0
  333. package/src/cli/internal/completions/zsh.ts +4 -2
  334. package/src/cli/internal/wizard.ts +34 -26
  335. package/src/cluster/ClusterSchema.ts +32 -0
  336. package/src/cluster/ClusterWorkflowEngine.ts +64 -36
  337. package/src/cluster/MessageStorage.ts +45 -14
  338. package/src/cluster/Runners.ts +8 -2
  339. package/src/cluster/Sharding.ts +219 -58
  340. package/src/cluster/SqlMessageStorage.ts +118 -84
  341. package/src/cluster/SqlRunnerStorage.ts +224 -128
  342. package/src/cluster/internal/entityManager.ts +151 -55
  343. package/src/encoding/Sse.ts +69 -79
  344. package/src/graphql/GraphQL.ts +494 -0
  345. package/src/graphql/GraphQLClient.ts +912 -0
  346. package/src/graphql/GraphQLClientError.ts +542 -0
  347. package/src/graphql/GraphQLGroup.ts +167 -0
  348. package/src/graphql/GraphQLMiddleware.ts +253 -0
  349. package/src/graphql/GraphQLProtocol.ts +1286 -0
  350. package/src/graphql/GraphQLResolver.ts +1010 -0
  351. package/src/graphql/index.ts +48 -0
  352. package/src/http/FindMyWay/internal/router.ts +4 -7
  353. package/src/http/HttpClient.ts +110 -12
  354. package/src/http/HttpEffect.ts +11 -5
  355. package/src/http/HttpMiddleware.ts +33 -34
  356. package/src/http/HttpRouter.ts +35 -0
  357. package/src/http/HttpServerResponse.ts +28 -16
  358. package/src/http/HttpTraceContext.ts +8 -2
  359. package/src/http/Multipart.ts +17 -1
  360. package/src/http-api/HttpApiScalar.ts +5 -0
  361. package/src/internal/dateTime.ts +13 -10
  362. package/src/internal/effect.ts +22 -15
  363. package/src/internal/graphql.ts +263 -0
  364. package/src/internal/graphqlHeaders.ts +11 -0
  365. package/src/internal/request.ts +31 -3
  366. package/src/internal/schema/toCodeDocument.ts +7 -1
  367. package/src/internal/schema/toJsonSchemaDocument.ts +34 -2
  368. package/src/internal/version.ts +1 -1
  369. package/src/net/AddressResolver.ts +222 -0
  370. package/src/net/Dns.ts +1035 -0
  371. package/src/net/Host.ts +544 -0
  372. package/src/net/IpInterface.ts +117 -7
  373. package/src/net/IpNetwork.ts +116 -17
  374. package/src/net/NetAddress.ts +620 -76
  375. package/src/net/index.ts +18 -0
  376. package/src/observability/OtlpMetrics.ts +12 -23
  377. package/src/observability/PrometheusMetrics.ts +1 -0
  378. package/src/persistence/PersistedQueue.ts +146 -53
  379. package/src/rpc/RpcClient.ts +41 -19
  380. package/src/rpc/RpcServer.ts +115 -40
  381. package/src/socket/DatagramSocket.ts +919 -0
  382. package/src/socket/Socket.ts +28 -2
  383. package/src/socket/index.ts +6 -0
  384. package/src/sql/Migrator.ts +21 -5
  385. package/src/sql/SqlClient.ts +39 -15
  386. package/src/testing/TestCrypto.ts +94 -0
  387. package/src/testing/index.ts +6 -0
  388. package/src/workflow/DurableDeferred.ts +160 -47
  389. package/src/workflow/WorkflowEngine.ts +50 -5
@@ -934,10 +934,6 @@ export const subtractDuration: {
934
934
  mapEpochMillis(self, (millis) => millis - Duration.toMillis(Duration.fromInputUnsafe(duration)))
935
935
  )
936
936
 
937
- const addMillis = (date: Date, amount: number): void => {
938
- date.setTime(date.getTime() + amount)
939
- }
940
-
941
937
  /** @internal */
942
938
  export const add: {
943
939
  (
@@ -949,20 +945,26 @@ export const add: {
949
945
  ): A
950
946
  } = dual(
951
947
  2,
952
- (self: DateTime.DateTime, parts: Partial<DateTime.DateTime.PartsForMath>): DateTime.DateTime =>
953
- mutate(self, (date) => {
948
+ (self: DateTime.DateTime, parts: Partial<DateTime.DateTime.PartsForMath>): DateTime.DateTime => {
949
+ // time units move the instant, calendar units move the wall clock
950
+ const shifted = mutateUtc(self, (date) => {
954
951
  if (parts.milliseconds) {
955
- addMillis(date, parts.milliseconds)
952
+ date.setTime(date.getTime() + parts.milliseconds)
956
953
  }
957
954
  if (parts.seconds) {
958
- addMillis(date, parts.seconds * 1000)
955
+ date.setTime(date.getTime() + parts.seconds * 1000)
959
956
  }
960
957
  if (parts.minutes) {
961
- addMillis(date, parts.minutes * 60 * 1000)
958
+ date.setTime(date.getTime() + parts.minutes * 60 * 1000)
962
959
  }
963
960
  if (parts.hours) {
964
- addMillis(date, parts.hours * 60 * 60 * 1000)
961
+ date.setTime(date.getTime() + parts.hours * 60 * 60 * 1000)
965
962
  }
963
+ })
964
+ if (!parts.days && !parts.weeks && !parts.months && !parts.years) {
965
+ return shifted
966
+ }
967
+ return mutate(shifted, (date) => {
966
968
  if (parts.days) {
967
969
  date.setUTCDate(date.getUTCDate() + parts.days)
968
970
  }
@@ -989,6 +991,7 @@ export const add: {
989
991
  }
990
992
  }
991
993
  })
994
+ }
992
995
  )
993
996
 
994
997
  /** @internal */
@@ -1507,13 +1507,19 @@ const succeedPayload = function(this: { readonly payload: any }, _value: unknown
1507
1507
  // V8 includes the property name of a stored continuation in its stack trace.
1508
1508
  // Other engines need an explicit frame for the stack cleaner to cut at.
1509
1509
  const continuationMarksStack = (() => {
1510
+ const limit = getStackTraceLimit()
1511
+ if (limit === 0) return false
1510
1512
  const marker = "~effect/Effect/stackProbe"
1511
1513
  const probe = {
1512
1514
  [marker]: function stackProbe() {
1513
- return new Error().stack
1515
+ return new Error()
1514
1516
  }
1515
1517
  }
1516
- return probe[marker]()?.includes("[as " + marker + "]") === true
1518
+ // Only the probe frame is needed to detect the continuation property name.
1519
+ setStackTraceLimit(1)
1520
+ const error = probe[marker]()
1521
+ setStackTraceLimit(limit)
1522
+ return error.stack?.includes("[as " + marker + "]") === true
1517
1523
  })()
1518
1524
  const mapCont = function(this: { readonly payload: any }, value: any, fiber: FiberImpl) {
1519
1525
  const f = this.payload
@@ -4453,7 +4459,7 @@ export const cachedInvalidateWithTTL: {
4453
4459
  const infiniteTTL = constant(Infinity)
4454
4460
 
4455
4461
  interface CachedRun<A, E> {
4456
- fiber: FiberImpl<A, E> | undefined
4462
+ readonly fiber: FiberImpl<A, E>
4457
4463
  awaiters: number
4458
4464
  }
4459
4465
 
@@ -4470,17 +4476,19 @@ const makeCachedUnsafe = <A, E, R>(
4470
4476
  onExitUnsafe(fiber, () => {
4471
4477
  // Abandon the run once every caller has left, unless it already finished.
4472
4478
  if (--run.awaiters > 0 || current !== run) return
4473
- // Detach it first so new callers start a fresh run instead of joining
4474
- // one that is being interrupted.
4479
+ // Detach before interruption so new callers start a fresh run.
4475
4480
  current = undefined
4476
- return fiberInterrupt(run.fiber!)
4481
+ return fiberInterrupt(run.fiber)
4477
4482
  })
4478
- return fiberJoin(run.fiber!)
4483
+ return fiberJoin(run.fiber)
4479
4484
  }
4480
4485
 
4481
4486
  return [
4482
4487
  withFiber((fiber) => {
4483
- if (current !== undefined) return join(fiber, current)
4488
+ if (current !== undefined) {
4489
+ // A run joining itself is not an awaiter, so external callers can still abandon it.
4490
+ return fiber === current.fiber ? fiberJoin(current.fiber) : join(fiber, current)
4491
+ }
4484
4492
  if (
4485
4493
  exit !== undefined &&
4486
4494
  (expiresAt === Infinity || fiber.getRef(ClockRef).currentTimeMillisUnsafe() < expiresAt)
@@ -4489,10 +4497,11 @@ const makeCachedUnsafe = <A, E, R>(
4489
4497
  }
4490
4498
  exit = undefined
4491
4499
  const clock = fiber.getRef(ClockRef)
4492
- const run: CachedRun<A, E> = { fiber: undefined, awaiters: 0 }
4500
+ const run: CachedRun<A, E> = { fiber: new FiberImpl(fiber.context), awaiters: 0 }
4493
4501
  current = run
4494
- run.fiber = forkUnsafe(
4495
- fiber,
4502
+ // Join before evaluating, which may synchronously re-enter and interrupt other awaiters.
4503
+ const joined = join(fiber, run)
4504
+ run.fiber.evaluate(
4496
4505
  onExitPrimitive(self, (exit_) => {
4497
4506
  // An abandoned run must not overwrite or clear a replacement run.
4498
4507
  if (current !== run) return
@@ -4502,11 +4511,9 @@ const makeCachedUnsafe = <A, E, R>(
4502
4511
  const duration = ttlMillis(exit_)
4503
4512
  expiresAt = duration === Infinity ? Infinity : clock.currentTimeMillisUnsafe() + duration
4504
4513
  exit = exit_
4505
- }),
4506
- true,
4507
- true
4514
+ }) as any
4508
4515
  )
4509
- return run.fiber._exit ?? join(fiber, run)
4516
+ return run.fiber._exit ?? joined
4510
4517
  }),
4511
4518
  sync(() => {
4512
4519
  exit = undefined
@@ -0,0 +1,263 @@
1
+ import { isReadonlyArrayNonEmpty, type NonEmptyReadonlyArray } from "../Array.ts"
2
+ import * as Context from "../Context.ts"
3
+ import * as Effect from "../Effect.ts"
4
+ import type * as GraphQL from "../graphql/GraphQL.ts"
5
+ import type { DocumentTemplate } from "../graphql/GraphQL.ts"
6
+ import type { PartialResult } from "../graphql/GraphQLClient.ts"
7
+ import {
8
+ DecodeError,
9
+ EncodeError,
10
+ GraphQLClientError,
11
+ type GraphQLError,
12
+ type Reason,
13
+ ResponseError
14
+ } from "../graphql/GraphQLClientError.ts"
15
+ import type { ExecutionResult, GraphQLRequest } from "../graphql/GraphQLProtocol.ts"
16
+ import * as Schema from "../Schema.ts"
17
+
18
+ /**
19
+ * Builds a response error with raw data and transport metadata.
20
+ *
21
+ * @internal
22
+ */
23
+ export const responseError = (
24
+ result: ExecutionResult | undefined,
25
+ errors: NonEmptyReadonlyArray<GraphQLError>
26
+ ): ResponseError =>
27
+ new ResponseError({
28
+ errors,
29
+ ...(result?.data === undefined ? {} : { data: result.data as Schema.Json }),
30
+ ...(result?.extensions === undefined ? {} : { extensions: result.extensions }),
31
+ ...(result?.status === undefined ? {} : { status: result.status }),
32
+ ...(result?.headers === undefined ? {} : { headers: result.headers })
33
+ })
34
+
35
+ /**
36
+ * Raw responses for partial results, used by resolvers to preserve error
37
+ * metadata. Mock client results have no entry.
38
+ *
39
+ * @internal
40
+ */
41
+ export const partialResponses = new WeakMap<object, ExecutionResult>()
42
+
43
+ /**
44
+ * Joins two printed pieces, adding a space only where two non-punctuators
45
+ * would otherwise touch. This is the generator printer's rule, so joining a
46
+ * generated template reproduces the printed document exactly.
47
+ */
48
+ const concat = (left: string, right: string): string =>
49
+ /[\w"-]$/.test(left) && /^[\w"-]/.test(right) ? `${left} ${right}` : left + right
50
+
51
+ const concatAll = (pieces: ReadonlyArray<string>): string => pieces.reduce(concat, "")
52
+
53
+ /** Renders template parts, prefixing every name (the odd entries). */
54
+ const renderParts = (parts: DocumentTemplate.Parts, prefix: string): string =>
55
+ parts.map((part, i) => i % 2 === 1 ? prefix + part : part).join("")
56
+
57
+ const isShared = (fragment: DocumentTemplate.Fragment): boolean => fragment.body.length <= 1
58
+
59
+ /**
60
+ * Renders the template once per prefix. The empty prefix renders it as
61
+ * written; any other prefix renames variables and per-slice fragments and
62
+ * aliases root fields to the prefixed response key.
63
+ */
64
+ const render = (
65
+ kind: string,
66
+ name: string,
67
+ template: DocumentTemplate,
68
+ prefixes: ReadonlyArray<string>
69
+ ): string =>
70
+ concatAll([
71
+ kind,
72
+ name,
73
+ template.variables.length === 0 ? "" : `(${
74
+ concatAll(
75
+ prefixes.flatMap((prefix) =>
76
+ template.variables.map((variable) => `$${prefix}${variable.name}:${variable.body}`)
77
+ )
78
+ )
79
+ })`,
80
+ template.directives === undefined ? "" : renderParts(template.directives, ""),
81
+ `{${
82
+ concatAll(prefixes.flatMap((prefix) =>
83
+ template.selections.map((selection) => {
84
+ const key = prefix === "" ? selection.alias : `${prefix}${selection.alias ?? selection.name}`
85
+ return `${key === undefined ? "" : `${key}:`}${selection.name ?? ""}${renderParts(selection.body, prefix)}`
86
+ })
87
+ ))
88
+ }}`,
89
+ ...template.fragments.flatMap((fragment) =>
90
+ (isShared(fragment) ? [""] : prefixes).map((prefix) =>
91
+ concatAll(["fragment", prefix + fragment.name, renderParts(fragment.body, prefix)])
92
+ )
93
+ )
94
+ ])
95
+
96
+ /**
97
+ * Joins a template into the document it was split from.
98
+ *
99
+ * @internal
100
+ */
101
+ export const joinTemplate = (kind: string, name: string, template: DocumentTemplate): string =>
102
+ render(kind, name, template, [""])
103
+
104
+ /**
105
+ * Why the template can't be sliced for any prefixes, if it can't: an operation
106
+ * directive references a variable, or a root selection is a fragment spread or
107
+ * inline fragment.
108
+ *
109
+ * @internal
110
+ */
111
+ export const templateUnsliceableReason = (template: DocumentTemplate): string | undefined => {
112
+ if (template.directives !== undefined && template.directives.length > 1) {
113
+ return "its operation directives reference variables"
114
+ }
115
+ if (template.selections.some((selection) => selection.name === undefined)) {
116
+ return "it has a fragment spread or inline fragment at the root"
117
+ }
118
+ return undefined
119
+ }
120
+
121
+ /**
122
+ * Renders one operation that repeats the template once per prefix. Each
123
+ * slice's variables, root response keys and per-slice fragments are renamed
124
+ * with its prefix; operation directives and shared fragments appear once.
125
+ * Prefixes must start a GraphQL name, and none may be a prefix of another.
126
+ *
127
+ * Throws rather than producing an invalid document when the template is
128
+ * unsliceable (see {@link templateUnsliceableReason}) or a renamed fragment
129
+ * would take a shared fragment's name.
130
+ *
131
+ * @internal
132
+ */
133
+ export const renderSlices = (
134
+ kind: string,
135
+ name: string,
136
+ template: DocumentTemplate,
137
+ prefixes: NonEmptyReadonlyArray<string>
138
+ ): string => {
139
+ const shared = new Set(template.fragments.filter(isShared).map((fragment) => fragment.name))
140
+ const collision = template.fragments
141
+ .flatMap((fragment) => isShared(fragment) ? [] : prefixes.map((prefix) => prefix + fragment.name))
142
+ .find((renamed) => shared.has(renamed))
143
+ const reason = templateUnsliceableReason(template) ??
144
+ (collision === undefined ? undefined : `fragment ${collision} would collide with a shared fragment`)
145
+ if (reason !== undefined) throw new Error(`Cannot render slices of operation ${name}: ${reason}`)
146
+ return render(kind, name, template, prefixes)
147
+ }
148
+
149
+ /**
150
+ * Forces POST for alias batches to avoid GET URL length limits.
151
+ *
152
+ * @internal
153
+ */
154
+ export const ForcePost = Context.Reference<boolean>("effect/graphql/ForcePost", { defaultValue: () => false })
155
+
156
+ /**
157
+ * JSON with object keys sorted, so equal JSON values give equal strings.
158
+ *
159
+ * @internal
160
+ */
161
+ export const canonicalJson = (value: unknown): string =>
162
+ JSON.stringify(value, (_, value) =>
163
+ value !== null && typeof value === "object" && !Array.isArray(value)
164
+ ? Object.fromEntries(Object.keys(value).sort().map((key) => [key, value[key]]))
165
+ : value)
166
+
167
+ /**
168
+ * Shared variable encoding, result decoding and client error mapping.
169
+ *
170
+ * @internal
171
+ */
172
+ export const makeCodec = <Op extends GraphQL.Any>(operation: Op) => {
173
+ const fail = (reason: Reason) => new GraphQLClientError({ operation: operation.name, reason })
174
+ const schemaFail = (make: (description: string) => Reason) => (error: Schema.SchemaError) =>
175
+ Effect.fail(fail(make(error.message)))
176
+ const encode = Schema.encodeEffect(operation.variables)
177
+ const decode = Schema.decodeUnknownEffect(operation.result)
178
+
179
+ const encodeVariables = (
180
+ variables: GraphQL.Variables<Op> | undefined
181
+ ): Effect.Effect<unknown, GraphQLClientError, Op["variables"]["EncodingServices"]> =>
182
+ Effect.catch(encode(variables ?? {}), schemaFail((description) => new EncodeError({ description })))
183
+
184
+ const decodeData = (
185
+ data: unknown
186
+ ): Effect.Effect<GraphQL.Result<Op>, GraphQLClientError, Op["result"]["DecodingServices"]> =>
187
+ Effect.catch(decode(data), schemaFail((description) => new DecodeError({ description })))
188
+
189
+ // GraphQL requires errors when data is null or missing. Check before decoding,
190
+ // since schemas such as Schema.Json accept null.
191
+ const failResponse = (result: ExecutionResult): Effect.Effect<never, GraphQLClientError> => {
192
+ const errors = result.errors ?? []
193
+ return Effect.fail(fail(
194
+ isReadonlyArrayNonEmpty(errors)
195
+ ? responseError(result, errors)
196
+ : new DecodeError({ description: "data is null or missing without errors" })
197
+ ))
198
+ }
199
+
200
+ const decodeStrict = (
201
+ result: ExecutionResult
202
+ ): Effect.Effect<GraphQL.Result<Op>, GraphQLClientError, Op["result"]["DecodingServices"]> =>
203
+ isReadonlyArrayNonEmpty(result.errors ?? []) || result.data === null || result.data === undefined
204
+ ? failResponse(result)
205
+ : decodeData(result.data)
206
+
207
+ const decodePartial = (
208
+ result: ExecutionResult
209
+ ): Effect.Effect<PartialResult<GraphQL.Result<Op>>, GraphQLClientError, Op["result"]["DecodingServices"]> => {
210
+ if (result.data === null || result.data === undefined) return failResponse(result)
211
+ return Effect.map(decodeData(result.data), (data): PartialResult<GraphQL.Result<Op>> => {
212
+ const partial = { data, errors: result.errors ?? [] }
213
+ partialResponses.set(partial, result)
214
+ return partial
215
+ })
216
+ }
217
+
218
+ return { fail, schemaFail, encodeVariables, failResponse, decodeStrict, decodePartial } as const
219
+ }
220
+
221
+ /**
222
+ * Each real client method's runner for batches: its middleware and protocol,
223
+ * sending as POST. Mock and custom methods have none.
224
+ *
225
+ * @internal
226
+ */
227
+ export const rawExecutors = new WeakMap<
228
+ object,
229
+ (request: GraphQLRequest) => Effect.Effect<ExecutionResult, unknown, unknown>
230
+ >()
231
+
232
+ /**
233
+ * Splits a batched response, removing prefixes from root keys and error paths.
234
+ * Returns undefined if an error matches no slice or data is null or missing.
235
+ *
236
+ * @internal
237
+ */
238
+ export const splitSlices = (
239
+ result: ExecutionResult,
240
+ template: DocumentTemplate,
241
+ prefixes: ReadonlyArray<string>
242
+ ): ReadonlyArray<ExecutionResult> | undefined => {
243
+ const sliceErrors = prefixes.map((): Array<GraphQLError> => [])
244
+ for (const error of result.errors ?? []) {
245
+ const key = error.path?.[0]
246
+ // No prefix is a prefix of another, so at most one matches.
247
+ const index = typeof key === "string" ? prefixes.findIndex((prefix) => key.startsWith(prefix)) : -1
248
+ if (index === -1) return undefined
249
+ sliceErrors[index].push(
250
+ { ...error, path: [(key as string).slice(prefixes[index].length), ...error.path!.slice(1)] } as GraphQLError
251
+ )
252
+ }
253
+ if (result.data === null || result.data === undefined) return undefined
254
+ const data = result.data as Record<string, unknown>
255
+ return prefixes.map((prefix, i) => {
256
+ const sliceData: Record<string, unknown> = {}
257
+ for (const selection of template.selections) {
258
+ const key = (selection.alias ?? selection.name)!
259
+ if (Object.hasOwn(data, prefix + key)) sliceData[key] = data[prefix + key]
260
+ }
261
+ return { ...result, data: sliceData, errors: sliceErrors[i] }
262
+ })
263
+ }
@@ -0,0 +1,11 @@
1
+ import * as Headers from "../http/Headers.ts"
2
+ import * as Schema from "../Schema.ts"
3
+ import * as SchemaGetter from "../SchemaGetter.ts"
4
+
5
+ // Keep headers branded at runtime while encoding only their string entries.
6
+ export const HeadersSchema = Schema.Record(Schema.String, Schema.String).pipe(
7
+ Schema.decodeTo(Schema.declare<Headers.Headers>(Headers.isHeaders), {
8
+ decode: SchemaGetter.transform(Headers.fromInput),
9
+ encode: SchemaGetter.transform((headers) => ({ ...headers }))
10
+ })
11
+ )
@@ -4,6 +4,8 @@ import type { Effect } from "../Effect.ts"
4
4
  import type { Exit } from "../Exit.ts"
5
5
  import type { Fiber } from "../Fiber.ts"
6
6
  import { dual } from "../Function.ts"
7
+ import * as MutableHashMap from "../MutableHashMap.ts"
8
+ import * as Option from "../Option.ts"
7
9
  import type * as Request from "../Request.ts"
8
10
  import { makeEntry } from "../Request.ts"
9
11
  import type { RequestResolver } from "../RequestResolver.ts"
@@ -67,10 +69,36 @@ export const requestUnsafe = <A extends Request.Any>(
67
69
  return () => removeEntryUnsafe(options.resolver, entry)
68
70
  }
69
71
 
72
+ /**
73
+ * Pending batches of resolvers whose `batchKey` is in this set match keys with
74
+ * `Equal` instead of by reference.
75
+ *
76
+ * @internal
77
+ */
78
+ export const equalBatchKeys = new WeakSet<Function>()
79
+
80
+ interface BatchMap {
81
+ get(key: unknown): Batch | undefined
82
+ has(key: unknown): boolean
83
+ set(key: unknown, batch: Batch): void
84
+ delete(key: unknown): void
85
+ }
86
+
87
+ const makeBatchMap = (resolver: RequestResolver<any>): BatchMap => {
88
+ if (!equalBatchKeys.has(resolver.batchKey)) return new Map()
89
+ const map = MutableHashMap.empty<unknown, Batch>()
90
+ return {
91
+ get: (key) => Option.getOrUndefined(MutableHashMap.get(map, key)),
92
+ has: (key) => MutableHashMap.has(map, key),
93
+ set: (key, batch) => MutableHashMap.set(map, key, batch),
94
+ delete: (key) => MutableHashMap.remove(map, key)
95
+ }
96
+ }
97
+
70
98
  interface Batch {
71
99
  key: unknown
72
100
  resolver: RequestResolver<any>
73
- map: Map<unknown, Batch>
101
+ map: BatchMap
74
102
  readonly entrySet: Set<Request.Entry<any>>
75
103
  readonly entries: Set<Request.Entry<any>>
76
104
  readonly delayEffect: Effect<void>
@@ -79,7 +107,7 @@ interface Batch {
79
107
  }
80
108
 
81
109
  const batchPool: Array<Batch> = []
82
- const pendingBatches = new WeakMap<RequestResolver<any>, Map<unknown, Batch>>()
110
+ const pendingBatches = new WeakMap<RequestResolver<any>, BatchMap>()
83
111
 
84
112
  const addEntry = <A extends Request.Any>(
85
113
  resolver: RequestResolver<A>,
@@ -93,7 +121,7 @@ const addEntry = <A extends Request.Any>(
93
121
  ) => {
94
122
  let batchMap = pendingBatches.get(resolver)
95
123
  if (!batchMap) {
96
- batchMap = new Map<object, Batch>()
124
+ batchMap = makeBatchMap(resolver)
97
125
  pendingBatches.set(resolver, batchMap)
98
126
  }
99
127
  let batch: Batch | undefined
@@ -48,6 +48,8 @@ function renderEmittableAnnotation(input: unknown): string | undefined {
48
48
  return entries.length === 0 ? "{}" : `{ ${entries.join(", ")} }`
49
49
  }
50
50
 
51
+ const canonicalFiniteCheck = `Schema.isFinite().annotate({ "expected": "a finite number" })`
52
+
51
53
  function renderAnnotations(
52
54
  annotations: Schema.Annotations.Annotations | undefined
53
55
  ): string | undefined {
@@ -341,7 +343,11 @@ export function toCodeDocument(
341
343
  let runtime = base.runtime + runtimeAnnotate(representation.annotations)
342
344
  for (let index = 0; index < representation.checks.length; index++) {
343
345
  const check = representation.checks[index]
344
- runtime += `.check(${compileCheck(check, [...path, "checks", index])})`
346
+ const compiledCheck = compileCheck(check, [...path, "checks", index])
347
+ // Only collapse a bare number's leading canonical check.
348
+ runtime = runtime === "Schema.Number" && compiledCheck === canonicalFiniteCheck
349
+ ? "Schema.Finite"
350
+ : `${runtime}.check(${compiledCheck})`
345
351
  }
346
352
  return makeCode(runtime, base.Type)
347
353
  }
@@ -121,6 +121,37 @@ function hasNoCollisions(left: JsonSchema.JsonSchema, rightKeys: ReadonlyArray<s
121
121
  return typeof left.$ref !== "string" && rightKeys.every((key) => !Object.hasOwn(left, key))
122
122
  }
123
123
 
124
+ // Every bound on one schema object applies, so a repeated bound reduces to its tighter value.
125
+ const lowerBoundKeywords = "|minimum|exclusiveMinimum|minLength|minItems|minProperties|"
126
+ const upperBoundKeywords = "|maximum|exclusiveMaximum|maxLength|maxItems|maxProperties|"
127
+
128
+ // Tightens repeated bounds and drops an inclusive or exclusive bound implied by the other on the same side. Returns
129
+ // `undefined` for a `$ref` schema or a non-bound collision, so the caller falls back to `allOf`.
130
+ function mergeInlineCheck(
131
+ left: JsonSchema.JsonSchema,
132
+ right: JsonSchema.JsonSchema,
133
+ rightKeys: ReadonlyArray<string>
134
+ ): JsonSchema.JsonSchema | undefined {
135
+ if (typeof left.$ref === "string") return undefined
136
+ const out: JsonSchema.JsonSchema = { ...left, ...right }
137
+ for (const key of rightKeys) {
138
+ if (!Object.hasOwn(left, key)) continue
139
+ const a = left[key]
140
+ const b = right[key]
141
+ if (typeof a !== "number" || typeof b !== "number") return undefined
142
+ if (lowerBoundKeywords.includes(`|${key}|`)) out[key] = Math.max(a, b)
143
+ else if (upperBoundKeywords.includes(`|${key}|`)) out[key] = Math.min(a, b)
144
+ else return undefined
145
+ }
146
+ if (typeof out.minimum === "number" && typeof out.exclusiveMinimum === "number") {
147
+ delete out[out.exclusiveMinimum >= out.minimum ? "minimum" : "exclusiveMinimum"]
148
+ }
149
+ if (typeof out.maximum === "number" && typeof out.exclusiveMaximum === "number") {
150
+ delete out[out.exclusiveMaximum <= out.maximum ? "maximum" : "exclusiveMaximum"]
151
+ }
152
+ return out
153
+ }
154
+
124
155
  // `format` and `content*` can affect validation, so they are not treated as pure annotations.
125
156
  const promotableAnnotationKeywords = "|title|description|default|examples|readOnly|writeOnly|"
126
157
  const inlineableAnnotatedCheckKeywords = inlineableCheckKeywords + promotableAnnotationKeywords
@@ -149,8 +180,9 @@ function appendJsonSchema(
149
180
  : appendJsonSchema(base, extracted.schema, inlineCheck)
150
181
  }
151
182
  }
152
- if (inlineCheck && hasNoCollisions(left, rightKeys)) {
153
- return { ...left, ...right }
183
+ if (inlineCheck) {
184
+ const merged = mergeInlineCheck(left, right, rightKeys)
185
+ if (merged !== undefined) return merged
154
186
  }
155
187
  const members = Array.isArray(right.allOf) && rightKeys.length === 1 ? right.allOf : [right]
156
188
  if (Array.isArray(left.allOf)) {
@@ -1,2 +1,2 @@
1
1
  /** @internal */
2
- export const version = "4.0.2"
2
+ export const version = "4.0.4"