effect 4.0.6 → 4.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (480) hide show
  1. package/dist/Arbitrary.d.ts +10 -2
  2. package/dist/Arbitrary.d.ts.map +1 -1
  3. package/dist/Arbitrary.js +2 -1
  4. package/dist/Arbitrary.js.map +1 -1
  5. package/dist/Channel.d.ts.map +1 -1
  6. package/dist/Channel.js +21 -6
  7. package/dist/Channel.js.map +1 -1
  8. package/dist/Data.d.ts +54 -235
  9. package/dist/Data.d.ts.map +1 -1
  10. package/dist/Data.js.map +1 -1
  11. package/dist/Effect.d.ts +1 -1
  12. package/dist/Effect.js +1 -1
  13. package/dist/Equal.d.ts.map +1 -1
  14. package/dist/Equal.js +8 -1
  15. package/dist/Equal.js.map +1 -1
  16. package/dist/Exit.d.ts +3 -3
  17. package/dist/Exit.d.ts.map +1 -1
  18. package/dist/Exit.js.map +1 -1
  19. package/dist/Formatter.d.ts.map +1 -1
  20. package/dist/Formatter.js +27 -13
  21. package/dist/Formatter.js.map +1 -1
  22. package/dist/Hash.d.ts.map +1 -1
  23. package/dist/Hash.js +4 -1
  24. package/dist/Hash.js.map +1 -1
  25. package/dist/JsonPatch.js +4 -0
  26. package/dist/JsonPatch.js.map +1 -1
  27. package/dist/JsonSchema.d.ts.map +1 -1
  28. package/dist/JsonSchema.js +13 -40
  29. package/dist/JsonSchema.js.map +1 -1
  30. package/dist/Metric.d.ts +3 -3
  31. package/dist/MutableList.d.ts +5 -2
  32. package/dist/MutableList.d.ts.map +1 -1
  33. package/dist/MutableList.js +7 -5
  34. package/dist/MutableList.js.map +1 -1
  35. package/dist/MutableRef.d.ts.map +1 -1
  36. package/dist/MutableRef.js +7 -0
  37. package/dist/MutableRef.js.map +1 -1
  38. package/dist/PartitionedSemaphore.d.ts +2 -1
  39. package/dist/PartitionedSemaphore.d.ts.map +1 -1
  40. package/dist/PartitionedSemaphore.js +22 -12
  41. package/dist/PartitionedSemaphore.js.map +1 -1
  42. package/dist/Pool.d.ts.map +1 -1
  43. package/dist/Pool.js +77 -27
  44. package/dist/Pool.js.map +1 -1
  45. package/dist/PubSub.d.ts.map +1 -1
  46. package/dist/PubSub.js +5 -6
  47. package/dist/PubSub.js.map +1 -1
  48. package/dist/Ref.d.ts.map +1 -1
  49. package/dist/Ref.js +8 -0
  50. package/dist/Ref.js.map +1 -1
  51. package/dist/Schedule.js +1 -1
  52. package/dist/Schedule.js.map +1 -1
  53. package/dist/Schema.d.ts +24 -8
  54. package/dist/Schema.d.ts.map +1 -1
  55. package/dist/Schema.js +37 -28
  56. package/dist/Schema.js.map +1 -1
  57. package/dist/SchemaAST.d.ts +4 -2
  58. package/dist/SchemaAST.d.ts.map +1 -1
  59. package/dist/SchemaAST.js +14 -17
  60. package/dist/SchemaAST.js.map +1 -1
  61. package/dist/SchemaParser.d.ts.map +1 -1
  62. package/dist/SchemaParser.js +48 -22
  63. package/dist/SchemaParser.js.map +1 -1
  64. package/dist/SchemaRepresentation.d.ts +19 -10
  65. package/dist/SchemaRepresentation.d.ts.map +1 -1
  66. package/dist/SchemaRepresentation.js +23 -13
  67. package/dist/SchemaRepresentation.js.map +1 -1
  68. package/dist/SchemaTransformation.d.ts +4 -1
  69. package/dist/SchemaTransformation.d.ts.map +1 -1
  70. package/dist/SchemaTransformation.js +9 -2
  71. package/dist/SchemaTransformation.js.map +1 -1
  72. package/dist/Semaphore.d.ts.map +1 -1
  73. package/dist/Semaphore.js +54 -35
  74. package/dist/Semaphore.js.map +1 -1
  75. package/dist/Sink.d.ts.map +1 -1
  76. package/dist/Sink.js +7 -2
  77. package/dist/Sink.js.map +1 -1
  78. package/dist/Stream.d.ts.map +1 -1
  79. package/dist/Stream.js +22 -10
  80. package/dist/Stream.js.map +1 -1
  81. package/dist/String.d.ts +3 -0
  82. package/dist/String.d.ts.map +1 -1
  83. package/dist/String.js +3 -0
  84. package/dist/String.js.map +1 -1
  85. package/dist/Tracer.d.ts +11 -1
  86. package/dist/Tracer.d.ts.map +1 -1
  87. package/dist/Tracer.js +6 -1
  88. package/dist/Tracer.js.map +1 -1
  89. package/dist/ai/LanguageModel.d.ts.map +1 -1
  90. package/dist/ai/LanguageModel.js +9 -0
  91. package/dist/ai/LanguageModel.js.map +1 -1
  92. package/dist/ai/McpSchema.d.ts +110 -110
  93. package/dist/ai/McpSchema.d.ts.map +1 -1
  94. package/dist/ai/McpServer.d.ts.map +1 -1
  95. package/dist/ai/McpServer.js +21 -15
  96. package/dist/ai/McpServer.js.map +1 -1
  97. package/dist/ai/Prompt.d.ts +52 -0
  98. package/dist/ai/Prompt.d.ts.map +1 -1
  99. package/dist/ai/Prompt.js +38 -0
  100. package/dist/ai/Prompt.js.map +1 -1
  101. package/dist/ai/Response.d.ts +16 -3
  102. package/dist/ai/Response.d.ts.map +1 -1
  103. package/dist/ai/Response.js +4 -0
  104. package/dist/ai/Response.js.map +1 -1
  105. package/dist/ai/Tool.d.ts +24 -0
  106. package/dist/ai/Tool.d.ts.map +1 -1
  107. package/dist/ai/Tool.js +5 -2
  108. package/dist/ai/Tool.js.map +1 -1
  109. package/dist/ai/Toolkit.d.ts.map +1 -1
  110. package/dist/ai/Toolkit.js +8 -1
  111. package/dist/ai/Toolkit.js.map +1 -1
  112. package/dist/cli/Argument.d.ts +15 -0
  113. package/dist/cli/Argument.d.ts.map +1 -1
  114. package/dist/cli/Argument.js +5 -0
  115. package/dist/cli/Argument.js.map +1 -1
  116. package/dist/cli/CliError.d.ts +78 -0
  117. package/dist/cli/CliError.d.ts.map +1 -1
  118. package/dist/cli/CliError.js +65 -3
  119. package/dist/cli/CliError.js.map +1 -1
  120. package/dist/cli/CliOutput.d.ts +155 -6
  121. package/dist/cli/CliOutput.d.ts.map +1 -1
  122. package/dist/cli/CliOutput.js +62 -6
  123. package/dist/cli/CliOutput.js.map +1 -1
  124. package/dist/cli/Command.d.ts +24 -16
  125. package/dist/cli/Command.d.ts.map +1 -1
  126. package/dist/cli/Command.js +59 -29
  127. package/dist/cli/Command.js.map +1 -1
  128. package/dist/cli/Completions.d.ts +58 -0
  129. package/dist/cli/Completions.d.ts.map +1 -1
  130. package/dist/cli/Completions.js +49 -9
  131. package/dist/cli/Completions.js.map +1 -1
  132. package/dist/cli/Flag.d.ts +15 -0
  133. package/dist/cli/Flag.d.ts.map +1 -1
  134. package/dist/cli/Flag.js +5 -0
  135. package/dist/cli/Flag.js.map +1 -1
  136. package/dist/cli/GlobalFlag.d.ts.map +1 -1
  137. package/dist/cli/GlobalFlag.js +15 -7
  138. package/dist/cli/GlobalFlag.js.map +1 -1
  139. package/dist/cli/Param.d.ts +9 -0
  140. package/dist/cli/Param.d.ts.map +1 -1
  141. package/dist/cli/Param.js +21 -2
  142. package/dist/cli/Param.js.map +1 -1
  143. package/dist/cli/TerminalCapabilities.d.ts +3 -2
  144. package/dist/cli/TerminalCapabilities.d.ts.map +1 -1
  145. package/dist/cli/TerminalCapabilities.js +3 -1
  146. package/dist/cli/TerminalCapabilities.js.map +1 -1
  147. package/dist/cli/internal/completions/bash.js +73 -27
  148. package/dist/cli/internal/completions/bash.js.map +1 -1
  149. package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
  150. package/dist/cluster/ClusterWorkflowEngine.js +45 -10
  151. package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
  152. package/dist/cluster/MessageStorage.d.ts +23 -45
  153. package/dist/cluster/MessageStorage.d.ts.map +1 -1
  154. package/dist/cluster/MessageStorage.js +6 -7
  155. package/dist/cluster/MessageStorage.js.map +1 -1
  156. package/dist/cluster/Sharding.d.ts.map +1 -1
  157. package/dist/cluster/Sharding.js +61 -21
  158. package/dist/cluster/Sharding.js.map +1 -1
  159. package/dist/cluster/ShardingConfig.d.ts +10 -0
  160. package/dist/cluster/ShardingConfig.d.ts.map +1 -1
  161. package/dist/cluster/ShardingConfig.js.map +1 -1
  162. package/dist/cluster/Snowflake.d.ts.map +1 -1
  163. package/dist/cluster/Snowflake.js +3 -7
  164. package/dist/cluster/Snowflake.js.map +1 -1
  165. package/dist/cluster/SqlRunnerStorage.d.ts.map +1 -1
  166. package/dist/cluster/SqlRunnerStorage.js +87 -39
  167. package/dist/cluster/SqlRunnerStorage.js.map +1 -1
  168. package/dist/cluster/internal/entityManager.js +54 -20
  169. package/dist/cluster/internal/entityManager.js.map +1 -1
  170. package/dist/devtools/DevToolsClient.d.ts.map +1 -1
  171. package/dist/devtools/DevToolsClient.js +2 -0
  172. package/dist/devtools/DevToolsClient.js.map +1 -1
  173. package/dist/encoding/Base64.js +36 -0
  174. package/dist/encoding/Base64.js.map +1 -1
  175. package/dist/encoding/Sse.d.ts.map +1 -1
  176. package/dist/encoding/Sse.js +3 -3
  177. package/dist/encoding/Sse.js.map +1 -1
  178. package/dist/encoding/Toml.d.ts.map +1 -1
  179. package/dist/encoding/Toml.js +21 -16
  180. package/dist/encoding/Toml.js.map +1 -1
  181. package/dist/eventlog/SqlEventJournal.d.ts.map +1 -1
  182. package/dist/eventlog/SqlEventJournal.js +47 -27
  183. package/dist/eventlog/SqlEventJournal.js.map +1 -1
  184. package/dist/eventlog/internal/conflicts.d.ts +0 -1
  185. package/dist/eventlog/internal/conflicts.d.ts.map +1 -1
  186. package/dist/eventlog/internal/conflicts.js +0 -3
  187. package/dist/eventlog/internal/conflicts.js.map +1 -1
  188. package/dist/http/Cookies.d.ts.map +1 -1
  189. package/dist/http/Cookies.js +10 -9
  190. package/dist/http/Cookies.js.map +1 -1
  191. package/dist/http/HttpClient.d.ts +423 -0
  192. package/dist/http/HttpClient.d.ts.map +1 -1
  193. package/dist/http/HttpClient.js +231 -7
  194. package/dist/http/HttpClient.js.map +1 -1
  195. package/dist/http/HttpClientError.d.ts +8 -1
  196. package/dist/http/HttpClientError.d.ts.map +1 -1
  197. package/dist/http/HttpClientError.js +37 -1
  198. package/dist/http/HttpClientError.js.map +1 -1
  199. package/dist/http/HttpClientRequest.d.ts.map +1 -1
  200. package/dist/http/HttpClientRequest.js +1 -1
  201. package/dist/http/HttpClientRequest.js.map +1 -1
  202. package/dist/http/HttpMiddleware.d.ts +1 -1
  203. package/dist/http/HttpMiddleware.d.ts.map +1 -1
  204. package/dist/http/HttpMiddleware.js +14 -16
  205. package/dist/http/HttpMiddleware.js.map +1 -1
  206. package/dist/http/HttpRouter.d.ts.map +1 -1
  207. package/dist/http/HttpRouter.js +2 -1
  208. package/dist/http/HttpRouter.js.map +1 -1
  209. package/dist/http/HttpServerError.js +2 -2
  210. package/dist/http/HttpServerError.js.map +1 -1
  211. package/dist/http/HttpServerRequest.d.ts +6 -1
  212. package/dist/http/HttpServerRequest.d.ts.map +1 -1
  213. package/dist/http/HttpServerRequest.js +73 -10
  214. package/dist/http/HttpServerRequest.js.map +1 -1
  215. package/dist/http/HttpStaticServer.d.ts.map +1 -1
  216. package/dist/http/HttpStaticServer.js +48 -21
  217. package/dist/http/HttpStaticServer.js.map +1 -1
  218. package/dist/http/MultipartParser/internal/contentType.js +3 -3
  219. package/dist/http/UrlParams.d.ts +3 -1
  220. package/dist/http/UrlParams.d.ts.map +1 -1
  221. package/dist/http/UrlParams.js +4 -2
  222. package/dist/http/UrlParams.js.map +1 -1
  223. package/dist/http/internal/compression.js +4 -5
  224. package/dist/http/internal/compression.js.map +1 -1
  225. package/dist/http/internal/decompression.js +3 -0
  226. package/dist/http/internal/decompression.js.map +1 -1
  227. package/dist/http/internal/httpBody.js +8 -1
  228. package/dist/http/internal/httpBody.js.map +1 -1
  229. package/dist/http/internal/urlParams.js +25 -0
  230. package/dist/http/internal/urlParams.js.map +1 -1
  231. package/dist/http-api/HttpApi.d.ts +3 -6
  232. package/dist/http-api/HttpApi.d.ts.map +1 -1
  233. package/dist/http-api/HttpApi.js +3 -6
  234. package/dist/http-api/HttpApi.js.map +1 -1
  235. package/dist/http-api/HttpApiBuilder.d.ts.map +1 -1
  236. package/dist/http-api/HttpApiBuilder.js +27 -11
  237. package/dist/http-api/HttpApiBuilder.js.map +1 -1
  238. package/dist/http-api/HttpApiClient.d.ts +77 -7
  239. package/dist/http-api/HttpApiClient.d.ts.map +1 -1
  240. package/dist/http-api/HttpApiClient.js +142 -44
  241. package/dist/http-api/HttpApiClient.js.map +1 -1
  242. package/dist/http-api/HttpApiEndpoint.d.ts +24 -7
  243. package/dist/http-api/HttpApiEndpoint.d.ts.map +1 -1
  244. package/dist/http-api/HttpApiEndpoint.js +109 -27
  245. package/dist/http-api/HttpApiEndpoint.js.map +1 -1
  246. package/dist/http-api/HttpApiSchema.d.ts +76 -29
  247. package/dist/http-api/HttpApiSchema.d.ts.map +1 -1
  248. package/dist/http-api/HttpApiSchema.js +70 -59
  249. package/dist/http-api/HttpApiSchema.js.map +1 -1
  250. package/dist/http-api/HttpApiTest.d.ts.map +1 -1
  251. package/dist/http-api/HttpApiTest.js +3 -2
  252. package/dist/http-api/HttpApiTest.js.map +1 -1
  253. package/dist/http-api/OpenApi.d.ts.map +1 -1
  254. package/dist/http-api/OpenApi.js +25 -16
  255. package/dist/http-api/OpenApi.js.map +1 -1
  256. package/dist/http-api/internal/toCodecHttpProperties.d.ts +2 -0
  257. package/dist/http-api/internal/toCodecHttpProperties.d.ts.map +1 -0
  258. package/dist/http-api/internal/toCodecHttpProperties.js +38 -0
  259. package/dist/http-api/internal/toCodecHttpProperties.js.map +1 -0
  260. package/dist/internal/arbitrary/runner.d.ts.map +1 -1
  261. package/dist/internal/arbitrary/runner.js +120 -44
  262. package/dist/internal/arbitrary/runner.js.map +1 -1
  263. package/dist/internal/core.js +2 -0
  264. package/dist/internal/core.js.map +1 -1
  265. package/dist/internal/effect.js +21 -13
  266. package/dist/internal/effect.js.map +1 -1
  267. package/dist/internal/equal.js +14 -0
  268. package/dist/internal/equal.js.map +1 -1
  269. package/dist/internal/jsonSchema.d.ts +2 -0
  270. package/dist/internal/jsonSchema.d.ts.map +1 -0
  271. package/dist/internal/jsonSchema.js +28 -0
  272. package/dist/internal/jsonSchema.js.map +1 -0
  273. package/dist/internal/matcher.js +1 -1
  274. package/dist/internal/matcher.js.map +1 -1
  275. package/dist/internal/schema/compilerRegistry.js +4 -1
  276. package/dist/internal/schema/compilerRegistry.js.map +1 -1
  277. package/dist/internal/schema/content.d.ts +2 -0
  278. package/dist/internal/schema/content.d.ts.map +1 -0
  279. package/dist/internal/schema/content.js +13 -0
  280. package/dist/internal/schema/content.js.map +1 -0
  281. package/dist/internal/schema/fromJsonSchemaDocument.js +173 -185
  282. package/dist/internal/schema/fromJsonSchemaDocument.js.map +1 -1
  283. package/dist/internal/schema/fromRepresentation.js +2 -1
  284. package/dist/internal/schema/fromRepresentation.js.map +1 -1
  285. package/dist/internal/schema/standardSchema.js +8 -2
  286. package/dist/internal/schema/standardSchema.js.map +1 -1
  287. package/dist/internal/schema/toCodeDocument.js +3 -3
  288. package/dist/internal/schema/toCodeDocument.js.map +1 -1
  289. package/dist/internal/schema/toCodec.js +21 -24
  290. package/dist/internal/schema/toCodec.js.map +1 -1
  291. package/dist/internal/schema/toJsonSchemaDocument.js +205 -140
  292. package/dist/internal/schema/toJsonSchemaDocument.js.map +1 -1
  293. package/dist/internal/schema/toRepresentation.js +107 -129
  294. package/dist/internal/schema/toRepresentation.js.map +1 -1
  295. package/dist/internal/sql.d.ts +2 -0
  296. package/dist/internal/sql.d.ts.map +1 -0
  297. package/dist/internal/sql.js +13 -0
  298. package/dist/internal/sql.js.map +1 -0
  299. package/dist/internal/version.js +1 -1
  300. package/dist/observability/OtlpProxy.d.ts +154 -0
  301. package/dist/observability/OtlpProxy.d.ts.map +1 -0
  302. package/dist/observability/OtlpProxy.js +235 -0
  303. package/dist/observability/OtlpProxy.js.map +1 -0
  304. package/dist/observability/OtlpTracer.d.ts.map +1 -1
  305. package/dist/observability/OtlpTracer.js +4 -0
  306. package/dist/observability/OtlpTracer.js.map +1 -1
  307. package/dist/observability/index.d.ts +5 -0
  308. package/dist/observability/index.d.ts.map +1 -1
  309. package/dist/observability/index.js +5 -0
  310. package/dist/observability/index.js.map +1 -1
  311. package/dist/persistence/CircuitBreaker.d.ts +897 -0
  312. package/dist/persistence/CircuitBreaker.d.ts.map +1 -0
  313. package/dist/persistence/CircuitBreaker.js +1165 -0
  314. package/dist/persistence/CircuitBreaker.js.map +1 -0
  315. package/dist/persistence/Redis.d.ts +78 -2
  316. package/dist/persistence/Redis.d.ts.map +1 -1
  317. package/dist/persistence/Redis.js +62 -7
  318. package/dist/persistence/Redis.js.map +1 -1
  319. package/dist/persistence/index.d.ts +5 -0
  320. package/dist/persistence/index.d.ts.map +1 -1
  321. package/dist/persistence/index.js +5 -0
  322. package/dist/persistence/index.js.map +1 -1
  323. package/dist/process/ChildProcess.d.ts +30 -4
  324. package/dist/process/ChildProcess.d.ts.map +1 -1
  325. package/dist/process/ChildProcess.js.map +1 -1
  326. package/dist/process/ChildProcessSpawner.d.ts +30 -0
  327. package/dist/process/ChildProcessSpawner.d.ts.map +1 -1
  328. package/dist/process/ChildProcessSpawner.js +5 -2
  329. package/dist/process/ChildProcessSpawner.js.map +1 -1
  330. package/dist/reactivity/AsyncResult.d.ts +1 -1
  331. package/dist/reactivity/AsyncResult.d.ts.map +1 -1
  332. package/dist/rpc/RpcClient.d.ts.map +1 -1
  333. package/dist/rpc/RpcClient.js +9 -8
  334. package/dist/rpc/RpcClient.js.map +1 -1
  335. package/dist/rpc/RpcSerialization.d.ts +14 -0
  336. package/dist/rpc/RpcSerialization.d.ts.map +1 -1
  337. package/dist/rpc/RpcSerialization.js +20 -8
  338. package/dist/rpc/RpcSerialization.js.map +1 -1
  339. package/dist/rpc/RpcServer.d.ts.map +1 -1
  340. package/dist/rpc/RpcServer.js +11 -1
  341. package/dist/rpc/RpcServer.js.map +1 -1
  342. package/dist/rpc/RpcTest.d.ts +1 -0
  343. package/dist/rpc/RpcTest.d.ts.map +1 -1
  344. package/dist/rpc/RpcTest.js +1 -0
  345. package/dist/rpc/RpcTest.js.map +1 -1
  346. package/dist/sql/Migrator.d.ts +2 -1
  347. package/dist/sql/Migrator.d.ts.map +1 -1
  348. package/dist/sql/Migrator.js +11 -8
  349. package/dist/sql/Migrator.js.map +1 -1
  350. package/dist/sql/SqlClient.d.ts +9 -4
  351. package/dist/sql/SqlClient.d.ts.map +1 -1
  352. package/dist/sql/SqlClient.js +8 -1
  353. package/dist/sql/SqlClient.js.map +1 -1
  354. package/dist/sql/SqlResolver.d.ts +4 -0
  355. package/dist/sql/SqlResolver.d.ts.map +1 -1
  356. package/dist/sql/SqlResolver.js +18 -4
  357. package/dist/sql/SqlResolver.js.map +1 -1
  358. package/dist/sql/Statement.d.ts +7 -0
  359. package/dist/sql/Statement.d.ts.map +1 -1
  360. package/dist/sql/Statement.js +21 -2
  361. package/dist/sql/Statement.js.map +1 -1
  362. package/dist/workflow/DurableDeferred.d.ts.map +1 -1
  363. package/dist/workflow/DurableDeferred.js +21 -2
  364. package/dist/workflow/DurableDeferred.js.map +1 -1
  365. package/package.json +1 -1
  366. package/src/Arbitrary.ts +10 -2
  367. package/src/Channel.ts +47 -18
  368. package/src/Data.ts +60 -265
  369. package/src/Effect.ts +1 -1
  370. package/src/Equal.ts +8 -1
  371. package/src/Exit.ts +3 -3
  372. package/src/Formatter.ts +28 -13
  373. package/src/Hash.ts +4 -1
  374. package/src/JsonPatch.ts +4 -0
  375. package/src/JsonSchema.ts +12 -40
  376. package/src/Metric.ts +3 -3
  377. package/src/MutableList.ts +7 -5
  378. package/src/MutableRef.ts +8 -1
  379. package/src/PartitionedSemaphore.ts +24 -13
  380. package/src/Pool.ts +109 -37
  381. package/src/PubSub.ts +5 -6
  382. package/src/Ref.ts +8 -0
  383. package/src/Schedule.ts +1 -1
  384. package/src/Schema.ts +48 -25
  385. package/src/SchemaAST.ts +20 -20
  386. package/src/SchemaParser.ts +51 -18
  387. package/src/SchemaRepresentation.ts +31 -34
  388. package/src/SchemaTransformation.ts +9 -2
  389. package/src/Semaphore.ts +67 -40
  390. package/src/Sink.ts +15 -2
  391. package/src/Stream.ts +33 -16
  392. package/src/String.ts +3 -0
  393. package/src/Tracer.ts +15 -1
  394. package/src/ai/LanguageModel.ts +9 -0
  395. package/src/ai/McpServer.ts +14 -13
  396. package/src/ai/Prompt.ts +65 -0
  397. package/src/ai/Response.ts +34 -9
  398. package/src/ai/Tool.ts +38 -2
  399. package/src/ai/Toolkit.ts +4 -1
  400. package/src/cli/Argument.ts +15 -0
  401. package/src/cli/CliError.ts +90 -3
  402. package/src/cli/CliOutput.ts +183 -6
  403. package/src/cli/Command.ts +53 -41
  404. package/src/cli/Completions.ts +51 -0
  405. package/src/cli/Flag.ts +15 -0
  406. package/src/cli/GlobalFlag.ts +6 -7
  407. package/src/cli/Param.ts +29 -6
  408. package/src/cli/TerminalCapabilities.ts +6 -3
  409. package/src/cli/internal/completions/bash.ts +79 -29
  410. package/src/cluster/ClusterWorkflowEngine.ts +46 -16
  411. package/src/cluster/MessageStorage.ts +19 -14
  412. package/src/cluster/Sharding.ts +83 -21
  413. package/src/cluster/ShardingConfig.ts +5 -0
  414. package/src/cluster/Snowflake.ts +3 -7
  415. package/src/cluster/SqlRunnerStorage.ts +110 -47
  416. package/src/cluster/internal/entityManager.ts +75 -22
  417. package/src/devtools/DevToolsClient.ts +2 -0
  418. package/src/encoding/Base64.ts +38 -0
  419. package/src/encoding/Sse.ts +4 -3
  420. package/src/encoding/Toml.ts +33 -16
  421. package/src/eventlog/SqlEventJournal.ts +68 -45
  422. package/src/eventlog/internal/conflicts.ts +0 -4
  423. package/src/http/Cookies.ts +10 -11
  424. package/src/http/HttpClient.ts +547 -7
  425. package/src/http/HttpClientError.ts +35 -1
  426. package/src/http/HttpClientRequest.ts +9 -1
  427. package/src/http/HttpMiddleware.ts +15 -18
  428. package/src/http/HttpRouter.ts +2 -1
  429. package/src/http/HttpServerError.ts +2 -2
  430. package/src/http/HttpServerRequest.ts +102 -16
  431. package/src/http/HttpStaticServer.ts +51 -22
  432. package/src/http/MultipartParser/internal/contentType.ts +3 -3
  433. package/src/http/UrlParams.ts +6 -1
  434. package/src/http/internal/compression.ts +4 -5
  435. package/src/http/internal/decompression.ts +6 -0
  436. package/src/http/internal/httpBody.ts +10 -2
  437. package/src/http/internal/urlParams.ts +29 -0
  438. package/src/http-api/HttpApi.ts +3 -6
  439. package/src/http-api/HttpApiBuilder.ts +45 -15
  440. package/src/http-api/HttpApiClient.ts +218 -72
  441. package/src/http-api/HttpApiEndpoint.ts +121 -30
  442. package/src/http-api/HttpApiSchema.ts +141 -48
  443. package/src/http-api/HttpApiTest.ts +3 -2
  444. package/src/http-api/OpenApi.ts +20 -17
  445. package/src/http-api/internal/toCodecHttpProperties.ts +56 -0
  446. package/src/internal/arbitrary/runner.ts +133 -36
  447. package/src/internal/core.ts +2 -0
  448. package/src/internal/effect.ts +24 -16
  449. package/src/internal/equal.ts +17 -0
  450. package/src/internal/jsonSchema.ts +27 -0
  451. package/src/internal/matcher.ts +1 -1
  452. package/src/internal/schema/compilerRegistry.ts +6 -1
  453. package/src/internal/schema/content.ts +18 -0
  454. package/src/internal/schema/fromJsonSchemaDocument.ts +228 -190
  455. package/src/internal/schema/fromRepresentation.ts +2 -1
  456. package/src/internal/schema/standardSchema.ts +2 -2
  457. package/src/internal/schema/toCodeDocument.ts +4 -4
  458. package/src/internal/schema/toCodec.ts +26 -22
  459. package/src/internal/schema/toJsonSchemaDocument.ts +189 -167
  460. package/src/internal/schema/toRepresentation.ts +122 -140
  461. package/src/internal/sql.ts +14 -0
  462. package/src/internal/version.ts +1 -1
  463. package/src/observability/OtlpProxy.ts +314 -0
  464. package/src/observability/OtlpTracer.ts +4 -0
  465. package/src/observability/index.ts +6 -0
  466. package/src/persistence/CircuitBreaker.ts +1678 -0
  467. package/src/persistence/Redis.ts +129 -8
  468. package/src/persistence/index.ts +6 -0
  469. package/src/process/ChildProcess.ts +30 -4
  470. package/src/process/ChildProcessSpawner.ts +41 -2
  471. package/src/reactivity/AsyncResult.ts +1 -1
  472. package/src/rpc/RpcClient.ts +13 -10
  473. package/src/rpc/RpcSerialization.ts +32 -9
  474. package/src/rpc/RpcServer.ts +16 -1
  475. package/src/rpc/RpcTest.ts +3 -0
  476. package/src/sql/Migrator.ts +12 -7
  477. package/src/sql/SqlClient.ts +11 -4
  478. package/src/sql/SqlResolver.ts +23 -9
  479. package/src/sql/Statement.ts +30 -2
  480. package/src/workflow/DurableDeferred.ts +23 -6
