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
@@ -8,6 +8,11 @@
8
8
  * storage constructor, layers, migrations, optional table prefixes, and the row
9
9
  * mapping needed by encoded message storage.
10
10
  *
11
+ * `layer`, `layerWith`, `make`, and `makeEncoded` run the migrations before
12
+ * building the storage. To run migrations with a different connection, such as
13
+ * a schema owner in a deploy step, use `layerMigrations` there and
14
+ * `layerStorage` in the runtime.
15
+ *
11
16
  * Request deduplication keys that exceed the 255-character `message_id`
12
17
  * column are hashed with the `Crypto` service before they are written, so
13
18
  * composed keys of any length are supported; shorter keys are stored as
@@ -24,7 +29,6 @@ import * as Hex from "../encoding/Hex.ts"
24
29
  import * as Layer from "../Layer.ts"
25
30
  import * as Option from "../Option.ts"
26
31
  import type * as PlatformError from "../PlatformError.ts"
27
- import * as Schedule from "../Schedule.ts"
28
32
  import * as Migrator from "../sql/Migrator.ts"
29
33
  import * as SqlClient from "../sql/SqlClient.ts"
30
34
  import type { Row } from "../sql/SqlConnection.ts"
@@ -73,19 +77,18 @@ export const makeEncoded: (options?: {
73
77
  MessageStorage.Encoded,
74
78
  never,
75
79
  SqlClient.SqlClient | Crypto.Crypto
76
- > = Effect.fnUntraced(function*(options) {
80
+ > = (options) => Effect.andThen(runMessageMigrations(options), makeEncodedStorage(options))
81
+
82
+ const makeEncodedStorage = Effect.fnUntraced(function*(
83
+ options: {
84
+ readonly prefix?: string | undefined
85
+ } | undefined
86
+ ) {
77
87
  const sql = (yield* SqlClient.SqlClient).withoutTransforms()
78
88
  const crypto = yield* Crypto.Crypto
79
89
  const prefix = options?.prefix ?? "cluster"
80
90
  const table = (name: string) => `${prefix}_${name}`
81
91
 
82
- yield* Effect.orDie(
83
- Migrator.make({})({
84
- loader: migrations(options),
85
- table: table("migrations")
86
- })
87
- )
88
-
89
92
  const messageKindAckChunk = sql.literal(String(messageKind.AckChunk))
90
93
  const messageKindInterrupt = sql.literal(String(messageKind.Interrupt))
91
94
  const replyKindWithExit = sql.literal(String(replyKind.WithExit))
@@ -810,69 +813,27 @@ export const make: (options?: {
810
813
  > = (options) => Effect.flatMap(makeEncoded(options), MessageStorage.makeEncoded)
811
814
 
812
815
  /**
813
- * Layer that provides SQL-backed `MessageStorage` using the default table prefix
814
- * and the default snowflake generator.
815
- *
816
- * **When to use**
817
- *
818
- * Use when a cluster should persist mailbox messages and replies in SQL using
819
- * the default `cluster` table prefix and the standard snowflake generator.
816
+ * Migration loader for the SQL message storage tables.
820
817
  *
821
818
  * **Details**
822
819
  *
823
- * The layer runs the SQL migrations through `make`, provides `MessageStorage`,
824
- * and supplies `Snowflake.layerGenerator` internally. Callers still provide
825
- * `SqlClient`, `ShardingConfig`, and `Crypto.Crypto`, which is used to hash
826
- * message deduplication keys that would overflow the fixed-width
827
- * `message_id` column.
828
- *
829
- * **Gotchas**
830
- *
831
- * This layer always uses the `cluster` table prefix. Use `layerWith` before
832
- * deployment if you need a different stable prefix, because changing prefixes
833
- * later points the runtime at a different set of tables.
834
- *
835
- * @see {@link layerWith} for the same SQL storage layer with a custom table prefix
836
- * @see {@link make} for the lower-level service constructor that uses an existing `Snowflake.Generator`
820
+ * History is recorded in `<prefix>_migrations`; the default
821
+ * prefix is `cluster`.
837
822
  *
838
823
  * @stability unstable
839
- * @category layers
840
- * @since 4.0.0
841
- */
842
- export const layer: Layer.Layer<
843
- MessageStorage.MessageStorage,
844
- never,
845
- SqlClient.SqlClient | ShardingConfig | Crypto.Crypto
846
- > = Layer.effect(MessageStorage.MessageStorage, make()).pipe(
847
- Layer.provide(Snowflake.layerGenerator)
848
- )
849
-
850
- /**
851
- * Layer that provides SQL-backed `MessageStorage` using a custom table prefix.
852
- *
853
- * @stability unstable
854
- * @category layers
855
- * @since 4.0.0
824
+ * @category migrations
825
+ * @since 4.1.0
856
826
  */
857
- export const layerWith = (options: {
858
- readonly prefix?: string | undefined
859
- }): Layer.Layer<MessageStorage.MessageStorage, never, SqlClient.SqlClient | ShardingConfig | Crypto.Crypto> =>
860
- Layer.effect(MessageStorage.MessageStorage, make(options)).pipe(
861
- Layer.provide(Snowflake.layerGenerator)
862
- )
863
-
864
- // -------------------------------------------------------------------------------------------------
865
- // internal
866
- // -------------------------------------------------------------------------------------------------
867
-
868
- const migrations = (options?: {
827
+ export const migrations = (options?: {
869
828
  readonly prefix?: string | undefined
870
- }) => {
829
+ }): Migrator.Loader => {
871
830
  const prefix = options?.prefix ?? "cluster"
872
831
  const table = (name: string) => `${prefix}_${name}`
873
832
  const messagesTable = table("messages")
874
833
  const repliesTable = table("replies")
875
834
 
835
+ // The migrator serializes PostgreSQL DDL. Propagate errors: retrying in an
836
+ // aborted transaction cannot succeed.
876
837
  return Migrator.fromRecord({
877
838
  "0001_create_tables": Effect.gen(function*() {
878
839
  const sql = (yield* SqlClient.SqlClient).withoutTransforms()
@@ -956,7 +917,7 @@ const migrations = (options?: {
956
917
  deliver_at BIGINT,
957
918
  UNIQUE (message_id)
958
919
  )
959
- `.pipe(Effect.ignore),
920
+ `,
960
921
  orElse: () =>
961
922
  // sqlite
962
923
  sql`
@@ -1016,18 +977,7 @@ const migrations = (options?: {
1016
977
  CREATE INDEX IF NOT EXISTS ${sql(requestIdLookupIndex)}
1017
978
  ON ${messagesTableSql} (request_id)
1018
979
  `
1019
- }).pipe(
1020
- sql.withTransaction,
1021
- Effect.tapDefect((error) =>
1022
- Effect.annotateLogs(Effect.logDebug("Failed to create indexes", error), {
1023
- package: "@effect/cluster",
1024
- module: "SqlMessageStorage"
1025
- })
1026
- ),
1027
- Effect.retry({
1028
- schedule: Schedule.spaced(1000)
1029
- })
1030
- ),
980
+ }),
1031
981
  orElse: () =>
1032
982
  // sqlite
1033
983
  Effect.all([
@@ -1121,17 +1071,7 @@ const migrations = (options?: {
1121
1071
  sql`
1122
1072
  CREATE INDEX IF NOT EXISTS ${sql(replyLookupIndex)}
1123
1073
  ON ${repliesTableSql} (request_id, kind, acked);
1124
- `.pipe(
1125
- Effect.tapDefect((error) =>
1126
- Effect.annotateLogs(Effect.logDebug("Failed to create indexes", error), {
1127
- package: "@effect/cluster",
1128
- module: "SqlMessageStorage"
1129
- })
1130
- ),
1131
- Effect.retry({
1132
- schedule: Schedule.spaced(1000)
1133
- })
1134
- ),
1074
+ `,
1135
1075
  orElse: () =>
1136
1076
  // sqlite
1137
1077
  sql`
@@ -1180,6 +1120,100 @@ const migrations = (options?: {
1180
1120
  })
1181
1121
  }
1182
1122
 
1123
+ const runMessageMigrations = (options?: {
1124
+ readonly prefix?: string | undefined
1125
+ }): Effect.Effect<void, never, SqlClient.SqlClient> =>
1126
+ Migrator.make({})({
1127
+ loader: migrations(options),
1128
+ table: `${options?.prefix ?? "cluster"}_migrations`
1129
+ }).pipe(Effect.asVoid, Effect.orDie)
1130
+
1131
+ /**
1132
+ * Runs the SQL message storage migrations without providing storage.
1133
+ *
1134
+ * **Details**
1135
+ *
1136
+ * Use an owner connection in a deploy step, then use `layerStorage` with a
1137
+ * DML-only runtime connection. History is recorded in `<prefix>_migrations`.
1138
+ * Migration errors become defects.
1139
+ *
1140
+ * On PostgreSQL, use the role's `search_path` to select a schema. A
1141
+ * schema-qualified prefix such as `app.cluster` produces an invalid index name.
1142
+ *
1143
+ * @stability unstable
1144
+ * @category layers
1145
+ * @since 4.1.0
1146
+ */
1147
+ export const layerMigrations = (options: {
1148
+ readonly prefix?: string | undefined
1149
+ }): Layer.Layer<never, never, SqlClient.SqlClient> => Layer.effectDiscard(runMessageMigrations(options))
1150
+
1151
+ /**
1152
+ * Provides SQL-backed `MessageStorage` without DDL or startup schema checks.
1153
+ *
1154
+ * **Details**
1155
+ *
1156
+ * Run `layerMigrations` separately before using this layer.
1157
+ * This layer supplies `Snowflake.layerGenerator` internally.
1158
+ *
1159
+ * @stability unstable
1160
+ * @category layers
1161
+ * @since 4.1.0
1162
+ */
1163
+ export const layerStorage = (options: {
1164
+ readonly prefix?: string | undefined
1165
+ }): Layer.Layer<MessageStorage.MessageStorage, never, SqlClient.SqlClient | ShardingConfig | Crypto.Crypto> =>
1166
+ Layer.effect(
1167
+ MessageStorage.MessageStorage,
1168
+ Effect.flatMap(makeEncodedStorage(options), MessageStorage.makeEncoded)
1169
+ ).pipe(
1170
+ Layer.provide(Snowflake.layerGenerator)
1171
+ )
1172
+
1173
+ /**
1174
+ * Provides SQL-backed `MessageStorage` with a custom table prefix,
1175
+ * running migrations first.
1176
+ *
1177
+ * **Details**
1178
+ *
1179
+ * Migration errors become defects. Use `layerMigrations` and `layerStorage`
1180
+ * to migrate separately.
1181
+ *
1182
+ * @stability unstable
1183
+ * @category layers
1184
+ * @since 4.0.0
1185
+ */
1186
+ export const layerWith = (options: {
1187
+ readonly prefix?: string | undefined
1188
+ }): Layer.Layer<MessageStorage.MessageStorage, never, SqlClient.SqlClient | ShardingConfig | Crypto.Crypto> =>
1189
+ layerStorage(options).pipe(
1190
+ Layer.provide(layerMigrations(options))
1191
+ )
1192
+
1193
+ /**
1194
+ * Provides SQL-backed `MessageStorage` with the `cluster` table prefix,
1195
+ * running migrations first and supplying `Snowflake.layerGenerator`.
1196
+ *
1197
+ * **Details**
1198
+ *
1199
+ * The connection needs DDL permissions. PostgreSQL takes an exclusive lock
1200
+ * on the migration history table. Use `layerWith` for a custom prefix or
1201
+ * `layerMigrations` and `layerStorage` to migrate separately.
1202
+ *
1203
+ * @stability unstable
1204
+ * @category layers
1205
+ * @since 4.0.0
1206
+ */
1207
+ export const layer: Layer.Layer<
1208
+ MessageStorage.MessageStorage,
1209
+ never,
1210
+ SqlClient.SqlClient | ShardingConfig | Crypto.Crypto
1211
+ > = layerWith({})
1212
+
1213
+ // -------------------------------------------------------------------------------------------------
1214
+ // internal
1215
+ // -------------------------------------------------------------------------------------------------
1216
+
1183
1217
  const messageKind = {
1184
1218
  "Request": 0,
1185
1219
  "AckChunk": 1,
@@ -3,10 +3,15 @@
3
3
  *
4
4
  * The SQL-backed `RunnerStorage` records runners, health flags, machine ids,
5
5
  * and shard locks so multiple processes can coordinate which runner owns each
6
- * shard. This module creates the required runner and lock tables, supports an
6
+ * shard. This module migrates the required runner and lock tables, supports an
7
7
  * optional table prefix, uses advisory locks for PostgreSQL and MySQL when
8
8
  * enabled, and provides constructors and layers for the storage service.
9
9
  *
10
+ * `layer`, `layerWith`, and `make` run the migrations before building the
11
+ * storage. To run migrations with a different connection, such as a schema
12
+ * owner in a deploy step, use `layerMigrations` there and `layerStorage` in the
13
+ * runtime.
14
+ *
10
15
  * @stability unstable
11
16
  * @since 4.0.0
12
17
  */
@@ -17,6 +22,7 @@ import * as Effect from "../Effect.ts"
17
22
  import * as Fiber from "../Fiber.ts"
18
23
  import * as Layer from "../Layer.ts"
19
24
  import * as Scope from "../Scope.ts"
25
+ import * as Migrator from "../sql/Migrator.ts"
20
26
  import * as SqlClient from "../sql/SqlClient.ts"
21
27
  import type { Connection } from "../sql/SqlConnection.ts"
22
28
  import type { SqlError } from "../sql/SqlError.ts"
@@ -41,36 +47,7 @@ const postgresLockNamespace = (prefix: string): number => {
41
47
  return hash | 0
42
48
  }
43
49
 
44
- /**
45
- * Creates a SQL-backed `RunnerStorage` implementation for registered runners and
46
- * shard locks, using the configured table prefix and advisory locks where
47
- * supported and enabled.
48
- *
49
- * **When to use**
50
- *
51
- * Use to create a SQL-backed `RunnerStorage` value directly when building
52
- * custom service or layer composition around the storage implementation.
53
- *
54
- * **Details**
55
- *
56
- * When `prefix` is omitted, `make` uses the `cluster` prefix, creating
57
- * `cluster_runners` and `cluster_locks`. PostgreSQL and MySQL use advisory
58
- * locks unless `ShardingConfig.shardLockDisableAdvisory` is enabled; other
59
- * dialects use rows in the locks table.
60
- *
61
- * **Gotchas**
62
- *
63
- * Changing `prefix` changes both generated table names, so runners using
64
- * different prefixes do not share registrations or shard locks.
65
- *
66
- * @see {@link layer} for the default SQL-backed storage layer
67
- * @see {@link layerWith} for a SQL-backed storage layer with a custom table prefix
68
- *
69
- * @stability unstable
70
- * @category constructors
71
- * @since 4.0.0
72
- */
73
- export const make = Effect.fnUntraced(function*(options: {
50
+ const makeStorage = Effect.fnUntraced(function*(options: {
74
51
  readonly prefix?: string | undefined
75
52
  }) {
76
53
  const config = yield* ShardingConfig.ShardingConfig
@@ -183,99 +160,9 @@ export const make = Effect.fnUntraced(function*(options: {
183
160
  const runnersTable = table("runners")
184
161
  const runnersTableSql = sql(runnersTable)
185
162
 
186
- yield* sql.onDialectOrElse({
187
- mssql: () =>
188
- sql`
189
- IF OBJECT_ID(N'${runnersTableSql}', N'U') IS NULL
190
- CREATE TABLE ${runnersTableSql} (
191
- machine_id INT IDENTITY PRIMARY KEY,
192
- address VARCHAR(255) NOT NULL,
193
- runner TEXT NOT NULL,
194
- healthy BIT NOT NULL DEFAULT 1,
195
- last_heartbeat DATETIME NOT NULL DEFAULT GETDATE(),
196
- UNIQUE(address)
197
- )
198
- `,
199
- mysql: () =>
200
- sql`
201
- CREATE TABLE IF NOT EXISTS ${runnersTableSql} (
202
- machine_id INT AUTO_INCREMENT PRIMARY KEY,
203
- address VARCHAR(255) NOT NULL,
204
- runner TEXT NOT NULL,
205
- healthy BOOLEAN NOT NULL DEFAULT TRUE,
206
- last_heartbeat DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
207
- UNIQUE(address)
208
- )
209
- `,
210
- pg: () =>
211
- sql`
212
- CREATE TABLE IF NOT EXISTS ${runnersTableSql} (
213
- machine_id SERIAL PRIMARY KEY,
214
- address VARCHAR(255) NOT NULL,
215
- runner TEXT NOT NULL,
216
- healthy BOOLEAN NOT NULL DEFAULT TRUE,
217
- last_heartbeat TIMESTAMP NOT NULL DEFAULT NOW(),
218
- UNIQUE(address)
219
- )
220
- `,
221
- orElse: () =>
222
- // sqlite
223
- sql`
224
- CREATE TABLE IF NOT EXISTS ${runnersTableSql} (
225
- machine_id INTEGER PRIMARY KEY AUTOINCREMENT,
226
- address TEXT NOT NULL,
227
- runner TEXT NOT NULL,
228
- healthy INTEGER NOT NULL DEFAULT 1,
229
- last_heartbeat DATETIME NOT NULL DEFAULT (CURRENT_TIMESTAMP),
230
- UNIQUE(address)
231
- )
232
- `
233
- })
234
-
235
163
  const locksTable = table("locks")
236
164
  const locksTableSql = sql(locksTable)
237
165
 
238
- yield* sql.onDialectOrElse({
239
- mssql: () =>
240
- sql`
241
- IF OBJECT_ID(N'${locksTableSql}', N'U') IS NULL
242
- CREATE TABLE ${locksTableSql} (
243
- shard_id VARCHAR(50) PRIMARY KEY,
244
- address VARCHAR(255) NOT NULL,
245
- acquired_at DATETIME NOT NULL
246
- )
247
- `,
248
- mysql: () =>
249
- disableAdvisoryLocks ?
250
- sql`
251
- CREATE TABLE IF NOT EXISTS ${locksTableSql} (
252
- shard_id VARCHAR(50) PRIMARY KEY,
253
- address VARCHAR(255) NOT NULL,
254
- acquired_at DATETIME NOT NULL
255
- )
256
- ` :
257
- Effect.void,
258
- pg: () =>
259
- disableAdvisoryLocks ?
260
- sql`
261
- CREATE TABLE IF NOT EXISTS ${locksTableSql} (
262
- shard_id VARCHAR(50) PRIMARY KEY,
263
- address VARCHAR(255) NOT NULL,
264
- acquired_at TIMESTAMP NOT NULL
265
- )
266
- ` :
267
- Effect.void,
268
- orElse: () =>
269
- // sqlite
270
- sql`
271
- CREATE TABLE IF NOT EXISTS ${locksTableSql} (
272
- shard_id TEXT PRIMARY KEY,
273
- address TEXT NOT NULL,
274
- acquired_at DATETIME NOT NULL
275
- )
276
- `
277
- })
278
-
279
166
  const sqlNowString = sql.onDialectOrElse({
280
167
  pg: () => "NOW()",
281
168
  mysql: () => "NOW()",
@@ -765,20 +652,213 @@ export const make = Effect.fnUntraced(function*(options: {
765
652
  }, withTracerDisabled)
766
653
 
767
654
  /**
768
- * Layer that provides SQL-backed `RunnerStorage` using the default table prefix.
655
+ * Creates a SQL-backed `RunnerStorage` implementation for registered runners and
656
+ * shard locks, using the configured table prefix and advisory locks where
657
+ * supported and enabled.
658
+ *
659
+ * **When to use**
660
+ *
661
+ * Use to create a SQL-backed `RunnerStorage` value directly when building
662
+ * custom service or layer composition around the storage implementation.
663
+ *
664
+ * **Details**
665
+ *
666
+ * `make` first runs the runner storage migrations, so the connection needs
667
+ * permission to create tables. When `prefix` is omitted, `make` uses the
668
+ * `cluster` prefix, creating `cluster_runners`, `cluster_locks`, and the
669
+ * `cluster_runner_migrations` history table. PostgreSQL and MySQL use advisory
670
+ * locks unless `ShardingConfig.shardLockDisableAdvisory` is enabled; other
671
+ * dialects use rows in the locks table.
672
+ *
673
+ * **Gotchas**
674
+ *
675
+ * Changing `prefix` changes all generated table names, so runners using
676
+ * different prefixes do not share registrations or shard locks.
677
+ *
678
+ * @see {@link layer} for the default SQL-backed storage layer
679
+ * @see {@link layerWith} for a SQL-backed storage layer with a custom table prefix
680
+ * @see {@link layerStorage} for a storage layer that does not run migrations
769
681
  *
770
682
  * @stability unstable
771
- * @category layers
683
+ * @category constructors
772
684
  * @since 4.0.0
773
685
  */
774
- export const layer: Layer.Layer<
775
- RunnerStorage.RunnerStorage,
686
+ export const make = (options: {
687
+ readonly prefix?: string | undefined
688
+ }): Effect.Effect<
689
+ RunnerStorage.RunnerStorage["Service"],
776
690
  SqlError,
777
- SqlClient.SqlClient | ShardingConfig.ShardingConfig
778
- > = Layer.effect(RunnerStorage.RunnerStorage)(make({}))
691
+ SqlClient.SqlClient | ShardingConfig.ShardingConfig | Scope.Scope
692
+ > => Effect.andThen(runRunnerMigrations(options), makeStorage(options))
779
693
 
780
694
  /**
781
- * Layer that provides SQL-backed `RunnerStorage` using a custom table prefix.
695
+ * Migration loader for the SQL runner storage tables.
696
+ *
697
+ * **Details**
698
+ *
699
+ * History is recorded in `<prefix>_runner_migrations`; the default
700
+ * prefix is `cluster`. The locks table is created regardless of advisory lock settings.
701
+ *
702
+ * @stability unstable
703
+ * @category migrations
704
+ * @since 4.1.0
705
+ */
706
+ export const migrations = (options: {
707
+ readonly prefix?: string | undefined
708
+ }): Migrator.Loader => {
709
+ const prefix = options.prefix ?? "cluster"
710
+ const table = (name: string) => `${prefix}_${name}`
711
+ const runnersTable = table("runners")
712
+ const locksTable = table("locks")
713
+
714
+ return Migrator.fromRecord({
715
+ // Existing deployments may have these tables but no migration history.
716
+ "0001_create_tables": Effect.gen(function*() {
717
+ const sql = (yield* SqlClient.SqlClient).withoutTransforms()
718
+ const runnersTableSql = sql(runnersTable)
719
+ const locksTableSql = sql(locksTable)
720
+
721
+ yield* sql.onDialectOrElse({
722
+ mssql: () =>
723
+ sql`
724
+ IF OBJECT_ID(N'${runnersTableSql}', N'U') IS NULL
725
+ CREATE TABLE ${runnersTableSql} (
726
+ machine_id INT IDENTITY PRIMARY KEY,
727
+ address VARCHAR(255) NOT NULL,
728
+ runner TEXT NOT NULL,
729
+ healthy BIT NOT NULL DEFAULT 1,
730
+ last_heartbeat DATETIME NOT NULL DEFAULT GETDATE(),
731
+ UNIQUE(address)
732
+ )
733
+ `,
734
+ mysql: () =>
735
+ sql`
736
+ CREATE TABLE IF NOT EXISTS ${runnersTableSql} (
737
+ machine_id INT AUTO_INCREMENT PRIMARY KEY,
738
+ address VARCHAR(255) NOT NULL,
739
+ runner TEXT NOT NULL,
740
+ healthy BOOLEAN NOT NULL DEFAULT TRUE,
741
+ last_heartbeat DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
742
+ UNIQUE(address)
743
+ )
744
+ `,
745
+ pg: () =>
746
+ sql`
747
+ CREATE TABLE IF NOT EXISTS ${runnersTableSql} (
748
+ machine_id SERIAL PRIMARY KEY,
749
+ address VARCHAR(255) NOT NULL,
750
+ runner TEXT NOT NULL,
751
+ healthy BOOLEAN NOT NULL DEFAULT TRUE,
752
+ last_heartbeat TIMESTAMP NOT NULL DEFAULT NOW(),
753
+ UNIQUE(address)
754
+ )
755
+ `,
756
+ orElse: () =>
757
+ // sqlite
758
+ sql`
759
+ CREATE TABLE IF NOT EXISTS ${runnersTableSql} (
760
+ machine_id INTEGER PRIMARY KEY AUTOINCREMENT,
761
+ address TEXT NOT NULL,
762
+ runner TEXT NOT NULL,
763
+ healthy INTEGER NOT NULL DEFAULT 1,
764
+ last_heartbeat DATETIME NOT NULL DEFAULT (CURRENT_TIMESTAMP),
765
+ UNIQUE(address)
766
+ )
767
+ `
768
+ })
769
+
770
+ yield* sql.onDialectOrElse({
771
+ mssql: () =>
772
+ sql`
773
+ IF OBJECT_ID(N'${locksTableSql}', N'U') IS NULL
774
+ CREATE TABLE ${locksTableSql} (
775
+ shard_id VARCHAR(50) PRIMARY KEY,
776
+ address VARCHAR(255) NOT NULL,
777
+ acquired_at DATETIME NOT NULL
778
+ )
779
+ `,
780
+ mysql: () =>
781
+ sql`
782
+ CREATE TABLE IF NOT EXISTS ${locksTableSql} (
783
+ shard_id VARCHAR(50) PRIMARY KEY,
784
+ address VARCHAR(255) NOT NULL,
785
+ acquired_at DATETIME NOT NULL
786
+ )
787
+ `,
788
+ pg: () =>
789
+ sql`
790
+ CREATE TABLE IF NOT EXISTS ${locksTableSql} (
791
+ shard_id VARCHAR(50) PRIMARY KEY,
792
+ address VARCHAR(255) NOT NULL,
793
+ acquired_at TIMESTAMP NOT NULL
794
+ )
795
+ `,
796
+ orElse: () =>
797
+ // sqlite
798
+ sql`
799
+ CREATE TABLE IF NOT EXISTS ${locksTableSql} (
800
+ shard_id TEXT PRIMARY KEY,
801
+ address TEXT NOT NULL,
802
+ acquired_at DATETIME NOT NULL
803
+ )
804
+ `
805
+ })
806
+ })
807
+ })
808
+ }
809
+
810
+ const runRunnerMigrations = (options: {
811
+ readonly prefix?: string | undefined
812
+ }): Effect.Effect<void, never, SqlClient.SqlClient> =>
813
+ Migrator.make({})({
814
+ loader: migrations(options),
815
+ // Message and runner migration ids overlap, so keep separate histories.
816
+ table: `${options.prefix ?? "cluster"}_runner_migrations`
817
+ }).pipe(Effect.asVoid, Effect.orDie)
818
+
819
+ /**
820
+ * Runs the SQL runner storage migrations without providing storage.
821
+ *
822
+ * **Details**
823
+ *
824
+ * Use an owner connection in a deploy step, then use `layerStorage` with a
825
+ * DML-only runtime connection. History is recorded in `<prefix>_runner_migrations`.
826
+ * Migration errors become defects.
827
+ * This layer does not require `ShardingConfig`.
828
+ *
829
+ * @stability unstable
830
+ * @category layers
831
+ * @since 4.1.0
832
+ */
833
+ export const layerMigrations = (options: {
834
+ readonly prefix?: string | undefined
835
+ }): Layer.Layer<never, never, SqlClient.SqlClient> => Layer.effectDiscard(runRunnerMigrations(options))
836
+
837
+ /**
838
+ * Provides SQL-backed `RunnerStorage` without DDL or startup schema checks.
839
+ *
840
+ * **Details**
841
+ *
842
+ * Run `layerMigrations` separately before using this layer.
843
+ *
844
+ * @stability unstable
845
+ * @category layers
846
+ * @since 4.1.0
847
+ */
848
+ export const layerStorage = (options: {
849
+ readonly prefix?: string | undefined
850
+ }): Layer.Layer<RunnerStorage.RunnerStorage, never, SqlClient.SqlClient | ShardingConfig.ShardingConfig> =>
851
+ Layer.effect(RunnerStorage.RunnerStorage)(makeStorage(options))
852
+
853
+ /**
854
+ * Provides SQL-backed `RunnerStorage` with a custom table prefix,
855
+ * running migrations first.
856
+ *
857
+ * **Details**
858
+ *
859
+ * The connection needs DDL permissions. PostgreSQL takes an exclusive lock
860
+ * on the migration history table. Use `layerMigrations` and `layerStorage`
861
+ * to migrate separately.
782
862
  *
783
863
  * @stability unstable
784
864
  * @category layers
@@ -788,3 +868,19 @@ export const layerWith = (options: {
788
868
  readonly prefix?: string | undefined
789
869
  }): Layer.Layer<RunnerStorage.RunnerStorage, SqlError, SqlClient.SqlClient | ShardingConfig.ShardingConfig> =>
790
870
  Layer.effect(RunnerStorage.RunnerStorage)(make(options))
871
+
872
+ /**
873
+ * Layer that provides SQL-backed `RunnerStorage` using the default table prefix,
874
+ * running the runner storage migrations first.
875
+ *
876
+ * @see {@link layerWith} for the same layer with a custom table prefix
877
+ *
878
+ * @stability unstable
879
+ * @category layers
880
+ * @since 4.0.0
881
+ */
882
+ export const layer: Layer.Layer<
883
+ RunnerStorage.RunnerStorage,
884
+ SqlError,
885
+ SqlClient.SqlClient | ShardingConfig.ShardingConfig
886
+ > = layerWith({})