effect 4.0.3 → 4.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (449) hide show
  1. package/AGENTS.md +24 -0
  2. package/CLAUDE.md +24 -0
  3. package/ai-docs/package.json +2 -2
  4. package/ai-docs/src/52_graphql/10_basics.ts +117 -0
  5. package/ai-docs/src/52_graphql/20_testing.ts +45 -0
  6. package/ai-docs/src/52_graphql/30_batching.ts +118 -0
  7. package/ai-docs/src/52_graphql/40_aliased-batching.ts +124 -0
  8. package/ai-docs/src/52_graphql/50_errors-and-retries.ts +74 -0
  9. package/ai-docs/src/52_graphql/index.md +6 -0
  10. package/dist/Array.d.ts +90 -6
  11. package/dist/Array.d.ts.map +1 -1
  12. package/dist/Array.js +4 -2
  13. package/dist/Array.js.map +1 -1
  14. package/dist/Channel.d.ts +6 -1
  15. package/dist/Channel.d.ts.map +1 -1
  16. package/dist/Channel.js +17 -3
  17. package/dist/Channel.js.map +1 -1
  18. package/dist/ConfigProvider.d.ts.map +1 -1
  19. package/dist/ConfigProvider.js +33 -32
  20. package/dist/ConfigProvider.js.map +1 -1
  21. package/dist/Context.d.ts.map +1 -1
  22. package/dist/Context.js +9 -0
  23. package/dist/Context.js.map +1 -1
  24. package/dist/Duration.d.ts.map +1 -1
  25. package/dist/Duration.js +2 -5
  26. package/dist/Duration.js.map +1 -1
  27. package/dist/Effect.d.ts +61 -19
  28. package/dist/Effect.d.ts.map +1 -1
  29. package/dist/Effect.js +58 -39
  30. package/dist/Effect.js.map +1 -1
  31. package/dist/FileSystem.d.ts +23 -9
  32. package/dist/FileSystem.d.ts.map +1 -1
  33. package/dist/FileSystem.js.map +1 -1
  34. package/dist/Match.d.ts +20 -6
  35. package/dist/Match.d.ts.map +1 -1
  36. package/dist/Match.js +2 -2
  37. package/dist/Match.js.map +1 -1
  38. package/dist/Path.d.ts +37 -5
  39. package/dist/Path.d.ts.map +1 -1
  40. package/dist/Path.js +36 -5
  41. package/dist/Path.js.map +1 -1
  42. package/dist/RequestResolver.d.ts.map +1 -1
  43. package/dist/RequestResolver.js +4 -10
  44. package/dist/RequestResolver.js.map +1 -1
  45. package/dist/Scheduler.d.ts +9 -0
  46. package/dist/Scheduler.d.ts.map +1 -1
  47. package/dist/Scheduler.js +9 -0
  48. package/dist/Scheduler.js.map +1 -1
  49. package/dist/Schema.d.ts +15 -2
  50. package/dist/Schema.d.ts.map +1 -1
  51. package/dist/Schema.js +16 -2
  52. package/dist/Schema.js.map +1 -1
  53. package/dist/SchemaGetter.d.ts +4 -0
  54. package/dist/SchemaGetter.d.ts.map +1 -1
  55. package/dist/SchemaGetter.js +52 -33
  56. package/dist/SchemaGetter.js.map +1 -1
  57. package/dist/Sink.d.ts.map +1 -1
  58. package/dist/Sink.js +38 -17
  59. package/dist/Sink.js.map +1 -1
  60. package/dist/Stream.d.ts +11 -0
  61. package/dist/Stream.d.ts.map +1 -1
  62. package/dist/Stream.js +16 -1
  63. package/dist/Stream.js.map +1 -1
  64. package/dist/String.d.ts +12 -0
  65. package/dist/String.d.ts.map +1 -1
  66. package/dist/String.js +17 -4
  67. package/dist/String.js.map +1 -1
  68. package/dist/TxRef.d.ts.map +1 -1
  69. package/dist/TxRef.js +3 -2
  70. package/dist/TxRef.js.map +1 -1
  71. package/dist/Utils.js +8 -3
  72. package/dist/Utils.js.map +1 -1
  73. package/dist/ai/AiError.d.ts +10 -10
  74. package/dist/ai/AiError.d.ts.map +1 -1
  75. package/dist/ai/AiError.js +1 -1
  76. package/dist/ai/AiError.js.map +1 -1
  77. package/dist/ai/AnthropicStructuredOutput.js +0 -2
  78. package/dist/ai/AnthropicStructuredOutput.js.map +1 -1
  79. package/dist/ai/Chat.d.ts +2 -2
  80. package/dist/ai/Chat.d.ts.map +1 -1
  81. package/dist/ai/Decision.d.ts +70 -19
  82. package/dist/ai/Decision.d.ts.map +1 -1
  83. package/dist/ai/Decision.js +37 -3
  84. package/dist/ai/Decision.js.map +1 -1
  85. package/dist/ai/DecisionModel.js +1 -1
  86. package/dist/ai/DecisionModel.js.map +1 -1
  87. package/dist/ai/LanguageModel.d.ts +38 -7
  88. package/dist/ai/LanguageModel.d.ts.map +1 -1
  89. package/dist/ai/LanguageModel.js +70 -40
  90. package/dist/ai/LanguageModel.js.map +1 -1
  91. package/dist/ai/McpServer.d.ts +61 -52
  92. package/dist/ai/McpServer.d.ts.map +1 -1
  93. package/dist/ai/McpServer.js +134 -50
  94. package/dist/ai/McpServer.js.map +1 -1
  95. package/dist/ai/Prompt.d.ts.map +1 -1
  96. package/dist/ai/Prompt.js +28 -5
  97. package/dist/ai/Prompt.js.map +1 -1
  98. package/dist/ai/Response.d.ts +5 -4
  99. package/dist/ai/Response.d.ts.map +1 -1
  100. package/dist/ai/Response.js.map +1 -1
  101. package/dist/cli/Completions.d.ts +5 -0
  102. package/dist/cli/Completions.d.ts.map +1 -1
  103. package/dist/cli/Completions.js.map +1 -1
  104. package/dist/cli/Flag.d.ts +100 -0
  105. package/dist/cli/Flag.d.ts.map +1 -1
  106. package/dist/cli/Flag.js +33 -0
  107. package/dist/cli/Flag.js.map +1 -1
  108. package/dist/cli/Param.d.ts +87 -0
  109. package/dist/cli/Param.d.ts.map +1 -1
  110. package/dist/cli/Param.js +30 -0
  111. package/dist/cli/Param.js.map +1 -1
  112. package/dist/cli/internal/command.d.ts.map +1 -1
  113. package/dist/cli/internal/command.js +2 -1
  114. package/dist/cli/internal/command.js.map +1 -1
  115. package/dist/cli/internal/completions/bash.js +4 -3
  116. package/dist/cli/internal/completions/bash.js.map +1 -1
  117. package/dist/cli/internal/completions/descriptor.js +8 -1
  118. package/dist/cli/internal/completions/descriptor.js.map +1 -1
  119. package/dist/cli/internal/completions/fish.js +4 -4
  120. package/dist/cli/internal/completions/fish.js.map +1 -1
  121. package/dist/cli/internal/completions/powershell.js +3 -2
  122. package/dist/cli/internal/completions/powershell.js.map +1 -1
  123. package/dist/cli/internal/completions/zsh.js +7 -3
  124. package/dist/cli/internal/completions/zsh.js.map +1 -1
  125. package/dist/cli/internal/parser.js +11 -3
  126. package/dist/cli/internal/parser.js.map +1 -1
  127. package/dist/cli/internal/wizard.d.ts.map +1 -1
  128. package/dist/cli/internal/wizard.js +2 -1
  129. package/dist/cli/internal/wizard.js.map +1 -1
  130. package/dist/cluster/ClusterWorkflowEngine.d.ts +1 -0
  131. package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
  132. package/dist/cluster/ClusterWorkflowEngine.js +113 -21
  133. package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
  134. package/dist/cluster/MessageStorage.d.ts.map +1 -1
  135. package/dist/cluster/MessageStorage.js +20 -12
  136. package/dist/cluster/MessageStorage.js.map +1 -1
  137. package/dist/cluster/Runners.d.ts.map +1 -1
  138. package/dist/cluster/Runners.js +54 -34
  139. package/dist/cluster/Runners.js.map +1 -1
  140. package/dist/cluster/Sharding.d.ts.map +1 -1
  141. package/dist/cluster/Sharding.js +6 -4
  142. package/dist/cluster/Sharding.js.map +1 -1
  143. package/dist/cluster/internal/entityManager.js +1 -1
  144. package/dist/cluster/internal/entityManager.js.map +1 -1
  145. package/dist/encoding/Sse.d.ts +6 -0
  146. package/dist/encoding/Sse.d.ts.map +1 -1
  147. package/dist/encoding/Sse.js +63 -71
  148. package/dist/encoding/Sse.js.map +1 -1
  149. package/dist/graphql/GraphQL.d.ts +349 -0
  150. package/dist/graphql/GraphQL.d.ts.map +1 -0
  151. package/dist/graphql/GraphQL.js +207 -0
  152. package/dist/graphql/GraphQL.js.map +1 -0
  153. package/dist/graphql/GraphQLClient.d.ts +562 -0
  154. package/dist/graphql/GraphQLClient.d.ts.map +1 -0
  155. package/dist/graphql/GraphQLClient.js +505 -0
  156. package/dist/graphql/GraphQLClient.js.map +1 -0
  157. package/dist/graphql/GraphQLClientError.d.ts +445 -0
  158. package/dist/graphql/GraphQLClientError.d.ts.map +1 -0
  159. package/dist/graphql/GraphQLClientError.js +479 -0
  160. package/dist/graphql/GraphQLClientError.js.map +1 -0
  161. package/dist/graphql/GraphQLGroup.d.ts +118 -0
  162. package/dist/graphql/GraphQLGroup.d.ts.map +1 -0
  163. package/dist/graphql/GraphQLGroup.js +109 -0
  164. package/dist/graphql/GraphQLGroup.js.map +1 -0
  165. package/dist/graphql/GraphQLMiddleware.d.ts +249 -0
  166. package/dist/graphql/GraphQLMiddleware.d.ts.map +1 -0
  167. package/dist/graphql/GraphQLMiddleware.js +130 -0
  168. package/dist/graphql/GraphQLMiddleware.js.map +1 -0
  169. package/dist/graphql/GraphQLProtocol.d.ts +969 -0
  170. package/dist/graphql/GraphQLProtocol.d.ts.map +1 -0
  171. package/dist/graphql/GraphQLProtocol.js +809 -0
  172. package/dist/graphql/GraphQLProtocol.js.map +1 -0
  173. package/dist/graphql/GraphQLResolver.d.ts +453 -0
  174. package/dist/graphql/GraphQLResolver.d.ts.map +1 -0
  175. package/dist/graphql/GraphQLResolver.js +582 -0
  176. package/dist/graphql/GraphQLResolver.js.map +1 -0
  177. package/dist/graphql/index.d.ts +40 -0
  178. package/dist/graphql/index.d.ts.map +1 -0
  179. package/dist/graphql/index.js +41 -0
  180. package/dist/graphql/index.js.map +1 -0
  181. package/dist/http/FetchHttpClient.d.ts +6 -3
  182. package/dist/http/FetchHttpClient.d.ts.map +1 -1
  183. package/dist/http/FetchHttpClient.js +6 -3
  184. package/dist/http/FetchHttpClient.js.map +1 -1
  185. package/dist/http/FindMyWay/internal/router.js +2 -1
  186. package/dist/http/FindMyWay/internal/router.js.map +1 -1
  187. package/dist/http/Headers.d.ts +3 -3
  188. package/dist/http/Headers.d.ts.map +1 -1
  189. package/dist/http/Headers.js +6 -5
  190. package/dist/http/Headers.js.map +1 -1
  191. package/dist/http/HttpClient.d.ts +27 -0
  192. package/dist/http/HttpClient.d.ts.map +1 -1
  193. package/dist/http/HttpClient.js +38 -11
  194. package/dist/http/HttpClient.js.map +1 -1
  195. package/dist/http/HttpClientError.d.ts.map +1 -1
  196. package/dist/http/HttpClientError.js +8 -6
  197. package/dist/http/HttpClientError.js.map +1 -1
  198. package/dist/http/HttpClientRequest.d.ts +147 -4
  199. package/dist/http/HttpClientRequest.d.ts.map +1 -1
  200. package/dist/http/HttpClientRequest.js +47 -1
  201. package/dist/http/HttpClientRequest.js.map +1 -1
  202. package/dist/http/HttpEffect.d.ts.map +1 -1
  203. package/dist/http/HttpEffect.js +14 -7
  204. package/dist/http/HttpEffect.js.map +1 -1
  205. package/dist/http/HttpMiddleware.d.ts +60 -0
  206. package/dist/http/HttpMiddleware.d.ts.map +1 -1
  207. package/dist/http/HttpMiddleware.js +93 -32
  208. package/dist/http/HttpMiddleware.js.map +1 -1
  209. package/dist/http/HttpRouter.d.ts +35 -0
  210. package/dist/http/HttpRouter.d.ts.map +1 -1
  211. package/dist/http/HttpRouter.js +87 -13
  212. package/dist/http/HttpRouter.js.map +1 -1
  213. package/dist/http/HttpServerError.d.ts.map +1 -1
  214. package/dist/http/HttpServerError.js +6 -4
  215. package/dist/http/HttpServerError.js.map +1 -1
  216. package/dist/http/HttpServerRequest.js +2 -2
  217. package/dist/http/HttpServerRequest.js.map +1 -1
  218. package/dist/http/HttpServerResponse.d.ts +8 -6
  219. package/dist/http/HttpServerResponse.d.ts.map +1 -1
  220. package/dist/http/HttpServerResponse.js +27 -16
  221. package/dist/http/HttpServerResponse.js.map +1 -1
  222. package/dist/http/HttpStaticServer.d.ts.map +1 -1
  223. package/dist/http/HttpStaticServer.js +4 -10
  224. package/dist/http/HttpStaticServer.js.map +1 -1
  225. package/dist/http/HttpTraceContext.js +1 -1
  226. package/dist/http/HttpTraceContext.js.map +1 -1
  227. package/dist/http/Multipart.d.ts.map +1 -1
  228. package/dist/http/Multipart.js +15 -1
  229. package/dist/http/Multipart.js.map +1 -1
  230. package/dist/http/Url.d.ts.map +1 -1
  231. package/dist/http/Url.js +2 -1
  232. package/dist/http/Url.js.map +1 -1
  233. package/dist/http/UrlParams.d.ts +112 -8
  234. package/dist/http/UrlParams.d.ts.map +1 -1
  235. package/dist/http/UrlParams.js +141 -14
  236. package/dist/http/UrlParams.js.map +1 -1
  237. package/dist/http/internal/compression.d.ts +1 -1
  238. package/dist/http/internal/compression.d.ts.map +1 -1
  239. package/dist/http/internal/compression.js +2 -10
  240. package/dist/http/internal/compression.js.map +1 -1
  241. package/dist/http/internal/compressionBody.d.ts +2 -0
  242. package/dist/http/internal/compressionBody.d.ts.map +1 -0
  243. package/dist/http/internal/compressionBody.js +36 -0
  244. package/dist/http/internal/compressionBody.js.map +1 -0
  245. package/dist/http/internal/decompression.d.ts +2 -0
  246. package/dist/http/internal/decompression.d.ts.map +1 -0
  247. package/dist/http/internal/decompression.js +162 -0
  248. package/dist/http/internal/decompression.js.map +1 -0
  249. package/dist/http/internal/tracing.js +14 -4
  250. package/dist/http/internal/tracing.js.map +1 -1
  251. package/dist/http/internal/urlParams.d.ts +2 -0
  252. package/dist/http/internal/urlParams.d.ts.map +1 -0
  253. package/dist/http/internal/urlParams.js +4 -0
  254. package/dist/http/internal/urlParams.js.map +1 -0
  255. package/dist/http-api/HttpApiClient.d.ts.map +1 -1
  256. package/dist/http-api/HttpApiClient.js +2 -1
  257. package/dist/http-api/HttpApiClient.js.map +1 -1
  258. package/dist/http-api/HttpApiScalar.d.ts +5 -0
  259. package/dist/http-api/HttpApiScalar.d.ts.map +1 -1
  260. package/dist/http-api/HttpApiScalar.js.map +1 -1
  261. package/dist/internal/core.js +17 -1
  262. package/dist/internal/core.js.map +1 -1
  263. package/dist/internal/dateTime.js +40 -35
  264. package/dist/internal/dateTime.js.map +1 -1
  265. package/dist/internal/effect.js +13 -6
  266. package/dist/internal/effect.js.map +1 -1
  267. package/dist/internal/graphql.d.ts +2 -0
  268. package/dist/internal/graphql.d.ts.map +1 -0
  269. package/dist/internal/graphql.js +205 -0
  270. package/dist/internal/graphql.js.map +1 -0
  271. package/dist/internal/graphqlHeaders.d.ts +4 -0
  272. package/dist/internal/graphqlHeaders.d.ts.map +1 -0
  273. package/dist/internal/graphqlHeaders.js +11 -0
  274. package/dist/internal/graphqlHeaders.js.map +1 -0
  275. package/dist/internal/request.js +20 -1
  276. package/dist/internal/request.js.map +1 -1
  277. package/dist/internal/schema/toCodeDocument.js +4 -1
  278. package/dist/internal/schema/toCodeDocument.js.map +1 -1
  279. package/dist/internal/schema/toJsonSchemaDocument.js +29 -5
  280. package/dist/internal/schema/toJsonSchemaDocument.js.map +1 -1
  281. package/dist/internal/version.js +1 -1
  282. package/dist/net/Host.d.ts +49 -0
  283. package/dist/net/Host.d.ts.map +1 -1
  284. package/dist/net/Host.js +55 -0
  285. package/dist/net/Host.js.map +1 -1
  286. package/dist/net/NetAddress.d.ts +8 -0
  287. package/dist/net/NetAddress.d.ts.map +1 -1
  288. package/dist/net/NetAddress.js +8 -0
  289. package/dist/net/NetAddress.js.map +1 -1
  290. package/dist/observability/Otlp.d.ts +15 -0
  291. package/dist/observability/Otlp.d.ts.map +1 -1
  292. package/dist/observability/Otlp.js +3 -0
  293. package/dist/observability/Otlp.js.map +1 -1
  294. package/dist/observability/OtlpExporter.d.ts +8 -0
  295. package/dist/observability/OtlpExporter.d.ts.map +1 -1
  296. package/dist/observability/OtlpExporter.js +10 -1
  297. package/dist/observability/OtlpExporter.js.map +1 -1
  298. package/dist/observability/OtlpLogger.d.ts +17 -0
  299. package/dist/observability/OtlpLogger.d.ts.map +1 -1
  300. package/dist/observability/OtlpLogger.js +14 -1
  301. package/dist/observability/OtlpLogger.js.map +1 -1
  302. package/dist/observability/OtlpMetrics.d.ts +17 -0
  303. package/dist/observability/OtlpMetrics.d.ts.map +1 -1
  304. package/dist/observability/OtlpMetrics.js +13 -0
  305. package/dist/observability/OtlpMetrics.js.map +1 -1
  306. package/dist/observability/OtlpTracer.d.ts +17 -0
  307. package/dist/observability/OtlpTracer.d.ts.map +1 -1
  308. package/dist/observability/OtlpTracer.js +15 -2
  309. package/dist/observability/OtlpTracer.js.map +1 -1
  310. package/dist/reactivity/AsyncResult.d.ts +6 -0
  311. package/dist/reactivity/AsyncResult.d.ts.map +1 -1
  312. package/dist/reactivity/AsyncResult.js +27 -0
  313. package/dist/reactivity/AsyncResult.js.map +1 -1
  314. package/dist/reactivity/AtomRegistry.js +3 -1
  315. package/dist/reactivity/AtomRegistry.js.map +1 -1
  316. package/dist/rpc/RpcClient.d.ts.map +1 -1
  317. package/dist/rpc/RpcClient.js +6 -1
  318. package/dist/rpc/RpcClient.js.map +1 -1
  319. package/dist/rpc/RpcServer.d.ts.map +1 -1
  320. package/dist/rpc/RpcServer.js +36 -9
  321. package/dist/rpc/RpcServer.js.map +1 -1
  322. package/dist/socket/Socket.d.ts +6 -0
  323. package/dist/socket/Socket.d.ts.map +1 -1
  324. package/dist/socket/Socket.js.map +1 -1
  325. package/dist/sql/SqlClient.d.ts +8 -7
  326. package/dist/sql/SqlClient.d.ts.map +1 -1
  327. package/dist/sql/SqlClient.js +8 -7
  328. package/dist/sql/SqlClient.js.map +1 -1
  329. package/dist/testing/TestClock.d.ts +16 -3
  330. package/dist/testing/TestClock.d.ts.map +1 -1
  331. package/dist/testing/TestClock.js +112 -22
  332. package/dist/testing/TestClock.js.map +1 -1
  333. package/dist/workflow/Activity.js +1 -0
  334. package/dist/workflow/Activity.js.map +1 -1
  335. package/dist/workflow/DurableDeferred.d.ts.map +1 -1
  336. package/dist/workflow/DurableDeferred.js +32 -3
  337. package/dist/workflow/DurableDeferred.js.map +1 -1
  338. package/dist/workflow/Workflow.d.ts +22 -0
  339. package/dist/workflow/Workflow.d.ts.map +1 -1
  340. package/dist/workflow/Workflow.js +15 -3
  341. package/dist/workflow/Workflow.js.map +1 -1
  342. package/dist/workflow/WorkflowEngine.d.ts +44 -3
  343. package/dist/workflow/WorkflowEngine.d.ts.map +1 -1
  344. package/dist/workflow/WorkflowEngine.js +45 -22
  345. package/dist/workflow/WorkflowEngine.js.map +1 -1
  346. package/package.json +6 -3
  347. package/src/Array.ts +95 -6
  348. package/src/Channel.ts +24 -3
  349. package/src/ConfigProvider.ts +40 -44
  350. package/src/Context.ts +9 -0
  351. package/src/Duration.ts +4 -5
  352. package/src/Effect.ts +140 -53
  353. package/src/FileSystem.ts +23 -9
  354. package/src/Match.ts +65 -12
  355. package/src/Path.ts +52 -7
  356. package/src/RequestResolver.ts +4 -10
  357. package/src/Scheduler.ts +9 -0
  358. package/src/Schema.ts +25 -4
  359. package/src/SchemaGetter.ts +47 -35
  360. package/src/Sink.ts +45 -18
  361. package/src/Stream.ts +33 -4
  362. package/src/String.ts +17 -4
  363. package/src/TxRef.ts +4 -2
  364. package/src/Utils.ts +8 -5
  365. package/src/ai/AiError.ts +3 -1
  366. package/src/ai/AnthropicStructuredOutput.ts +2 -2
  367. package/src/ai/Chat.ts +2 -2
  368. package/src/ai/Decision.ts +70 -21
  369. package/src/ai/DecisionModel.ts +1 -1
  370. package/src/ai/LanguageModel.ts +141 -63
  371. package/src/ai/McpServer.ts +259 -145
  372. package/src/ai/Prompt.ts +24 -10
  373. package/src/ai/Response.ts +6 -3
  374. package/src/cli/Completions.ts +5 -0
  375. package/src/cli/Flag.ts +101 -0
  376. package/src/cli/Param.ts +96 -0
  377. package/src/cli/internal/command.ts +2 -1
  378. package/src/cli/internal/completions/bash.ts +4 -3
  379. package/src/cli/internal/completions/descriptor.ts +10 -1
  380. package/src/cli/internal/completions/fish.ts +4 -4
  381. package/src/cli/internal/completions/powershell.ts +5 -2
  382. package/src/cli/internal/completions/zsh.ts +7 -3
  383. package/src/cli/internal/parser.ts +12 -3
  384. package/src/cli/internal/wizard.ts +2 -1
  385. package/src/cluster/ClusterWorkflowEngine.ts +143 -36
  386. package/src/cluster/MessageStorage.ts +14 -3
  387. package/src/cluster/Runners.ts +88 -66
  388. package/src/cluster/Sharding.ts +12 -9
  389. package/src/cluster/internal/entityManager.ts +1 -1
  390. package/src/encoding/Sse.ts +70 -80
  391. package/src/graphql/GraphQL.ts +494 -0
  392. package/src/graphql/GraphQLClient.ts +924 -0
  393. package/src/graphql/GraphQLClientError.ts +542 -0
  394. package/src/graphql/GraphQLGroup.ts +167 -0
  395. package/src/graphql/GraphQLMiddleware.ts +253 -0
  396. package/src/graphql/GraphQLProtocol.ts +1540 -0
  397. package/src/graphql/GraphQLResolver.ts +1038 -0
  398. package/src/graphql/index.ts +48 -0
  399. package/src/http/FetchHttpClient.ts +6 -3
  400. package/src/http/FindMyWay/internal/router.ts +2 -1
  401. package/src/http/Headers.ts +6 -9
  402. package/src/http/HttpClient.ts +72 -11
  403. package/src/http/HttpClientError.ts +10 -6
  404. package/src/http/HttpClientRequest.ts +173 -7
  405. package/src/http/HttpEffect.ts +11 -5
  406. package/src/http/HttpMiddleware.ts +113 -34
  407. package/src/http/HttpRouter.ts +95 -13
  408. package/src/http/HttpServerError.ts +8 -4
  409. package/src/http/HttpServerRequest.ts +2 -2
  410. package/src/http/HttpServerResponse.ts +28 -16
  411. package/src/http/HttpStaticServer.ts +4 -10
  412. package/src/http/HttpTraceContext.ts +1 -1
  413. package/src/http/Multipart.ts +17 -1
  414. package/src/http/Url.ts +2 -1
  415. package/src/http/UrlParams.ts +225 -26
  416. package/src/http/internal/compression.ts +3 -17
  417. package/src/http/internal/compressionBody.ts +56 -0
  418. package/src/http/internal/decompression.ts +226 -0
  419. package/src/http/internal/tracing.ts +21 -4
  420. package/src/http/internal/urlParams.ts +5 -0
  421. package/src/http-api/HttpApiClient.ts +2 -1
  422. package/src/http-api/HttpApiScalar.ts +5 -0
  423. package/src/internal/core.ts +21 -1
  424. package/src/internal/dateTime.ts +13 -10
  425. package/src/internal/effect.ts +13 -7
  426. package/src/internal/graphql.ts +286 -0
  427. package/src/internal/graphqlHeaders.ts +11 -0
  428. package/src/internal/request.ts +31 -3
  429. package/src/internal/schema/toCodeDocument.ts +7 -1
  430. package/src/internal/schema/toJsonSchemaDocument.ts +34 -2
  431. package/src/internal/version.ts +1 -1
  432. package/src/net/Host.ts +72 -0
  433. package/src/net/NetAddress.ts +9 -0
  434. package/src/observability/Otlp.ts +18 -0
  435. package/src/observability/OtlpExporter.ts +14 -3
  436. package/src/observability/OtlpLogger.ts +31 -2
  437. package/src/observability/OtlpMetrics.ts +30 -1
  438. package/src/observability/OtlpTracer.ts +32 -3
  439. package/src/reactivity/AsyncResult.ts +31 -0
  440. package/src/reactivity/AtomRegistry.ts +3 -1
  441. package/src/rpc/RpcClient.ts +6 -1
  442. package/src/rpc/RpcServer.ts +55 -15
  443. package/src/socket/Socket.ts +6 -0
  444. package/src/sql/SqlClient.ts +9 -7
  445. package/src/testing/TestClock.ts +144 -29
  446. package/src/workflow/Activity.ts +1 -0
  447. package/src/workflow/DurableDeferred.ts +43 -5
  448. package/src/workflow/Workflow.ts +31 -5
  449. package/src/workflow/WorkflowEngine.ts +107 -25