@@ -51,6 +51,10 @@ const buildFlagGroupDeclarations = (
51
51
  lines.push(``)
52
52
  }
53
53
 
54
+ // Quoting these substitutions breaks quote matching on Bash 3.2.
55
+ const removeQuotes = (variable: string): string =>
56
+ [`\\\\`, `\\"`, `\\'`].map((quote) => `${variable}=\${${variable}//${quote}/}`).join("; ")
57
+
54
58
  /**
55
59
  * Complete choices without `compgen -W`, which reparses quoted values. Escape
56
60
  * only the portion readline replaces for the active quote context.
@@ -71,9 +75,8 @@ const choicesHelper = (helperName: string, lines: Array<string>): void => {
71
75
  lines.push(` esac`)
72
76
  lines.push(``)
73
77
  lines.push(` local _prefix="$_cur" _committed="$_head"`)
74
- // Quoting these substitutions breaks quote matching on Bash 3.2.
75
- lines.push(` _prefix=\${_prefix//\\\\/}; _prefix=\${_prefix//\\"/}; _prefix=\${_prefix//\\'/}`)
76
- lines.push(` _committed=\${_committed//\\\\/}; _committed=\${_committed//\\"/}; _committed=\${_committed//\\'/}`)
78
+ lines.push(` ${removeQuotes("_prefix")}`)
79
+ lines.push(` ${removeQuotes("_committed")}`)
77
80
  lines.push(``)
78
81
  lines.push(` COMPREPLY=()`)
79
82
  lines.push(` local _choice _rest _match`)
@@ -111,30 +114,76 @@ const choicesHelper = (helperName: string, lines: Array<string>): void => {
111
114
  lines.push(``)
112
115
  }
113
116
 
114
- const choiceCompletion = (helperName: string, values: ReadonlyArray<string>): string =>
115
- `${helperName} "$cur" "$_comp_word" ${values.map((value) => `'${escapeForBash(value)}'`).join(" ")}`
117
+ interface Helpers {
118
+ readonly choices: string
119
+ readonly paths: string
120
+ }
116
121
 
117
- const flagValueCompletion = (type: Completions.FlagType, helperName: string): string | undefined => {
118
- switch (type._tag) {
119
- case "Boolean":
120
- return undefined
121
- case "Choice":
122
- return choiceCompletion(helperName, type.values)
123
- case "Path":
124
- if (type.pathType === "directory") return `COMPREPLY=( $(compgen -d -- "$cur") )`
125
- return `COMPREPLY=( $(compgen -f -- "$cur") )`
126
- default:
127
- return undefined
128
- }
122
+ /**
123
+ * Complete paths through the choice helper, one `compgen` line per candidate.
124
+ * The typed directory is kept as written so expansions in it still apply; only
125
+ * the completed name is quoted.
126
+ */
127
+ const pathsHelper = (helpers: Helpers, lines: Array<string>): void => {
128
+ lines.push(`${helpers.paths}()`)
129
+ lines.push(`{`)
130
+ lines.push(` local _kind="$1" _cur="$2" _word="$3"`)
131
+ lines.push(``)
132
+ lines.push(` local _prefix="$_cur" _committed="\${_cur%"$_word"}"`)
133
+ lines.push(` ${removeQuotes("_prefix")}`)
134
+ lines.push(` ${removeQuotes("_committed")}`)
135
+ lines.push(``)
136
+ // Track a quote the typed directory leaves open.
137
+ lines.push(` local _typed="" _dir="$_committed" _open="" _i`)
138
+ lines.push(` if [[ "$_word" == */* ]]; then`)
139
+ lines.push(` _typed="\${_word%/*}/"`)
140
+ lines.push(` _dir="\${_prefix%/*}/"`)
141
+ lines.push(` if [[ "$_cur" == "$_word" ]]; then`)
142
+ lines.push(` for ((_i = 0; _i < \${#_typed}; _i++)); do`)
143
+ lines.push(` case "$_open\${_typed:_i:1}" in`)
144
+ lines.push(` \\\\|\\"\\\\) ((_i += 1)) ;;`)
145
+ lines.push(` \\"|\\') _open="\${_typed:_i:1}" ;;`)
146
+ lines.push(` \\"\\"|\\'\\') _open="" ;;`)
147
+ lines.push(` esac`)
148
+ lines.push(` done`)
149
+ lines.push(` fi`)
150
+ lines.push(` fi`)
151
+ lines.push(``)
152
+ lines.push(` local _path _names=() _rest="\${_word#"$_typed"}"`)
153
+ lines.push(` while IFS= read -r _path; do`)
154
+ lines.push(` if [[ "$_path" == "$_dir"* ]]; then`)
155
+ lines.push(` _names+=("$_committed\${_path#"$_dir"}")`)
156
+ lines.push(` elif [[ -z "$_committed" ]]; then`)
157
+ // Bash 3.2 returns expanded paths, which replace the whole word.
158
+ lines.push(` _names+=("$_path")`)
159
+ lines.push(` _typed="" _rest="" _open=""`)
160
+ lines.push(` fi`)
161
+ lines.push(` done < <(compgen "$_kind" -- "$_prefix")`)
162
+ // Close the quote before the name so a common prefix stays balanced.
163
+ lines.push(` if [[ -n "$_open" ]]; then`)
164
+ lines.push(` _typed+="$_open"`)
165
+ lines.push(` _rest="\${_prefix##*/}"`)
166
+ lines.push(` fi`)
167
+ lines.push(``)
168
+ lines.push(` ${helpers.choices} "\${_cur%"$_word"}$_rest" "$_rest" "\${_names[@]}"`)
169
+ lines.push(` for ((_i = 0; _i < \${#COMPREPLY[@]}; _i++)); do`)
170
+ lines.push(` COMPREPLY[_i]="$_typed\${COMPREPLY[_i]}"`)
171
+ lines.push(` done`)
172
+ lines.push(`}`)
173
+ lines.push(``)
129
174
  }
130
175
 
131
- const argCompletion = (type: Completions.ArgumentType, helperName: string): string | undefined => {
176
+ const valueCompletion = (
177
+ type: Completions.FlagType | Completions.ArgumentType,
178
+ helpers: Helpers
179
+ ): string | undefined => {
132
180
  switch (type._tag) {
133
- case "Choice":
134
- return choiceCompletion(helperName, type.values)
181
+ case "Choice": {
182
+ const values = type.values.map((value) => `'${escapeForBash(value)}'`).join(" ")
183
+ return `${helpers.choices} "$cur" "$_comp_word" ${values}`
184
+ }
135
185
  case "Path":
136
- if (type.pathType === "directory") return `COMPREPLY=( $(compgen -d -- "$cur") )`
137
- return `COMPREPLY=( $(compgen -f -- "$cur") )`
186
+ return `${helpers.paths} ${type.pathType === "directory" ? "-d" : "-f"} "$cur" "$_comp_word"`
138
187
  default:
139
188
  return undefined
140
189
  }
@@ -148,7 +197,7 @@ const generateFunction = (
148
197
  descriptor: Completions.CommandDescriptor,
149
198
  parentPath: ReadonlyArray<string>,
150
199
  lines: Array<string>,
151
- helperName: string
200
+ helpers: Helpers
152
201
  ): void => {
153
202
  const currentPath = [...parentPath, descriptor.name]
154
203
  const funcName = `_${currentPath.map(sanitizeFunctionName).join("_")}`
@@ -175,7 +224,7 @@ const generateFunction = (
175
224
  for (const alias of flag.aliases) {
176
225
  longNames.push(alias.length === 1 ? `-${alias}` : `--${alias}`)
177
226
  }
178
- const completion = flagValueCompletion(flag.type, helperName)
227
+ const completion = valueCompletion(flag.type, helpers)
179
228
  if (completion) {
180
229
  lines.push(` ${longNames.join("|")})`)
181
230
  lines.push(` ${completion}`)
@@ -231,7 +280,7 @@ const generateFunction = (
231
280
 
232
281
  // Positional argument completion
233
282
  const argsWithCompletions = descriptor.arguments.flatMap((argument, index) => {
234
- const completion = argCompletion(argument.type, helperName)
283
+ const completion = valueCompletion(argument.type, helpers)
235
284
  return completion === undefined ? [] : [{ argument, completion, index }]
236
285
  })
237
286
  if (argsWithCompletions.length > 0) {
@@ -287,7 +336,7 @@ const generateFunction = (
287
336
 
288
337
  // Recurse into subcommands
289
338
  for (const sub of descriptor.subcommands) {
290
- generateFunction(sub, currentPath, lines, helperName)
339
+ generateFunction(sub, currentPath, lines, helpers)
291
340
  }
292
341
  }
293
342
 
@@ -301,7 +350,7 @@ export const generate = (
301
350
  const lines: Array<string> = []
302
351
  const safeName = sanitizeFunctionName(executableName)
303
352
  // Sanitized command names cannot contain `-`.
304
- const helperName = `_${safeName}--choices`
353
+ const helpers: Helpers = { choices: `_${safeName}--choices`, paths: `_${safeName}--paths` }
305
354
 
306
355
  lines.push(`###-begin-${escapeForBash(executableName)}-completions-###`)
307
356
  lines.push(`#`)
@@ -341,8 +390,9 @@ export const generate = (
341
390
  lines.push(`fi`)
342
391
  lines.push(``)
343
392
 
344
- choicesHelper(helperName, lines)
345
- generateFunction(descriptor, [], lines, helperName)
393
+ choicesHelper(helpers.choices, lines)
394
+ pathsHelper(helpers, lines)
395
+ generateFunction(descriptor, [], lines, helpers)
346
396
 
347
397
  lines.push(`complete -F _${safeName} ${escapeForBash(executableName)}`)
348
398
  lines.push(`###-end-${escapeForBash(executableName)}-completions-###`)
@@ -7,6 +7,7 @@
7
7
  * @stability unstable
8
8
  * @since 4.0.0
9
9
  */
10
+ import * as Cause from "../Cause.ts"
10
11
  import * as Context from "../Context.ts"
11
12
  import * as DateTime from "../DateTime.ts"
12
13
  import * as Deferred from "../Deferred.ts"
@@ -539,9 +540,26 @@ export const make = Effect.gen(function*() {
539
540
  !instance.abandoned &&
540
541
  !(suspendOnFailure && exit._tag === "Failure")
541
542
  ) {
542
- return parent && !parent.detached
543
+ const resumeParent = parent && !parent.detached
543
544
  ? ensureSuccess(sendResumeParent(parent, executionId))
544
545
  : Effect.void
546
+ if (exit._tag === "Success" || !Cause.hasInterruptsOnly(exit.cause)) {
547
+ return resumeParent
548
+ }
549
+ // `interruptUnsafe` cuts the run off without a result and
550
+ // its replay applies the interrupt. Retain the scope like a
551
+ // suspended run, so `closeRuns` supersedes it and only the
552
+ // final run's compensations observe the interrupt.
553
+ return engine.deferredResult(InterruptSignal).pipe(
554
+ Effect.flatMap((maybeExit) => {
555
+ if (Option.isNone(maybeExit)) {
556
+ return resumeParent
557
+ }
558
+ instance.suspended = true
559
+ return Effect.void
560
+ }),
561
+ Effect.orDie
562
+ )
545
563
  }
546
564
  return engine.deferredResult(InterruptSignal).pipe(
547
565
  Effect.flatMap((maybeExit) => {
@@ -797,25 +815,28 @@ export const make = Effect.gen(function*() {
797
815
  if (exit) {
798
816
  return Option.some(exit)
799
817
  }
800
- return yield* requestReply({
818
+ const requestId = yield* requestIdFor({
801
819
  workflow: instance.workflow,
802
820
  entityType: `Workflow/${instance.workflow._tag}`,
803
821
  executionId: instance.executionId,
804
822
  tag: "deferred",
805
823
  id: deferred.name
806
- }).pipe(
807
- Effect.map((reply) => {
808
- if (Option.isNone(reply)) {
809
- return Option.none<Exit.Exit<unknown, unknown>>()
810
- }
811
- const decoded = decodeDeferredWithExit(reply.value as any)
812
- return Option.some(
813
- decoded.exit._tag === "Success"
814
- ? decoded.exit.value
815
- : decoded.exit
816
- )
817
- })
818
- )
824
+ })
825
+ if (Option.isNone(requestId)) {
826
+ return Option.none<Exit.Exit<unknown, unknown>>()
827
+ }
828
+ const reply = yield* replyForRequestId(requestId.value)
829
+ if (Option.isSome(reply)) {
830
+ return Option.some(deferredReplyExit(reply.value))
831
+ }
832
+ // The first completion saved under the deferred name wins, so a
833
+ // request the owner has not processed yet already holds the result.
834
+ const [request] = yield* storage.unprocessedMessagesById([requestId.value])
835
+ if (request?.envelope._tag === "Request") {
836
+ return Option.some(decodeDeferredPayload(request.envelope.payload).exit)
837
+ }
838
+ // It was processed after the first read, so its reply is stored now.
839
+ return Option.map(yield* replyForRequestId(requestId.value), deferredReplyExit)
819
840
  })),
820
841
  Effect.retry({
821
842
  while: (e) => e._tag === "PersistenceError",
@@ -896,10 +917,14 @@ const retryPolicy = Schedule.min([
896
917
  Schedule.spaced("1 minute")
897
918
  ])
898
919
 
920
+ // A cluster abandonment means this owner can no longer complete the effect, so
921
+ // retrying it would only wait on a retired run. Re-raise it as an annotated
922
+ // interrupt, so the activation can unwind and its shard can be released.
899
923
  const ensureSuccess = <A, E, R>(effect: Effect.Effect<A, E, R>) =>
900
924
  effect.pipe(
901
925
  Effect.sandbox,
902
- Effect.retry(retryPolicy),
926
+ Effect.retry({ schedule: retryPolicy, while: (cause) => !ClusterAbandon.isCause(cause) }),
927
+ Effect.catchIf(ClusterAbandon.isCause, () => ClusterAbandon.interrupt),
903
928
  Effect.orDie
904
929
  )
905
930
 
@@ -959,6 +984,11 @@ const isFailedReply = (reply: WithExitEncoded<Workflow.ResultEncoded<any, any>>)
959
984
  reply.exit._tag === "Success" && reply.exit.value._tag === "Suspended" && reply.exit.value.failed === true
960
985
 
961
986
  const decodeDeferredWithExit = Schema.decodeSync(Schema.toCodecJson(Reply.WithExit.schema(DeferredRpc)))
987
+ const decodeDeferredPayload = Schema.decodeUnknownSync(Schema.toCodecJson(DeferredRpc.payloadSchema))
988
+ const deferredReplyExit = (reply: WithExitEncoded<Workflow.ResultEncoded<any, any>>): Exit.Exit<unknown, unknown> => {
989
+ const decoded = decodeDeferredWithExit(reply as any)
990
+ return decoded.exit._tag === "Success" ? decoded.exit.value : decoded.exit
991
+ }
962
992
 
963
993
  const ResumeRpc = Rpc.make("resume", {
964
994
  // Older persisted resume envelopes have an empty payload and use the empty key.
@@ -133,8 +133,15 @@ export class MessageStorage extends Context.Service<MessageStorage, {
133
133
 
134
134
  /**
135
135
  * Unregister the reply handler for the specified message.
136
+ *
137
+ * By default the waiters are resumed with `EntityNotAssignedToRunner`. With
138
+ * `interrupt: true` they are interrupted with a cluster-abandon annotation
139
+ * instead, for when the request will not be served by this runner.
136
140
  */
137
- readonly unregisterReplyHandler: (requestId: Snowflake.Snowflake) => Effect.Effect<void>
141
+ readonly unregisterReplyHandler: (
142
+ requestId: Snowflake.Snowflake,
143
+ options?: { readonly interrupt?: boolean | undefined }
144
+ ) => Effect.Effect<void>
138
145
 
139
146
  /**
140
147
  * Unregister the reply handlers for the specified ShardId.
@@ -569,6 +576,14 @@ export const make = (
569
576
  }
570
577
  const replyHandlers = new Map<Snowflake.Snowflake, Array<ReplyHandler>>()
571
578
  const replyHandlersShard = new Map<string, Set<ReplyHandler>>()
579
+ const resumeUnregistered = (handler: ReplyHandler, options?: { readonly interrupt?: boolean | undefined }) =>
580
+ handler.resume(
581
+ options?.interrupt ? ClusterAbandon.interrupt : Effect.fail(
582
+ new EntityNotAssignedToRunner({
583
+ address: handler.message.envelope.address
584
+ })
585
+ )
586
+ )
572
587
  return MessageStorage.of({
573
588
  ...storage,
574
589
  // Nested transactions defer notifications to the outermost commit.
@@ -614,7 +629,7 @@ export const make = (
614
629
  })
615
630
  })
616
631
  },
617
- unregisterReplyHandler: (requestId) =>
632
+ unregisterReplyHandler: (requestId, options) =>
618
633
  Effect.sync(() => {
619
634
  const handlers = replyHandlers.get(requestId)
620
635
  if (!handlers) return
@@ -622,11 +637,7 @@ export const make = (
622
637
  for (let i = 0; i < handlers.length; i++) {
623
638
  const handler = handlers[i]
624
639
  handler.shardSet.delete(handler)
625
- handler.resume(Effect.fail(
626
- new EntityNotAssignedToRunner({
627
- address: handler.message.envelope.address
628
- })
629
- ))
640
+ resumeUnregistered(handler, options)
630
641
  }
631
642
  }),
632
643
  unregisterShardReplyHandlers: (shardId, options) =>
@@ -637,13 +648,7 @@ export const make = (
637
648
  replyHandlersShard.delete(id)
638
649
  shardSet.forEach((handler) => {
639
650
  replyHandlers.delete(handler.message.envelope.requestId)
640
- handler.resume(
641
- options?.interrupt ? ClusterAbandon.interrupt : Effect.fail(
642
- new EntityNotAssignedToRunner({
643
- address: handler.message.envelope.address
644
- })
645
- )
646
- )
651
+ resumeUnregistered(handler, options)
647
652
  })
648
653
  }),
649
654
  saveReply(reply) {
@@ -290,6 +290,24 @@ const make = Effect.gen(function*() {
290
290
  updateReleasingShardsGauge()
291
291
  }
292
292
  const activeShardsLatch = yield* Latch.make(false)
293
+
294
+ // Applies the result of a lock refresh: refreshed shards it did not return,
295
+ // and returned shards no longer assigned to this runner, move from
296
+ // `acquiredShards` to `releasingShards`. Shards acquired during the refresh
297
+ // are absent from its response, so only the refreshed ones are considered.
298
+ const releaseLostShards = (refreshed: ReadonlyArray<ShardId>, acquired: ReadonlyArray<ShardId>) => {
299
+ for (const shardId of refreshed) {
300
+ if (
301
+ MutableHashSet.has(acquiredShards, shardId) &&
302
+ (!acquired.includes(shardId) || !MutableHashSet.has(selfShards, shardId))
303
+ ) {
304
+ MutableHashSet.remove(acquiredShards, shardId)
305
+ MutableHashSet.add(releasingShards, shardId)
306
+ }
307
+ }
308
+ updateShardGauges()
309
+ if (MutableHashSet.size(releasingShards) > 0) activeShardsLatch.openUnsafe()
310
+ }
293
311
  // open once shutdown starts handing every shard off
294
312
  const handoffLatch = Latch.makeUnsafe(false)
295
313
  // open once the handoff has released every shard lock
@@ -690,27 +708,12 @@ const make = Effect.gen(function*() {
690
708
  return Effect.logInfo("Shard lock storage has recovered")
691
709
  })
692
710
 
693
- const refreshShardLocks = Effect.gen(function*() {
711
+ const refreshShardLocks = Effect.suspend(() => {
694
712
  const refreshed = [...acquiredShards, ...releasingShards]
695
- const acquired = yield* runnerStorage.refresh(selfAddress, refreshed)
696
- // Shards acquired during the request are absent from its response.
697
- for (const shardId of refreshed) {
698
- if (MutableHashSet.has(acquiredShards, shardId) && !acquired.includes(shardId)) {
699
- MutableHashSet.remove(acquiredShards, shardId)
700
- MutableHashSet.add(releasingShards, shardId)
701
- }
702
- }
703
- for (let i = 0; i < acquired.length; i++) {
704
- const shardId = acquired[i]
705
- if (!MutableHashSet.has(selfShards, shardId)) {
706
- MutableHashSet.remove(acquiredShards, shardId)
707
- MutableHashSet.add(releasingShards, shardId)
708
- }
709
- }
710
- updateShardGauges()
711
- if (MutableHashSet.size(releasingShards) > 0) {
712
- yield* activeShardsLatch.open
713
- }
713
+ return Effect.map(
714
+ runnerStorage.refresh(selfAddress, refreshed),
715
+ (acquired) => releaseLostShards(refreshed, acquired)
716
+ )
714
717
  }).pipe(
715
718
  Effect.retry({
716
719
  times: 5,
@@ -1541,6 +1544,27 @@ const make = Effect.gen(function*() {
1541
1544
  }
1542
1545
  const clientRequests = new Map<Snowflake.Snowflake, ClientRequestEntry>()
1543
1546
 
1547
+ // During shutdown, abandon local callers parked on persisted requests that a
1548
+ // retiring entity never started. They are served by the next owner. Callers
1549
+ // on a runner that keeps running are left waiting, so they stay durable.
1550
+ const abandonUndelivered = (
1551
+ address: EntityAddress,
1552
+ isDelivered: (requestId: Snowflake.Snowflake) => boolean
1553
+ ): Effect.Effect<void> =>
1554
+ Effect.suspend(() => {
1555
+ if (!MutableRef.get(isShutdown)) return Effect.void
1556
+ const abandon: Array<Effect.Effect<void>> = []
1557
+ for (const [requestId, entry] of clientRequests) {
1558
+ if (
1559
+ !Context.get(entry.message.annotations, Persisted) ||
1560
+ !Equal.equals(entry.message.envelope.address, address) ||
1561
+ isDelivered(requestId)
1562
+ ) continue
1563
+ abandon.push(storage.unregisterReplyHandler(requestId, { interrupt: true }))
1564
+ }
1565
+ return Effect.all(abandon, { discard: true })
1566
+ })
1567
+
1544
1568
  const clients: ResourceMap<
1545
1569
  Entity<any, any>,
1546
1570
  (entityId: string) => RpcClient.RpcClient<
@@ -1878,6 +1902,42 @@ const make = Effect.gen(function*() {
1878
1902
  const reaper = yield* EntityReaper
1879
1903
  const entityManagerLatches = new Map<string, Latch.Latch>()
1880
1904
 
1905
+ // This runner's view of its shards lags lock storage by up to one refresh,
1906
+ // or longer while the process is paused. So the final reply of a persisted
1907
+ // request is stored only once a refresh of its shard's lock confirms it.
1908
+ // Anything short of that, including a refresh that failed, timed out, was
1909
+ // interrupted, or never started because shutdown closed the scope, leaves
1910
+ // the reply for the shard's next owner. Concurrent writers on a shard share
1911
+ // one refresh, which outlives an interrupted writer. Entities draining from
1912
+ // a released shard still hold its lock.
1913
+ const pendingLockChecks = new Map<ShardId, Fiber.Fiber<boolean>>()
1914
+ const confirmShardLock = (runnerAddress: RunnerAddress, shardId: ShardId): Effect.Effect<boolean> =>
1915
+ Effect.suspend(() => {
1916
+ if (!MutableHashSet.has(acquiredShards, shardId) && !MutableHashSet.has(releasingShards, shardId)) {
1917
+ return Effect.succeed(false)
1918
+ }
1919
+ const pending = pendingLockChecks.get(shardId)
1920
+ const check = pending ? Effect.succeed(pending) : runnerStorage.refresh(runnerAddress, [shardId]).pipe(
1921
+ Effect.map((acquired) => {
1922
+ releaseLostShards([shardId], acquired)
1923
+ return acquired.includes(shardId)
1924
+ }),
1925
+ Effect.timeoutOption(shardLockInterval),
1926
+ Effect.map(Option.getOrElse(() => false)),
1927
+ Effect.catch(() => Effect.succeed(false)),
1928
+ Effect.forkIn(shardingScope, { startImmediately: true }),
1929
+ Effect.map((fiber) => {
1930
+ pendingLockChecks.set(shardId, fiber)
1931
+ fiber.addObserver(() => pendingLockChecks.delete(shardId))
1932
+ return fiber
1933
+ })
1934
+ )
1935
+ return Effect.flatMap(
1936
+ check,
1937
+ (fiber) => Effect.map(Fiber.await(fiber), (exit) => exit._tag === "Success" && exit.value)
1938
+ )
1939
+ })
1940
+
1881
1941
  const registerEntity: Sharding["Service"]["registerEntity"] = Effect.fnUntraced(
1882
1942
  function*(entity, build, options) {
1883
1943
  const runnerAddress = getRunnerAddress()
@@ -1895,7 +1955,9 @@ const make = Effect.gen(function*() {
1895
1955
  storage,
1896
1956
  runnerAddress,
1897
1957
  residency,
1898
- sharding
1958
+ sharding,
1959
+ abandonUndelivered,
1960
+ isShardOwned: (shardId) => confirmShardLock(runnerAddress, shardId)
1899
1961
  }).pipe(
1900
1962
  Effect.provideContext(services.pipe(
1901
1963
  // Registration overrides construction fallbacks, except for runner-owned services.
@@ -81,6 +81,11 @@ export class ShardingConfig extends Context.Service<ShardingConfig, {
81
81
  readonly shardLockRefreshInterval: Duration.Input
82
82
  /**
83
83
  * Shard lock expiration duration.
84
+ *
85
+ * With PostgreSQL advisory locks (PostgreSQL 14+), this also bounds how long
86
+ * a runner that stops refreshing, for example because its process is frozen,
87
+ * keeps its shards: the server ends its idle lock session after this
88
+ * duration, releasing the locks.
84
89
  */
85
90
  readonly shardLockExpiration: Duration.Input
86
91
  /**
@@ -257,18 +257,14 @@ export const makeGenerator: Effect.Effect<Snowflake.Generator> = Effect.gen(func
257
257
  machineId = newMachineId
258
258
  }),
259
259
  nextUnsafe() {
260
- let now = Math.floor(clock.currentTimeMillisUnsafe())
260
+ const now = Math.floor(clock.currentTimeMillisUnsafe())
261
261
 
262
- // account for clock drift, only allow time to move forward
263
- if (now < sequenceAt) {
264
- now = sequenceAt
265
- } else if (now > sequenceAt) {
262
+ if (now > sequenceAt) {
266
263
  // reset sequence if we're in a new millisecond
267
264
  sequence = 0
268
265
  sequenceAt = now
269
266
  } else if (sequence >= 4096) {
270
- // if we've hit the max sequence for this millisecond, go to the next
271
- // millisecond
267
+ // sequence exhausted and the clock hasn't advanced, so borrow the next millisecond
272
268
  sequenceAt++
273
269
  sequence = 0
274
270
  }