@@ -0,0 +1,969 @@
1
+ import * as Context from "../Context.ts";
2
+ import * as Duration from "../Duration.ts";
3
+ import * as Effect from "../Effect.ts";
4
+ import * as Headers from "../http/Headers.ts";
5
+ import * as HttpClient from "../http/HttpClient.ts";
6
+ import * as UrlParams from "../http/UrlParams.ts";
7
+ import * as Layer from "../Layer.ts";
8
+ import * as Schema from "../Schema.ts";
9
+ import type * as Scope from "../Scope.ts";
10
+ import * as Socket from "../socket/Socket.ts";
11
+ import * as Stream from "../Stream.ts";
12
+ import type { Kind } from "./GraphQL.ts";
13
+ import { TransportError } from "./GraphQLClientError.ts";
14
+ /**
15
+ * The request a transport sends. Middleware sees and may rewrite it before it
16
+ * reaches the transport.
17
+ *
18
+ * **Details**
19
+ *
20
+ * `kind` is the operation type, which the HTTP transport uses to send queries
21
+ * as `GET` when `queryMethod: "GET"` is set. `variables` are already encoded
22
+ * through the operation's variables Schema.
23
+ *
24
+ * `headers` and `urlParams` are applied by the HTTP transport, to queries,
25
+ * mutations and graphql-sse subscriptions alike. A graphql-ws transport
26
+ * ignores both, because graphql-ws has no per-operation headers or URL.
27
+ * Request headers are normalized, immutable `Headers.Headers` values.
28
+ *
29
+ * @stability experimental
30
+ * @category models
31
+ * @since 4.0.0
32
+ */
33
+ export interface GraphQLRequest {
34
+ readonly kind: Kind;
35
+ readonly query: string;
36
+ readonly operationName: string;
37
+ readonly variables: unknown;
38
+ readonly extensions?: Record<string, unknown> | undefined;
39
+ readonly headers: Headers.Headers;
40
+ readonly urlParams: UrlParams.UrlParams;
41
+ }
42
+ /**
43
+ * A raw GraphQL result before schema decoding. Middleware receive it from
44
+ * `next` and can read response `extensions`, such as rate-limit costs.
45
+ *
46
+ * **Details**
47
+ *
48
+ * `status` and `headers` are transport metadata, not part of the GraphQL
49
+ * response body: the client decodes the body without them and then copies
50
+ * what the transport reported. Middleware may read or rewrite them, and a
51
+ * failed call's `ResponseError` carries the final values. Headers use
52
+ * `Headers.Headers` at runtime and encode as a plain string record.
53
+ *
54
+ * @stability experimental
55
+ * @category schemas
56
+ * @since 4.0.0
57
+ */
58
+ export declare const ExecutionResult: Schema.Struct<{
59
+ readonly data: Schema.optional<Schema.Unknown>;
60
+ readonly errors: Schema.optional<Schema.$Array<Schema.StructWithRest<Schema.Struct<{
61
+ readonly message: Schema.String;
62
+ readonly locations: Schema.optional<Schema.$Array<Schema.Struct<{
63
+ readonly line: Schema.Number;
64
+ readonly column: Schema.Number;
65
+ }>>>;
66
+ readonly path: Schema.optional<Schema.$Array<Schema.Union<readonly [Schema.String, Schema.Number]>>>;
67
+ readonly extensions: Schema.optional<Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>>;
68
+ }>, readonly [Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>]>>>;
69
+ readonly extensions: Schema.optional<Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>>;
70
+ readonly status: Schema.optional<Schema.Int>;
71
+ readonly headers: Schema.optional<Schema.decodeTo<Schema.declare<Headers.Headers, Headers.Headers>, Schema.$Record<Schema.String, Schema.String>, never, never>>;
72
+ }>;
73
+ /**
74
+ * The decoded type of {@link ExecutionResult}.
75
+ *
76
+ * @stability experimental
77
+ * @category models
78
+ * @since 4.0.0
79
+ */
80
+ export type ExecutionResult = typeof ExecutionResult.Type;
81
+ declare const GraphQLProtocol_base: Context.ServiceClass<GraphQLProtocol, "effect/graphql/GraphQLProtocol", {
82
+ readonly execute: (request: GraphQLRequest) => Effect.Effect<{
83
+ readonly body: unknown;
84
+ readonly status?: number | undefined;
85
+ readonly headers?: Headers.Headers | undefined;
86
+ }, TransportError>;
87
+ readonly subscribe: (request: GraphQLRequest) => Stream.Stream<{
88
+ readonly body: unknown;
89
+ readonly status?: number | undefined;
90
+ readonly headers?: Headers.Headers | undefined;
91
+ }, TransportError>;
92
+ /**
93
+ * Resolves the transport URL for resolver batching. Set by `layerHttp`;
94
+ * optional for custom transports.
95
+ */
96
+ readonly url?: ((options: {
97
+ readonly kind: Kind;
98
+ readonly operationName: string;
99
+ }) => Effect.Effect<string>) | undefined;
100
+ }>;
101
+ /**
102
+ * The transport service. `execute` answers a query or mutation with the raw
103
+ * JSON body, and `subscribe` turns a subscription into a stream of raw events.
104
+ * Both fail only with `TransportError`; GraphQL `errors` are left in the body
105
+ * for the client to interpret.
106
+ *
107
+ * **Details**
108
+ *
109
+ * Each answer is `{ body, status?, headers? }`. The HTTP transport sets
110
+ * `headers` on every answer, including graphql-sse events, and `status` on
111
+ * all but graphql-sse events. Headers are `Headers.Headers` values.
112
+ * graphql-ws leaves both unset.
113
+ *
114
+ * **Example** (A scripted transport for tests)
115
+ *
116
+ * ```ts import.meta.vitest
117
+ * import { Effect, Layer, Schema, Stream } from "effect"
118
+ * import { GraphQL, GraphQLClient, GraphQLGroup, GraphQLProtocol } from "effect/graphql"
119
+ *
120
+ * const Viewer = GraphQL.query("Viewer", {
121
+ * document: "query Viewer{viewer{login}}",
122
+ * result: Schema.Struct({ viewer: Schema.Struct({ login: Schema.String }) })
123
+ * })
124
+ *
125
+ * const Scripted = Layer.succeed(GraphQLProtocol.GraphQLProtocol, {
126
+ * execute: () => Effect.succeed({ body: { data: { viewer: { login: "tim" } } } }),
127
+ * subscribe: () => Stream.empty
128
+ * })
129
+ *
130
+ * const program = Effect.gen(function*() {
131
+ * const client = yield* GraphQLClient.make(GraphQLGroup.make(Viewer))
132
+ * return yield* client.Viewer()
133
+ * })
134
+ *
135
+ * await Effect.runPromise(program.pipe(Effect.provide(Scripted))) // => { viewer: { login: "tim" } }
136
+ * ```
137
+ *
138
+ * @stability experimental
139
+ * @category services
140
+ * @since 4.0.0
141
+ */
142
+ export declare class GraphQLProtocol extends GraphQLProtocol_base {
143
+ }
144
+ /**
145
+ * The URL of an HTTP transport: fixed, resolved for each operation from the
146
+ * calling context, `kind` and `operationName`, or an `Effect` with no errors
147
+ * or requirements. See {@link layerHttp}.
148
+ *
149
+ * @stability experimental
150
+ * @category models
151
+ * @since 4.0.0
152
+ */
153
+ export type Url = string | Effect.Effect<string> | ((options: {
154
+ readonly context: Context.Context<never>;
155
+ readonly kind: Kind;
156
+ readonly operationName: string;
157
+ }) => string);
158
+ /**
159
+ * Builds the HTTP transport as an effect, for composing transports by hand.
160
+ * Most code uses {@link layerHttp}.
161
+ *
162
+ * **Details**
163
+ *
164
+ * Takes the same options as {@link layerHttp}, including `queryMethod`.
165
+ * Without `subscriptions`, subscriptions use graphql-sse distinct mode on
166
+ * `url`. With `subscriptions.webSocket`, `url` must be a string, subscriptions
167
+ * go over graphql-ws instead, and the effect also builds the graphql-ws
168
+ * transport, so it needs a `Socket.WebSocketConstructor` and a `Scope`.
169
+ *
170
+ * @stability experimental
171
+ * @category constructors
172
+ * @since 4.0.0
173
+ */
174
+ export declare const makeHttp: {
175
+ /**
176
+ * Builds the HTTP transport as an effect, for composing transports by hand.
177
+ * Most code uses {@link layerHttp}.
178
+ *
179
+ * **Details**
180
+ *
181
+ * Takes the same options as {@link layerHttp}, including `queryMethod`.
182
+ * Without `subscriptions`, subscriptions use graphql-sse distinct mode on
183
+ * `url`. With `subscriptions.webSocket`, `url` must be a string, subscriptions
184
+ * go over graphql-ws instead, and the effect also builds the graphql-ws
185
+ * transport, so it needs a `Socket.WebSocketConstructor` and a `Scope`.
186
+ *
187
+ * @stability experimental
188
+ * @category constructors
189
+ * @since 4.0.0
190
+ */
191
+ <R = never>(options: {
192
+ readonly url: string;
193
+ readonly queryMethod?: "GET" | "POST" | undefined;
194
+ readonly subscriptions: {
195
+ readonly webSocket: {
196
+ readonly url: string;
197
+ readonly headers?: Headers.Input | undefined;
198
+ readonly connectionParams?: Effect.Effect<Record<string, unknown> | undefined, unknown, R> | undefined;
199
+ readonly connectionAckTimeout?: Duration.Input | undefined;
200
+ readonly keepAlive?: Duration.Input | false | undefined;
201
+ readonly idleTimeout?: Duration.Input | undefined;
202
+ };
203
+ };
204
+ }): Effect.Effect<GraphQLProtocol["Service"], never, HttpClient.HttpClient | Socket.WebSocketConstructor | Scope.Scope | R>;
205
+ /**
206
+ * Builds the HTTP transport as an effect, for composing transports by hand.
207
+ * Most code uses {@link layerHttp}.
208
+ *
209
+ * **Details**
210
+ *
211
+ * Takes the same options as {@link layerHttp}, including `queryMethod`.
212
+ * Without `subscriptions`, subscriptions use graphql-sse distinct mode on
213
+ * `url`. With `subscriptions.webSocket`, `url` must be a string, subscriptions
214
+ * go over graphql-ws instead, and the effect also builds the graphql-ws
215
+ * transport, so it needs a `Socket.WebSocketConstructor` and a `Scope`.
216
+ *
217
+ * @stability experimental
218
+ * @category constructors
219
+ * @since 4.0.0
220
+ */
221
+ (options: {
222
+ readonly url: Url;
223
+ readonly queryMethod?: "GET" | "POST" | undefined;
224
+ readonly subscriptions?: undefined;
225
+ }): Effect.Effect<GraphQLProtocol["Service"], never, HttpClient.HttpClient>;
226
+ };
227
+ /**
228
+ * The HTTP transport: queries and mutations are sent as `POST` with a JSON
229
+ * body to `url`, using the `HttpClient` in context. Subscriptions use
230
+ * graphql-sse distinct mode on the same URL, or graphql-ws when
231
+ * `subscriptions.webSocket` is set.
232
+ *
233
+ * **Details**
234
+ *
235
+ * With `queryMethod: "GET"` (default `"POST"`), queries are sent as `GET`
236
+ * with no body: `query` and `operationName` become URL params, plus
237
+ * `variables` and `extensions` as JSON when set. Mutations are always
238
+ * `POST`, and so are `GraphQLResolver.aliased` batches. A long query is not
239
+ * retried as `POST`.
240
+ *
241
+ * A request's `headers` and `urlParams`, from the call options or from
242
+ * middleware, are applied to every HTTP request. A query string already on
243
+ * `url` is kept. On `GET`, the request's `urlParams` come before the GraphQL
244
+ * params, which replace any caller param with the same name.
245
+ *
246
+ * Every response's HTTP `status` is passed to the client as
247
+ * `ExecutionResult.status`, and a call that fails with GraphQL `errors`
248
+ * reports it as `ResponseError.status`. Response headers are passed the
249
+ * same way, as `ExecutionResult.headers` and `ResponseError.headers`.
250
+ *
251
+ * A response is a GraphQL response when its `Content-Type` is
252
+ * `application/graphql-response+json`, whatever the status, or when it is
253
+ * `application/json` and the body has a list of `errors` or a `data` object
254
+ * (or `null`). Media types match case-insensitively. Anything else
255
+ * is a `TransportError` with the response `status` and `headers`, and a
256
+ * `Retry-After` header (whole seconds or an HTTP date, measured from when the
257
+ * response arrived) becomes `retryAfter`.
258
+ *
259
+ * A subscription is a `POST` with `Accept: text/event-stream`. Each `next`
260
+ * event is emitted with the response headers but no status, and the stream
261
+ * ends on a `complete` event, with or without a `data:` line. A body that
262
+ * fails, or ends without a `complete` event, is a retryable `TransportError`
263
+ * with a server `retry:` line as its `retryAfter`, so the client's
264
+ * `subscriptionRetry` resubscribes. A non-stream answer, such as a `400` with
265
+ * `errors`, is read like a query's response. Interrupting the stream aborts
266
+ * the request.
267
+ *
268
+ * With `subscriptions: { webSocket }`, subscriptions go over graphql-ws as in
269
+ * {@link layerWebSocket}, and the layer needs a `Socket.WebSocketConstructor`.
270
+ *
271
+ * To route each query, mutation and graphql-sse subscription, `url` can be a
272
+ * function of the calling fiber's context (including the call's `context`
273
+ * option), `kind` and `operationName`, or an `Effect<string>` with no errors
274
+ * or requirements that runs in that context. Use a defaulted
275
+ * `Context.Reference` to select the server. Reading a missing service with
276
+ * `Context.get` is a defect, not a `TransportError`. Neither form can be
277
+ * combined with `subscriptions.webSocket`: the socket URL is fixed at
278
+ * connection time.
279
+ *
280
+ * **Gotchas**
281
+ *
282
+ * `GraphQLResolver` resolves each lookup's URL once, before middleware run and
283
+ * before the batched request exists, then sends each batch to the URL it was
284
+ * grouped by. A single call resolves it in the transport, after middleware.
285
+ * So the URL must depend only on the context and the operation, and
286
+ * middleware must not change `kind` or `operationName` or provide services
287
+ * the URL reads.
288
+ *
289
+ * `RequestResolver.withCache` and `RequestResolver.persisted` key on the lookup,
290
+ * not the URL, so results can leak across servers. For caching, use a separate
291
+ * client and resolver per server, for example with `LayerMap`.
292
+ *
293
+ * **Example** (Building a client over HTTP)
294
+ *
295
+ * ```ts import.meta.vitest
296
+ * import { Effect, Layer, Schema } from "effect"
297
+ * import { GraphQL, GraphQLClient, GraphQLGroup, GraphQLProtocol } from "effect/graphql"
298
+ * import { HttpClient, HttpClientResponse } from "effect/http"
299
+ *
300
+ * const Viewer = GraphQL.query("Viewer", {
301
+ * document: "query Viewer{viewer{login}}",
302
+ * result: Schema.Struct({ viewer: Schema.Struct({ login: Schema.String }) })
303
+ * })
304
+ *
305
+ * // A stand-in for a real HttpClient layer such as FetchHttpClient.layer
306
+ * const FakeServer = Layer.succeed(
307
+ * HttpClient.HttpClient,
308
+ * HttpClient.make((request) =>
309
+ * Effect.succeed(HttpClientResponse.fromWeb(
310
+ * request,
311
+ * new Response(JSON.stringify({ data: { viewer: { login: "tim" } } }), {
312
+ * headers: { "content-type": "application/graphql-response+json" }
313
+ * })
314
+ * ))
315
+ * )
316
+ * )
317
+ *
318
+ * const program = Effect.gen(function*() {
319
+ * const client = yield* GraphQLClient.make(GraphQLGroup.make(Viewer))
320
+ * return yield* client.Viewer()
321
+ * }).pipe(
322
+ * Effect.provide(GraphQLProtocol.layerHttp({ url: "https://api.github.com/graphql" })),
323
+ * Effect.provide(FakeServer)
324
+ * )
325
+ *
326
+ * await Effect.runPromise(program) // => { viewer: { login: "tim" } }
327
+ * ```
328
+ *
329
+ * **Example** (Queries over GET with a per-call URL param)
330
+ *
331
+ * ```ts import.meta.vitest
332
+ * import { Effect, Layer, Schema } from "effect"
333
+ * import { GraphQL, GraphQLClient, GraphQLGroup, GraphQLProtocol } from "effect/graphql"
334
+ * import { HttpClient, HttpClientResponse } from "effect/http"
335
+ *
336
+ * const Viewer = GraphQL.query("Viewer", {
337
+ * document: "query Viewer{viewer{login}}",
338
+ * result: Schema.Struct({ viewer: Schema.Struct({ login: Schema.String }) })
339
+ * })
340
+ *
341
+ * // A stand-in server that answers with the method and the `preview` param
342
+ * const FakeServer = Layer.succeed(
343
+ * HttpClient.HttpClient,
344
+ * HttpClient.make((request, url) =>
345
+ * Effect.succeed(HttpClientResponse.fromWeb(
346
+ * request,
347
+ * new Response(
348
+ * JSON.stringify({ data: { viewer: { login: `${request.method} ${url.searchParams.get("preview")}` } } }),
349
+ * { headers: { "content-type": "application/graphql-response+json" } }
350
+ * )
351
+ * ))
352
+ * )
353
+ * )
354
+ *
355
+ * const program = Effect.gen(function*() {
356
+ * const client = yield* GraphQLClient.make(GraphQLGroup.make(Viewer))
357
+ * return yield* client.Viewer(undefined, { urlParams: { preview: "draft-token" } })
358
+ * }).pipe(
359
+ * Effect.provide(GraphQLProtocol.layerHttp({ url: "https://cms.example.com/graphql", queryMethod: "GET" })),
360
+ * Effect.provide(FakeServer)
361
+ * )
362
+ *
363
+ * await Effect.runPromise(program) // => { viewer: { login: "GET draft-token" } }
364
+ * ```
365
+ *
366
+ * **Example** (One client for github.com, GHE.com and GitHub Enterprise Server)
367
+ *
368
+ * ```ts import.meta.vitest
369
+ * import { Context, Effect, Layer, Schema } from "effect"
370
+ * import { GraphQL, GraphQLClient, GraphQLGroup, GraphQLProtocol } from "effect/graphql"
371
+ * import { HttpClient, HttpClientResponse } from "effect/http"
372
+ *
373
+ * const Viewer = GraphQL.query("Viewer", {
374
+ * document: "query Viewer{viewer{login}}",
375
+ * result: Schema.Struct({ viewer: Schema.Struct({ login: Schema.String }) })
376
+ * })
377
+ *
378
+ * const GitHubHost = Context.Reference<string>("GitHubHost", { defaultValue: () => "github.com" })
379
+ *
380
+ * const Protocol = GraphQLProtocol.layerHttp({
381
+ * url: ({ context }) => {
382
+ * const host = Context.get(context, GitHubHost)
383
+ * if (host === "github.com") return "https://api.github.com/graphql"
384
+ * if (host.endsWith(".ghe.com")) return `https://api.${host}/graphql`
385
+ * return `https://${host}/api/graphql`
386
+ * }
387
+ * })
388
+ *
389
+ * // Echo the request URL instead of calling GitHub.
390
+ * const FakeServer = Layer.succeed(
391
+ * HttpClient.HttpClient,
392
+ * HttpClient.make((request, url) =>
393
+ * Effect.succeed(HttpClientResponse.fromWeb(
394
+ * request,
395
+ * new Response(JSON.stringify({ data: { viewer: { login: url.href } } }), {
396
+ * headers: { "content-type": "application/graphql-response+json" }
397
+ * })
398
+ * ))
399
+ * )
400
+ * )
401
+ *
402
+ * const program = Effect.gen(function*() {
403
+ * const client = yield* GraphQLClient.make(GraphQLGroup.make(Viewer))
404
+ * const dotcom = yield* client.Viewer()
405
+ * const cloud = yield* client.Viewer().pipe(Effect.provideService(GitHubHost, "acme.ghe.com"))
406
+ * const server = yield* client.Viewer(undefined, { context: Context.make(GitHubHost, "github.example.com") })
407
+ * return [dotcom, cloud, server].map((result) => result.viewer.login)
408
+ * }).pipe(
409
+ * Effect.provide(Protocol),
410
+ * Effect.provide(FakeServer)
411
+ * )
412
+ *
413
+ * await Effect.runPromise(program) // => ["https://api.github.com/graphql", "https://api.acme.ghe.com/graphql", "https://github.example.com/api/graphql"]
414
+ * ```
415
+ *
416
+ * **Example** (Subscriptions over graphql-ws, everything else over POST)
417
+ *
418
+ * ```ts import.meta.vitest
419
+ * import { Effect } from "effect"
420
+ * import { GraphQLProtocol } from "effect/graphql"
421
+ *
422
+ * const token = Effect.succeed("secret")
423
+ *
424
+ * // Provide an HttpClient and a Socket.WebSocketConstructor, such as
425
+ * // FetchHttpClient.layer and NodeSocket.layerWebSocketConstructor
426
+ * export const Protocol = GraphQLProtocol.layerHttp({
427
+ * url: "https://example.com/graphql",
428
+ * subscriptions: {
429
+ * webSocket: {
430
+ * url: "wss://example.com/graphql",
431
+ * connectionParams: Effect.map(token, (token) => ({ authorization: `Bearer ${token}` }))
432
+ * }
433
+ * }
434
+ * })
435
+ * ```
436
+ *
437
+ * @stability experimental
438
+ * @category layers
439
+ * @since 4.0.0
440
+ */
441
+ export declare const layerHttp: {
442
+ /**
443
+ * The HTTP transport: queries and mutations are sent as `POST` with a JSON
444
+ * body to `url`, using the `HttpClient` in context. Subscriptions use
445
+ * graphql-sse distinct mode on the same URL, or graphql-ws when
446
+ * `subscriptions.webSocket` is set.
447
+ *
448
+ * **Details**
449
+ *
450
+ * With `queryMethod: "GET"` (default `"POST"`), queries are sent as `GET`
451
+ * with no body: `query` and `operationName` become URL params, plus
452
+ * `variables` and `extensions` as JSON when set. Mutations are always
453
+ * `POST`, and so are `GraphQLResolver.aliased` batches. A long query is not
454
+ * retried as `POST`.
455
+ *
456
+ * A request's `headers` and `urlParams`, from the call options or from
457
+ * middleware, are applied to every HTTP request. A query string already on
458
+ * `url` is kept. On `GET`, the request's `urlParams` come before the GraphQL
459
+ * params, which replace any caller param with the same name.
460
+ *
461
+ * Every response's HTTP `status` is passed to the client as
462
+ * `ExecutionResult.status`, and a call that fails with GraphQL `errors`
463
+ * reports it as `ResponseError.status`. Response headers are passed the
464
+ * same way, as `ExecutionResult.headers` and `ResponseError.headers`.
465
+ *
466
+ * A response is a GraphQL response when its `Content-Type` is
467
+ * `application/graphql-response+json`, whatever the status, or when it is
468
+ * `application/json` and the body has a list of `errors` or a `data` object
469
+ * (or `null`). Media types match case-insensitively. Anything else
470
+ * is a `TransportError` with the response `status` and `headers`, and a
471
+ * `Retry-After` header (whole seconds or an HTTP date, measured from when the
472
+ * response arrived) becomes `retryAfter`.
473
+ *
474
+ * A subscription is a `POST` with `Accept: text/event-stream`. Each `next`
475
+ * event is emitted with the response headers but no status, and the stream
476
+ * ends on a `complete` event, with or without a `data:` line. A body that
477
+ * fails, or ends without a `complete` event, is a retryable `TransportError`
478
+ * with a server `retry:` line as its `retryAfter`, so the client's
479
+ * `subscriptionRetry` resubscribes. A non-stream answer, such as a `400` with
480
+ * `errors`, is read like a query's response. Interrupting the stream aborts
481
+ * the request.
482
+ *
483
+ * With `subscriptions: { webSocket }`, subscriptions go over graphql-ws as in
484
+ * {@link layerWebSocket}, and the layer needs a `Socket.WebSocketConstructor`.
485
+ *
486
+ * To route each query, mutation and graphql-sse subscription, `url` can be a
487
+ * function of the calling fiber's context (including the call's `context`
488
+ * option), `kind` and `operationName`, or an `Effect<string>` with no errors
489
+ * or requirements that runs in that context. Use a defaulted
490
+ * `Context.Reference` to select the server. Reading a missing service with
491
+ * `Context.get` is a defect, not a `TransportError`. Neither form can be
492
+ * combined with `subscriptions.webSocket`: the socket URL is fixed at
493
+ * connection time.
494
+ *
495
+ * **Gotchas**
496
+ *
497
+ * `GraphQLResolver` resolves each lookup's URL once, before middleware run and
498
+ * before the batched request exists, then sends each batch to the URL it was
499
+ * grouped by. A single call resolves it in the transport, after middleware.
500
+ * So the URL must depend only on the context and the operation, and
501
+ * middleware must not change `kind` or `operationName` or provide services
502
+ * the URL reads.
503
+ *
504
+ * `RequestResolver.withCache` and `RequestResolver.persisted` key on the lookup,
505
+ * not the URL, so results can leak across servers. For caching, use a separate
506
+ * client and resolver per server, for example with `LayerMap`.
507
+ *
508
+ * **Example** (Building a client over HTTP)
509
+ *
510
+ * ```ts import.meta.vitest
511
+ * import { Effect, Layer, Schema } from "effect"
512
+ * import { GraphQL, GraphQLClient, GraphQLGroup, GraphQLProtocol } from "effect/graphql"
513
+ * import { HttpClient, HttpClientResponse } from "effect/http"
514
+ *
515
+ * const Viewer = GraphQL.query("Viewer", {
516
+ * document: "query Viewer{viewer{login}}",
517
+ * result: Schema.Struct({ viewer: Schema.Struct({ login: Schema.String }) })
518
+ * })
519
+ *
520
+ * // A stand-in for a real HttpClient layer such as FetchHttpClient.layer
521
+ * const FakeServer = Layer.succeed(
522
+ * HttpClient.HttpClient,
523
+ * HttpClient.make((request) =>
524
+ * Effect.succeed(HttpClientResponse.fromWeb(
525
+ * request,
526
+ * new Response(JSON.stringify({ data: { viewer: { login: "tim" } } }), {
527
+ * headers: { "content-type": "application/graphql-response+json" }
528
+ * })
529
+ * ))
530
+ * )
531
+ * )
532
+ *
533
+ * const program = Effect.gen(function*() {
534
+ * const client = yield* GraphQLClient.make(GraphQLGroup.make(Viewer))
535
+ * return yield* client.Viewer()
536
+ * }).pipe(
537
+ * Effect.provide(GraphQLProtocol.layerHttp({ url: "https://api.github.com/graphql" })),
538
+ * Effect.provide(FakeServer)
539
+ * )
540
+ *
541
+ * await Effect.runPromise(program) // => { viewer: { login: "tim" } }
542
+ * ```
543
+ *
544
+ * **Example** (Queries over GET with a per-call URL param)
545
+ *
546
+ * ```ts import.meta.vitest
547
+ * import { Effect, Layer, Schema } from "effect"
548
+ * import { GraphQL, GraphQLClient, GraphQLGroup, GraphQLProtocol } from "effect/graphql"
549
+ * import { HttpClient, HttpClientResponse } from "effect/http"
550
+ *
551
+ * const Viewer = GraphQL.query("Viewer", {
552
+ * document: "query Viewer{viewer{login}}",
553
+ * result: Schema.Struct({ viewer: Schema.Struct({ login: Schema.String }) })
554
+ * })
555
+ *
556
+ * // A stand-in server that answers with the method and the `preview` param
557
+ * const FakeServer = Layer.succeed(
558
+ * HttpClient.HttpClient,
559
+ * HttpClient.make((request, url) =>
560
+ * Effect.succeed(HttpClientResponse.fromWeb(
561
+ * request,
562
+ * new Response(
563
+ * JSON.stringify({ data: { viewer: { login: `${request.method} ${url.searchParams.get("preview")}` } } }),
564
+ * { headers: { "content-type": "application/graphql-response+json" } }
565
+ * )
566
+ * ))
567
+ * )
568
+ * )
569
+ *
570
+ * const program = Effect.gen(function*() {
571
+ * const client = yield* GraphQLClient.make(GraphQLGroup.make(Viewer))
572
+ * return yield* client.Viewer(undefined, { urlParams: { preview: "draft-token" } })
573
+ * }).pipe(
574
+ * Effect.provide(GraphQLProtocol.layerHttp({ url: "https://cms.example.com/graphql", queryMethod: "GET" })),
575
+ * Effect.provide(FakeServer)
576
+ * )
577
+ *
578
+ * await Effect.runPromise(program) // => { viewer: { login: "GET draft-token" } }
579
+ * ```
580
+ *
581
+ * **Example** (One client for github.com, GHE.com and GitHub Enterprise Server)
582
+ *
583
+ * ```ts import.meta.vitest
584
+ * import { Context, Effect, Layer, Schema } from "effect"
585
+ * import { GraphQL, GraphQLClient, GraphQLGroup, GraphQLProtocol } from "effect/graphql"
586
+ * import { HttpClient, HttpClientResponse } from "effect/http"
587
+ *
588
+ * const Viewer = GraphQL.query("Viewer", {
589
+ * document: "query Viewer{viewer{login}}",
590
+ * result: Schema.Struct({ viewer: Schema.Struct({ login: Schema.String }) })
591
+ * })
592
+ *
593
+ * const GitHubHost = Context.Reference<string>("GitHubHost", { defaultValue: () => "github.com" })
594
+ *
595
+ * const Protocol = GraphQLProtocol.layerHttp({
596
+ * url: ({ context }) => {
597
+ * const host = Context.get(context, GitHubHost)
598
+ * if (host === "github.com") return "https://api.github.com/graphql"
599
+ * if (host.endsWith(".ghe.com")) return `https://api.${host}/graphql`
600
+ * return `https://${host}/api/graphql`
601
+ * }
602
+ * })
603
+ *
604
+ * // Echo the request URL instead of calling GitHub.
605
+ * const FakeServer = Layer.succeed(
606
+ * HttpClient.HttpClient,
607
+ * HttpClient.make((request, url) =>
608
+ * Effect.succeed(HttpClientResponse.fromWeb(
609
+ * request,
610
+ * new Response(JSON.stringify({ data: { viewer: { login: url.href } } }), {
611
+ * headers: { "content-type": "application/graphql-response+json" }
612
+ * })
613
+ * ))
614
+ * )
615
+ * )
616
+ *
617
+ * const program = Effect.gen(function*() {
618
+ * const client = yield* GraphQLClient.make(GraphQLGroup.make(Viewer))
619
+ * const dotcom = yield* client.Viewer()
620
+ * const cloud = yield* client.Viewer().pipe(Effect.provideService(GitHubHost, "acme.ghe.com"))
621
+ * const server = yield* client.Viewer(undefined, { context: Context.make(GitHubHost, "github.example.com") })
622
+ * return [dotcom, cloud, server].map((result) => result.viewer.login)
623
+ * }).pipe(
624
+ * Effect.provide(Protocol),
625
+ * Effect.provide(FakeServer)
626
+ * )
627
+ *
628
+ * await Effect.runPromise(program) // => ["https://api.github.com/graphql", "https://api.acme.ghe.com/graphql", "https://github.example.com/api/graphql"]
629
+ * ```
630
+ *
631
+ * **Example** (Subscriptions over graphql-ws, everything else over POST)
632
+ *
633
+ * ```ts import.meta.vitest
634
+ * import { Effect } from "effect"
635
+ * import { GraphQLProtocol } from "effect/graphql"
636
+ *
637
+ * const token = Effect.succeed("secret")
638
+ *
639
+ * // Provide an HttpClient and a Socket.WebSocketConstructor, such as
640
+ * // FetchHttpClient.layer and NodeSocket.layerWebSocketConstructor
641
+ * export const Protocol = GraphQLProtocol.layerHttp({
642
+ * url: "https://example.com/graphql",
643
+ * subscriptions: {
644
+ * webSocket: {
645
+ * url: "wss://example.com/graphql",
646
+ * connectionParams: Effect.map(token, (token) => ({ authorization: `Bearer ${token}` }))
647
+ * }
648
+ * }
649
+ * })
650
+ * ```
651
+ *
652
+ * @stability experimental
653
+ * @category layers
654
+ * @since 4.0.0
655
+ */
656
+ <R = never>(options: {
657
+ readonly url: string;
658
+ readonly queryMethod?: "GET" | "POST" | undefined;
659
+ readonly subscriptions: {
660
+ readonly webSocket: {
661
+ readonly url: string;
662
+ readonly headers?: Headers.Input | undefined;
663
+ readonly connectionParams?: Effect.Effect<Record<string, unknown> | undefined, unknown, R> | undefined;
664
+ readonly connectionAckTimeout?: Duration.Input | undefined;
665
+ readonly keepAlive?: Duration.Input | false | undefined;
666
+ readonly idleTimeout?: Duration.Input | undefined;
667
+ };
668
+ };
669
+ }): Layer.Layer<GraphQLProtocol, never, HttpClient.HttpClient | Socket.WebSocketConstructor | R>;
670
+ /**
671
+ * The HTTP transport: queries and mutations are sent as `POST` with a JSON
672
+ * body to `url`, using the `HttpClient` in context. Subscriptions use
673
+ * graphql-sse distinct mode on the same URL, or graphql-ws when
674
+ * `subscriptions.webSocket` is set.
675
+ *
676
+ * **Details**
677
+ *
678
+ * With `queryMethod: "GET"` (default `"POST"`), queries are sent as `GET`
679
+ * with no body: `query` and `operationName` become URL params, plus
680
+ * `variables` and `extensions` as JSON when set. Mutations are always
681
+ * `POST`, and so are `GraphQLResolver.aliased` batches. A long query is not
682
+ * retried as `POST`.
683
+ *
684
+ * A request's `headers` and `urlParams`, from the call options or from
685
+ * middleware, are applied to every HTTP request. A query string already on
686
+ * `url` is kept. On `GET`, the request's `urlParams` come before the GraphQL
687
+ * params, which replace any caller param with the same name.
688
+ *
689
+ * Every response's HTTP `status` is passed to the client as
690
+ * `ExecutionResult.status`, and a call that fails with GraphQL `errors`
691
+ * reports it as `ResponseError.status`. Response headers are passed the
692
+ * same way, as `ExecutionResult.headers` and `ResponseError.headers`.
693
+ *
694
+ * A response is a GraphQL response when its `Content-Type` is
695
+ * `application/graphql-response+json`, whatever the status, or when it is
696
+ * `application/json` and the body has a list of `errors` or a `data` object
697
+ * (or `null`). Media types match case-insensitively. Anything else
698
+ * is a `TransportError` with the response `status` and `headers`, and a
699
+ * `Retry-After` header (whole seconds or an HTTP date, measured from when the
700
+ * response arrived) becomes `retryAfter`.
701
+ *
702
+ * A subscription is a `POST` with `Accept: text/event-stream`. Each `next`
703
+ * event is emitted with the response headers but no status, and the stream
704
+ * ends on a `complete` event, with or without a `data:` line. A body that
705
+ * fails, or ends without a `complete` event, is a retryable `TransportError`
706
+ * with a server `retry:` line as its `retryAfter`, so the client's
707
+ * `subscriptionRetry` resubscribes. A non-stream answer, such as a `400` with
708
+ * `errors`, is read like a query's response. Interrupting the stream aborts
709
+ * the request.
710
+ *
711
+ * With `subscriptions: { webSocket }`, subscriptions go over graphql-ws as in
712
+ * {@link layerWebSocket}, and the layer needs a `Socket.WebSocketConstructor`.
713
+ *
714
+ * To route each query, mutation and graphql-sse subscription, `url` can be a
715
+ * function of the calling fiber's context (including the call's `context`
716
+ * option), `kind` and `operationName`, or an `Effect<string>` with no errors
717
+ * or requirements that runs in that context. Use a defaulted
718
+ * `Context.Reference` to select the server. Reading a missing service with
719
+ * `Context.get` is a defect, not a `TransportError`. Neither form can be
720
+ * combined with `subscriptions.webSocket`: the socket URL is fixed at
721
+ * connection time.
722
+ *
723
+ * **Gotchas**
724
+ *
725
+ * `GraphQLResolver` resolves each lookup's URL once, before middleware run and
726
+ * before the batched request exists, then sends each batch to the URL it was
727
+ * grouped by. A single call resolves it in the transport, after middleware.
728
+ * So the URL must depend only on the context and the operation, and
729
+ * middleware must not change `kind` or `operationName` or provide services
730
+ * the URL reads.
731
+ *
732
+ * `RequestResolver.withCache` and `RequestResolver.persisted` key on the lookup,
733
+ * not the URL, so results can leak across servers. For caching, use a separate
734
+ * client and resolver per server, for example with `LayerMap`.
735
+ *
736
+ * **Example** (Building a client over HTTP)
737
+ *
738
+ * ```ts import.meta.vitest
739
+ * import { Effect, Layer, Schema } from "effect"
740
+ * import { GraphQL, GraphQLClient, GraphQLGroup, GraphQLProtocol } from "effect/graphql"
741
+ * import { HttpClient, HttpClientResponse } from "effect/http"
742
+ *
743
+ * const Viewer = GraphQL.query("Viewer", {
744
+ * document: "query Viewer{viewer{login}}",
745
+ * result: Schema.Struct({ viewer: Schema.Struct({ login: Schema.String }) })
746
+ * })
747
+ *
748
+ * // A stand-in for a real HttpClient layer such as FetchHttpClient.layer
749
+ * const FakeServer = Layer.succeed(
750
+ * HttpClient.HttpClient,
751
+ * HttpClient.make((request) =>
752
+ * Effect.succeed(HttpClientResponse.fromWeb(
753
+ * request,
754
+ * new Response(JSON.stringify({ data: { viewer: { login: "tim" } } }), {
755
+ * headers: { "content-type": "application/graphql-response+json" }
756
+ * })
757
+ * ))
758
+ * )
759
+ * )
760
+ *
761
+ * const program = Effect.gen(function*() {
762
+ * const client = yield* GraphQLClient.make(GraphQLGroup.make(Viewer))
763
+ * return yield* client.Viewer()
764
+ * }).pipe(
765
+ * Effect.provide(GraphQLProtocol.layerHttp({ url: "https://api.github.com/graphql" })),
766
+ * Effect.provide(FakeServer)
767
+ * )
768
+ *
769
+ * await Effect.runPromise(program) // => { viewer: { login: "tim" } }
770
+ * ```
771
+ *
772
+ * **Example** (Queries over GET with a per-call URL param)
773
+ *
774
+ * ```ts import.meta.vitest
775
+ * import { Effect, Layer, Schema } from "effect"
776
+ * import { GraphQL, GraphQLClient, GraphQLGroup, GraphQLProtocol } from "effect/graphql"
777
+ * import { HttpClient, HttpClientResponse } from "effect/http"
778
+ *
779
+ * const Viewer = GraphQL.query("Viewer", {
780
+ * document: "query Viewer{viewer{login}}",
781
+ * result: Schema.Struct({ viewer: Schema.Struct({ login: Schema.String }) })
782
+ * })
783
+ *
784
+ * // A stand-in server that answers with the method and the `preview` param
785
+ * const FakeServer = Layer.succeed(
786
+ * HttpClient.HttpClient,
787
+ * HttpClient.make((request, url) =>
788
+ * Effect.succeed(HttpClientResponse.fromWeb(
789
+ * request,
790
+ * new Response(
791
+ * JSON.stringify({ data: { viewer: { login: `${request.method} ${url.searchParams.get("preview")}` } } }),
792
+ * { headers: { "content-type": "application/graphql-response+json" } }
793
+ * )
794
+ * ))
795
+ * )
796
+ * )
797
+ *
798
+ * const program = Effect.gen(function*() {
799
+ * const client = yield* GraphQLClient.make(GraphQLGroup.make(Viewer))
800
+ * return yield* client.Viewer(undefined, { urlParams: { preview: "draft-token" } })
801
+ * }).pipe(
802
+ * Effect.provide(GraphQLProtocol.layerHttp({ url: "https://cms.example.com/graphql", queryMethod: "GET" })),
803
+ * Effect.provide(FakeServer)
804
+ * )
805
+ *
806
+ * await Effect.runPromise(program) // => { viewer: { login: "GET draft-token" } }
807
+ * ```
808
+ *
809
+ * **Example** (One client for github.com, GHE.com and GitHub Enterprise Server)
810
+ *
811
+ * ```ts import.meta.vitest
812
+ * import { Context, Effect, Layer, Schema } from "effect"
813
+ * import { GraphQL, GraphQLClient, GraphQLGroup, GraphQLProtocol } from "effect/graphql"
814
+ * import { HttpClient, HttpClientResponse } from "effect/http"
815
+ *
816
+ * const Viewer = GraphQL.query("Viewer", {
817
+ * document: "query Viewer{viewer{login}}",
818
+ * result: Schema.Struct({ viewer: Schema.Struct({ login: Schema.String }) })
819
+ * })
820
+ *
821
+ * const GitHubHost = Context.Reference<string>("GitHubHost", { defaultValue: () => "github.com" })
822
+ *
823
+ * const Protocol = GraphQLProtocol.layerHttp({
824
+ * url: ({ context }) => {
825
+ * const host = Context.get(context, GitHubHost)
826
+ * if (host === "github.com") return "https://api.github.com/graphql"
827
+ * if (host.endsWith(".ghe.com")) return `https://api.${host}/graphql`
828
+ * return `https://${host}/api/graphql`
829
+ * }
830
+ * })
831
+ *
832
+ * // Echo the request URL instead of calling GitHub.
833
+ * const FakeServer = Layer.succeed(
834
+ * HttpClient.HttpClient,
835
+ * HttpClient.make((request, url) =>
836
+ * Effect.succeed(HttpClientResponse.fromWeb(
837
+ * request,
838
+ * new Response(JSON.stringify({ data: { viewer: { login: url.href } } }), {
839
+ * headers: { "content-type": "application/graphql-response+json" }
840
+ * })
841
+ * ))
842
+ * )
843
+ * )
844
+ *
845
+ * const program = Effect.gen(function*() {
846
+ * const client = yield* GraphQLClient.make(GraphQLGroup.make(Viewer))
847
+ * const dotcom = yield* client.Viewer()
848
+ * const cloud = yield* client.Viewer().pipe(Effect.provideService(GitHubHost, "acme.ghe.com"))
849
+ * const server = yield* client.Viewer(undefined, { context: Context.make(GitHubHost, "github.example.com") })
850
+ * return [dotcom, cloud, server].map((result) => result.viewer.login)
851
+ * }).pipe(
852
+ * Effect.provide(Protocol),
853
+ * Effect.provide(FakeServer)
854
+ * )
855
+ *
856
+ * await Effect.runPromise(program) // => ["https://api.github.com/graphql", "https://api.acme.ghe.com/graphql", "https://github.example.com/api/graphql"]
857
+ * ```
858
+ *
859
+ * **Example** (Subscriptions over graphql-ws, everything else over POST)
860
+ *
861
+ * ```ts import.meta.vitest
862
+ * import { Effect } from "effect"
863
+ * import { GraphQLProtocol } from "effect/graphql"
864
+ *
865
+ * const token = Effect.succeed("secret")
866
+ *
867
+ * // Provide an HttpClient and a Socket.WebSocketConstructor, such as
868
+ * // FetchHttpClient.layer and NodeSocket.layerWebSocketConstructor
869
+ * export const Protocol = GraphQLProtocol.layerHttp({
870
+ * url: "https://example.com/graphql",
871
+ * subscriptions: {
872
+ * webSocket: {
873
+ * url: "wss://example.com/graphql",
874
+ * connectionParams: Effect.map(token, (token) => ({ authorization: `Bearer ${token}` }))
875
+ * }
876
+ * }
877
+ * })
878
+ * ```
879
+ *
880
+ * @stability experimental
881
+ * @category layers
882
+ * @since 4.0.0
883
+ */
884
+ (options: {
885
+ readonly url: Url;
886
+ readonly queryMethod?: "GET" | "POST" | undefined;
887
+ readonly subscriptions?: undefined;
888
+ }): Layer.Layer<GraphQLProtocol, never, HttpClient.HttpClient>;
889
+ };
890
+ /**
891
+ * Builds the graphql-ws transport as an effect, for composing transports by
892
+ * hand. Most code uses {@link layerWebSocket}, which describes the options.
893
+ *
894
+ * @stability experimental
895
+ * @category constructors
896
+ * @since 4.0.0
897
+ */
898
+ export declare const makeWebSocket: <R = never>(options: {
899
+ readonly url: string;
900
+ readonly headers?: Headers.Input | undefined;
901
+ readonly connectionParams?: Effect.Effect<Record<string, unknown> | undefined, unknown, R> | undefined;
902
+ readonly connectionAckTimeout?: Duration.Input | undefined;
903
+ readonly keepAlive?: Duration.Input | false | undefined;
904
+ readonly idleTimeout?: Duration.Input | undefined;
905
+ }) => Effect.Effect<GraphQLProtocol["Service"], never, Socket.WebSocketConstructor | Scope.Scope | R>;
906
+ /**
907
+ * The graphql-ws transport: every operation goes over one WebSocket using the
908
+ * `graphql-transport-ws` subprotocol, with the `Socket.WebSocketConstructor`
909
+ * in context.
910
+ *
911
+ * **Details**
912
+ *
913
+ * The socket connects lazily and multiplexes operations by id. It closes after
914
+ * `idleTimeout` (default 0) with no active operations, or with code `1000`
915
+ * when the layer's scope closes.
916
+ *
917
+ * - Operations wait for `connection_ack`. `connectionAckTimeout` (default
918
+ * 10 seconds) starts after sending `connection_init`.
919
+ * - `connectionParams` runs on every connection, allowing token refresh.
920
+ * Failure or a socket close during evaluation is a `TransportError`.
921
+ * - Handshake `headers` accept `Headers.Input` and are normalized before
922
+ * reaching the socket. They require a Node or Bun WebSocket constructor;
923
+ * browsers cannot set them. Per-operation `headers` and `urlParams` are ignored.
924
+ * - Results carry no HTTP `status`.
925
+ * - `keepAlive` (default 10 seconds, or `false` to disable) sends `ping`.
926
+ * No server frame in the following interval causes a retryable failure.
927
+ * Server `ping` receives `pong`.
928
+ * - Lost connections fail every active operation with a `TransportError`
929
+ * carrying the close code. See `GraphQLClientError.isFatalCloseCode` for
930
+ * non-retryable codes. The transport never replays operations; the client
931
+ * retries subscriptions and the next operation reconnects.
932
+ * - Once the layer's scope has closed, every new operation fails at once
933
+ * with a non-retryable `TransportError` marked `fatal`.
934
+ * - Messages follow graphql-ws validation. Invalid messages close the socket
935
+ * with fatal code `4400`; valid messages for unknown ids are ignored.
936
+ * - Server `error` messages become `ResponseError` values. Interrupting a
937
+ * subscription sends `complete`.
938
+ *
939
+ * **Example** (A client over graphql-ws)
940
+ *
941
+ * ```ts import.meta.vitest
942
+ * import { Effect, Layer } from "effect"
943
+ * import { GraphQLProtocol } from "effect/graphql"
944
+ * import type { Socket } from "effect/socket"
945
+ *
946
+ * // Provide a Socket.WebSocketConstructor, such as
947
+ * // Socket.layerWebSocketConstructorGlobal in a browser
948
+ * export const Protocol: Layer.Layer<GraphQLProtocol.GraphQLProtocol, never, Socket.WebSocketConstructor> =
949
+ * GraphQLProtocol.layerWebSocket({
950
+ * url: "wss://example.com/graphql",
951
+ * connectionParams: Effect.succeed({ authorization: "Bearer secret" }),
952
+ * idleTimeout: "30 seconds"
953
+ * })
954
+ * ```
955
+ *
956
+ * @stability experimental
957
+ * @category layers
958
+ * @since 4.0.0
959
+ */
960
+ export declare const layerWebSocket: <R = never>(options: {
961
+ readonly url: string;
962
+ readonly headers?: Headers.Input | undefined;
963
+ readonly connectionParams?: Effect.Effect<Record<string, unknown> | undefined, unknown, R> | undefined;
964
+ readonly connectionAckTimeout?: Duration.Input | undefined;
965
+ readonly keepAlive?: Duration.Input | false | undefined;
966
+ readonly idleTimeout?: Duration.Input | undefined;
967
+ }) => Layer.Layer<GraphQLProtocol, never, Socket.WebSocketConstructor | R>;
968
+ export {};
969
+ //# sourceMappingURL=GraphQLProtocol.d.ts.map