@rikalabs/akter 0.1.0-alpha.0

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 (603) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +8 -0
  4. package/README.md +116 -0
  5. package/dist/actor/codecs.d.ts +77 -0
  6. package/dist/actor/codecs.js +87 -0
  7. package/dist/actor/connections.d.ts +34 -0
  8. package/dist/actor/connections.js +145 -0
  9. package/dist/actor/definition.d.ts +893 -0
  10. package/dist/actor/definition.js +147 -0
  11. package/dist/actor/descriptor.d.ts +172 -0
  12. package/dist/actor/descriptor.js +367 -0
  13. package/dist/actor/handles.d.ts +77 -0
  14. package/dist/actor/handles.js +265 -0
  15. package/dist/actor/jobs.d.ts +10 -0
  16. package/dist/actor/jobs.js +137 -0
  17. package/dist/actor/layers.d.ts +41 -0
  18. package/dist/actor/layers.js +177 -0
  19. package/dist/actor/reads.d.ts +47 -0
  20. package/dist/actor/reads.js +224 -0
  21. package/dist/actor/served.d.ts +120 -0
  22. package/dist/actor/served.js +72 -0
  23. package/dist/actor/turns.d.ts +13 -0
  24. package/dist/actor/turns.js +332 -0
  25. package/dist/actor/workflows.d.ts +16 -0
  26. package/dist/actor/workflows.js +37 -0
  27. package/dist/client/calls.d.ts +47 -0
  28. package/dist/client/calls.js +425 -0
  29. package/dist/client/clock.d.ts +56 -0
  30. package/dist/client/clock.js +119 -0
  31. package/dist/client/fleet-page.d.ts +15 -0
  32. package/dist/client/fleet-page.js +13 -0
  33. package/dist/client/fleet.d.ts +29 -0
  34. package/dist/client/fleet.js +51 -0
  35. package/dist/client/index.d.ts +17 -0
  36. package/dist/client/index.js +6 -0
  37. package/dist/client/make.d.ts +157 -0
  38. package/dist/client/make.js +221 -0
  39. package/dist/client/offline/queue.d.ts +118 -0
  40. package/dist/client/offline/queue.js +292 -0
  41. package/dist/client/offline/store.d.ts +74 -0
  42. package/dist/client/offline/store.js +78 -0
  43. package/dist/client/optimistic.d.ts +57 -0
  44. package/dist/client/optimistic.js +136 -0
  45. package/dist/client/report.d.ts +2 -0
  46. package/dist/client/report.js +8 -0
  47. package/dist/client/sessions/connection.d.ts +118 -0
  48. package/dist/client/sessions/connection.js +162 -0
  49. package/dist/client/sessions/feed.d.ts +42 -0
  50. package/dist/client/sessions/feed.js +43 -0
  51. package/dist/client/sessions/sse.d.ts +47 -0
  52. package/dist/client/sessions/sse.js +112 -0
  53. package/dist/client/sessions/stream.d.ts +28 -0
  54. package/dist/client/sessions/stream.js +35 -0
  55. package/dist/client/sessions/watch.d.ts +34 -0
  56. package/dist/client/sessions/watch.js +40 -0
  57. package/dist/client/transport.d.ts +37 -0
  58. package/dist/client/transport.js +66 -0
  59. package/dist/contexts/command.d.ts +132 -0
  60. package/dist/contexts/command.js +20 -0
  61. package/dist/contexts/connection.d.ts +68 -0
  62. package/dist/contexts/connection.js +0 -0
  63. package/dist/contexts/job.d.ts +49 -0
  64. package/dist/contexts/job.js +0 -0
  65. package/dist/contexts/workflow.d.ts +147 -0
  66. package/dist/contexts/workflow.js +22 -0
  67. package/dist/errors/actor.d.ts +200 -0
  68. package/dist/errors/actor.js +271 -0
  69. package/dist/errors/content.d.ts +19 -0
  70. package/dist/errors/content.js +14 -0
  71. package/dist/errors/database.d.ts +22 -0
  72. package/dist/errors/database.js +23 -0
  73. package/dist/errors/events.d.ts +17 -0
  74. package/dist/errors/events.js +14 -0
  75. package/dist/errors/subscription.d.ts +12 -0
  76. package/dist/errors/subscription.js +8 -0
  77. package/dist/errors/workflow.d.ts +28 -0
  78. package/dist/errors/workflow.js +17 -0
  79. package/dist/handles/actors.d.ts +17 -0
  80. package/dist/handles/actors.js +7 -0
  81. package/dist/handles/content.d.ts +59 -0
  82. package/dist/handles/content.js +36 -0
  83. package/dist/handles/intents.d.ts +164 -0
  84. package/dist/handles/intents.js +214 -0
  85. package/dist/handles/run.d.ts +31 -0
  86. package/dist/handles/run.js +21 -0
  87. package/dist/handles/workflow.d.ts +27 -0
  88. package/dist/handles/workflow.js +23 -0
  89. package/dist/identity/caller.d.ts +105 -0
  90. package/dist/identity/caller.js +68 -0
  91. package/dist/identity/child.d.ts +18 -0
  92. package/dist/identity/child.js +39 -0
  93. package/dist/identity/command.d.ts +19 -0
  94. package/dist/identity/command.js +21 -0
  95. package/dist/identity/connection.d.ts +24 -0
  96. package/dist/identity/connection.js +29 -0
  97. package/dist/identity/content.d.ts +18 -0
  98. package/dist/identity/content.js +12 -0
  99. package/dist/identity/digest.d.ts +4 -0
  100. package/dist/identity/digest.js +5 -0
  101. package/dist/identity/execution.d.ts +32 -0
  102. package/dist/identity/execution.js +63 -0
  103. package/dist/identity/mint.d.ts +51 -0
  104. package/dist/identity/mint.js +76 -0
  105. package/dist/identity/version.d.ts +2 -0
  106. package/dist/identity/version.js +3 -0
  107. package/dist/index.d.ts +159 -0
  108. package/dist/index.js +97 -0
  109. package/dist/members/blob.d.ts +43 -0
  110. package/dist/members/blob.js +29 -0
  111. package/dist/members/command.d.ts +109 -0
  112. package/dist/members/command.js +61 -0
  113. package/dist/members/connection.d.ts +55 -0
  114. package/dist/members/connection.js +49 -0
  115. package/dist/members/event.d.ts +36 -0
  116. package/dist/members/event.js +24 -0
  117. package/dist/members/job.d.ts +157 -0
  118. package/dist/members/job.js +67 -0
  119. package/dist/members/payload.d.ts +93 -0
  120. package/dist/members/payload.js +145 -0
  121. package/dist/members/reducer.d.ts +64 -0
  122. package/dist/members/reducer.js +27 -0
  123. package/dist/members/stream.d.ts +36 -0
  124. package/dist/members/stream.js +14 -0
  125. package/dist/members/subscription.d.ts +182 -0
  126. package/dist/members/subscription.js +91 -0
  127. package/dist/members/workflow.d.ts +99 -0
  128. package/dist/members/workflow.js +2 -0
  129. package/dist/policies/access.d.ts +35 -0
  130. package/dist/policies/access.js +6 -0
  131. package/dist/policies/command.d.ts +127 -0
  132. package/dist/policies/command.js +45 -0
  133. package/dist/policies/job.d.ts +28 -0
  134. package/dist/policies/job.js +60 -0
  135. package/dist/policies/schedules.d.ts +33 -0
  136. package/dist/policies/schedules.js +131 -0
  137. package/dist/protocol/frames.d.ts +66 -0
  138. package/dist/protocol/frames.js +55 -0
  139. package/dist/protocol/inspection.d.ts +807 -0
  140. package/dist/protocol/inspection.js +243 -0
  141. package/dist/protocol/wire.d.ts +184 -0
  142. package/dist/protocol/wire.js +150 -0
  143. package/dist/runtime/actors.d.ts +155 -0
  144. package/dist/runtime/actors.js +4 -0
  145. package/dist/runtime/admission.d.ts +34 -0
  146. package/dist/runtime/admission.js +72 -0
  147. package/dist/runtime/adoption/backfill.d.ts +27 -0
  148. package/dist/runtime/adoption/backfill.js +144 -0
  149. package/dist/runtime/adoption/enforce.d.ts +55 -0
  150. package/dist/runtime/adoption/enforce.js +241 -0
  151. package/dist/runtime/adoption/observe.d.ts +43 -0
  152. package/dist/runtime/adoption/observe.js +139 -0
  153. package/dist/runtime/adoption/plan.d.ts +45 -0
  154. package/dist/runtime/adoption/plan.js +192 -0
  155. package/dist/runtime/adoption/startup.d.ts +32 -0
  156. package/dist/runtime/adoption/startup.js +76 -0
  157. package/dist/runtime/adoption/status.d.ts +23 -0
  158. package/dist/runtime/adoption/status.js +47 -0
  159. package/dist/runtime/adoption/target.d.ts +33 -0
  160. package/dist/runtime/adoption/target.js +49 -0
  161. package/dist/runtime/connections/holder.d.ts +221 -0
  162. package/dist/runtime/connections/holder.js +816 -0
  163. package/dist/runtime/connections/owner.d.ts +263 -0
  164. package/dist/runtime/connections/owner.js +896 -0
  165. package/dist/runtime/connections/protocol.d.ts +441 -0
  166. package/dist/runtime/connections/protocol.js +222 -0
  167. package/dist/runtime/connections/reads.d.ts +24 -0
  168. package/dist/runtime/connections/reads.js +19 -0
  169. package/dist/runtime/connections/streams.d.ts +62 -0
  170. package/dist/runtime/connections/streams.js +128 -0
  171. package/dist/runtime/connections/transport.d.ts +40 -0
  172. package/dist/runtime/connections/transport.js +68 -0
  173. package/dist/runtime/connections/watch.d.ts +52 -0
  174. package/dist/runtime/connections/watch.js +159 -0
  175. package/dist/runtime/content/grant.d.ts +34 -0
  176. package/dist/runtime/content/grant.js +58 -0
  177. package/dist/runtime/content/store.d.ts +63 -0
  178. package/dist/runtime/content/store.js +294 -0
  179. package/dist/runtime/cron/key.d.ts +2 -0
  180. package/dist/runtime/cron/key.js +2 -0
  181. package/dist/runtime/cron/schedule.d.ts +69 -0
  182. package/dist/runtime/cron/schedule.js +144 -0
  183. package/dist/runtime/database/bounded.d.ts +43 -0
  184. package/dist/runtime/database/bounded.js +108 -0
  185. package/dist/runtime/database/connection.d.ts +8 -0
  186. package/dist/runtime/database/connection.js +18 -0
  187. package/dist/runtime/database/coordination.d.ts +19 -0
  188. package/dist/runtime/database/coordination.js +72 -0
  189. package/dist/runtime/database/flock.d.ts +10 -0
  190. package/dist/runtime/database/flock.js +60 -0
  191. package/dist/runtime/database/gate.d.ts +26 -0
  192. package/dist/runtime/database/gate.js +54 -0
  193. package/dist/runtime/database/keepalive.d.ts +11 -0
  194. package/dist/runtime/database/keepalive.js +22 -0
  195. package/dist/runtime/database/migrations.d.ts +177 -0
  196. package/dist/runtime/database/migrations.js +1018 -0
  197. package/dist/runtime/database/neki/migrations.d.ts +31 -0
  198. package/dist/runtime/database/neki/migrations.js +276 -0
  199. package/dist/runtime/database/neki/session.d.ts +23 -0
  200. package/dist/runtime/database/neki/session.js +31 -0
  201. package/dist/runtime/database/pglite.d.ts +21 -0
  202. package/dist/runtime/database/pglite.js +74 -0
  203. package/dist/runtime/database/replica.d.ts +41 -0
  204. package/dist/runtime/database/replica.js +51 -0
  205. package/dist/runtime/database/shards.d.ts +21 -0
  206. package/dist/runtime/database/shards.js +37 -0
  207. package/dist/runtime/database/snapshot.d.ts +7 -0
  208. package/dist/runtime/database/snapshot.js +7 -0
  209. package/dist/runtime/database/tenancy.d.ts +69 -0
  210. package/dist/runtime/database/tenancy.js +145 -0
  211. package/dist/runtime/database/transient.d.ts +10 -0
  212. package/dist/runtime/database/transient.js +25 -0
  213. package/dist/runtime/drain.d.ts +132 -0
  214. package/dist/runtime/drain.js +109 -0
  215. package/dist/runtime/entity/mailbox.d.ts +86 -0
  216. package/dist/runtime/entity/mailbox.js +121 -0
  217. package/dist/runtime/entity/register.d.ts +424 -0
  218. package/dist/runtime/entity/register.js +669 -0
  219. package/dist/runtime/events/append.d.ts +192 -0
  220. package/dist/runtime/events/append.js +128 -0
  221. package/dist/runtime/events/cursor.d.ts +2 -0
  222. package/dist/runtime/events/cursor.js +5 -0
  223. package/dist/runtime/events/replay.d.ts +20 -0
  224. package/dist/runtime/events/replay.js +45 -0
  225. package/dist/runtime/feeds.d.ts +26 -0
  226. package/dist/runtime/feeds.js +100 -0
  227. package/dist/runtime/fleet/checks.d.ts +17 -0
  228. package/dist/runtime/fleet/checks.js +106 -0
  229. package/dist/runtime/fleet/maintainer.d.ts +38 -0
  230. package/dist/runtime/fleet/maintainer.js +383 -0
  231. package/dist/runtime/fleet/pgoutput.d.ts +41 -0
  232. package/dist/runtime/fleet/pgoutput.js +102 -0
  233. package/dist/runtime/fleet/setup.d.ts +36 -0
  234. package/dist/runtime/fleet/setup.js +58 -0
  235. package/dist/runtime/fleet/subscribe.d.ts +42 -0
  236. package/dist/runtime/fleet/subscribe.js +147 -0
  237. package/dist/runtime/index.d.ts +66 -0
  238. package/dist/runtime/index.js +37 -0
  239. package/dist/runtime/inspector/http.d.ts +19 -0
  240. package/dist/runtime/inspector/http.js +36 -0
  241. package/dist/runtime/inspector/layer.d.ts +46 -0
  242. package/dist/runtime/inspector/layer.js +180 -0
  243. package/dist/runtime/inspector/queries.d.ts +711 -0
  244. package/dist/runtime/inspector/queries.js +494 -0
  245. package/dist/runtime/jobs/attempt.d.ts +254 -0
  246. package/dist/runtime/jobs/attempt.js +413 -0
  247. package/dist/runtime/jobs/isolation.d.ts +20 -0
  248. package/dist/runtime/jobs/isolation.js +10 -0
  249. package/dist/runtime/jobs/progress.d.ts +95 -0
  250. package/dist/runtime/jobs/progress.js +144 -0
  251. package/dist/runtime/layer.d.ts +260 -0
  252. package/dist/runtime/layer.js +876 -0
  253. package/dist/runtime/members.d.ts +381 -0
  254. package/dist/runtime/members.js +8 -0
  255. package/dist/runtime/operators/audit.d.ts +64 -0
  256. package/dist/runtime/operators/audit.js +56 -0
  257. package/dist/runtime/operators/auth.d.ts +29 -0
  258. package/dist/runtime/operators/auth.js +42 -0
  259. package/dist/runtime/operators/export.d.ts +68 -0
  260. package/dist/runtime/operators/export.js +137 -0
  261. package/dist/runtime/operators/grants.d.ts +45 -0
  262. package/dist/runtime/operators/grants.js +40 -0
  263. package/dist/runtime/operators/repair.d.ts +206 -0
  264. package/dist/runtime/operators/repair.js +226 -0
  265. package/dist/runtime/operators/routes.d.ts +35 -0
  266. package/dist/runtime/operators/routes.js +190 -0
  267. package/dist/runtime/operators/seed.d.ts +123 -0
  268. package/dist/runtime/operators/seed.js +123 -0
  269. package/dist/runtime/payloads/versions.d.ts +65 -0
  270. package/dist/runtime/payloads/versions.js +240 -0
  271. package/dist/runtime/peering/authority.d.ts +42 -0
  272. package/dist/runtime/peering/authority.js +132 -0
  273. package/dist/runtime/peering/credentials.d.ts +21 -0
  274. package/dist/runtime/peering/credentials.js +13 -0
  275. package/dist/runtime/peering/transport.d.ts +51 -0
  276. package/dist/runtime/peering/transport.js +175 -0
  277. package/dist/runtime/queries.d.ts +18 -0
  278. package/dist/runtime/queries.js +169 -0
  279. package/dist/runtime/readiness.d.ts +36 -0
  280. package/dist/runtime/readiness.js +44 -0
  281. package/dist/runtime/registration.d.ts +58 -0
  282. package/dist/runtime/registration.js +186 -0
  283. package/dist/runtime/request.d.ts +158 -0
  284. package/dist/runtime/request.js +102 -0
  285. package/dist/runtime/retry.d.ts +8 -0
  286. package/dist/runtime/retry.js +11 -0
  287. package/dist/runtime/runner.d.ts +93 -0
  288. package/dist/runtime/runner.js +122 -0
  289. package/dist/runtime/storage/codec.d.ts +39 -0
  290. package/dist/runtime/storage/codec.js +41 -0
  291. package/dist/runtime/storage/generation.d.ts +69 -0
  292. package/dist/runtime/storage/generation.js +49 -0
  293. package/dist/runtime/storage/placements.d.ts +15 -0
  294. package/dist/runtime/storage/placements.js +38 -0
  295. package/dist/runtime/storage/platform.d.ts +6 -0
  296. package/dist/runtime/storage/platform.js +9 -0
  297. package/dist/runtime/storage/retention.d.ts +73 -0
  298. package/dist/runtime/storage/retention.js +158 -0
  299. package/dist/runtime/subscriptions/identity.d.ts +31 -0
  300. package/dist/runtime/subscriptions/identity.js +45 -0
  301. package/dist/runtime/subscriptions/relay.d.ts +175 -0
  302. package/dist/runtime/subscriptions/relay.js +763 -0
  303. package/dist/runtime/subscriptions/storage.d.ts +40 -0
  304. package/dist/runtime/subscriptions/storage.js +98 -0
  305. package/dist/runtime/sweeps.d.ts +39 -0
  306. package/dist/runtime/sweeps.js +54 -0
  307. package/dist/runtime/telemetry/defects.d.ts +57 -0
  308. package/dist/runtime/telemetry/defects.js +43 -0
  309. package/dist/runtime/telemetry/metrics.d.ts +52 -0
  310. package/dist/runtime/telemetry/metrics.js +138 -0
  311. package/dist/runtime/telemetry/routes.d.ts +19 -0
  312. package/dist/runtime/telemetry/routes.js +18 -0
  313. package/dist/runtime/telemetry/sampler.d.ts +26 -0
  314. package/dist/runtime/telemetry/sampler.js +101 -0
  315. package/dist/runtime/telemetry/spans.d.ts +38 -0
  316. package/dist/runtime/telemetry/spans.js +44 -0
  317. package/dist/runtime/telemetry/usage.d.ts +52 -0
  318. package/dist/runtime/telemetry/usage.js +30 -0
  319. package/dist/runtime/topology/admission.d.ts +13 -0
  320. package/dist/runtime/topology/admission.js +36 -0
  321. package/dist/runtime/topology/locks.d.ts +56 -0
  322. package/dist/runtime/topology/locks.js +81 -0
  323. package/dist/runtime/topology/messages.d.ts +15 -0
  324. package/dist/runtime/topology/messages.js +32 -0
  325. package/dist/runtime/turn/admission.d.ts +22 -0
  326. package/dist/runtime/turn/admission.js +41 -0
  327. package/dist/runtime/turn/blobs.d.ts +38 -0
  328. package/dist/runtime/turn/blobs.js +215 -0
  329. package/dist/runtime/turn/execute.d.ts +208 -0
  330. package/dist/runtime/turn/execute.js +972 -0
  331. package/dist/runtime/turn/group.d.ts +165 -0
  332. package/dist/runtime/turn/group.js +326 -0
  333. package/dist/runtime/turn/hooks.d.ts +44 -0
  334. package/dist/runtime/turn/hooks.js +28 -0
  335. package/dist/runtime/turn/outbox.d.ts +159 -0
  336. package/dist/runtime/turn/outbox.js +269 -0
  337. package/dist/runtime/turn/pipeline.d.ts +68 -0
  338. package/dist/runtime/turn/pipeline.js +83 -0
  339. package/dist/runtime/turn/receipt.d.ts +81 -0
  340. package/dist/runtime/turn/receipt.js +32 -0
  341. package/dist/runtime/turn/relay.d.ts +179 -0
  342. package/dist/runtime/turn/relay.js +685 -0
  343. package/dist/runtime/turn/rows.d.ts +43 -0
  344. package/dist/runtime/turn/rows.js +592 -0
  345. package/dist/runtime/workflows/compatibility.d.ts +125 -0
  346. package/dist/runtime/workflows/compatibility.js +285 -0
  347. package/dist/runtime/workflows/engine.d.ts +107 -0
  348. package/dist/runtime/workflows/engine.js +826 -0
  349. package/dist/runtime/workflows/manifest.d.ts +34 -0
  350. package/dist/runtime/workflows/manifest.js +39 -0
  351. package/dist/runtime/workflows/steps.d.ts +33 -0
  352. package/dist/runtime/workflows/steps.js +152 -0
  353. package/dist/serve/api.d.ts +99 -0
  354. package/dist/serve/api.js +403 -0
  355. package/dist/serve/assertion/binding.d.ts +41 -0
  356. package/dist/serve/assertion/binding.js +92 -0
  357. package/dist/serve/assertion/verify.d.ts +93 -0
  358. package/dist/serve/assertion/verify.js +189 -0
  359. package/dist/serve/auth.d.ts +200 -0
  360. package/dist/serve/auth.js +92 -0
  361. package/dist/serve/clock.d.ts +10 -0
  362. package/dist/serve/clock.js +25 -0
  363. package/dist/serve/jwt.d.ts +65 -0
  364. package/dist/serve/jwt.js +202 -0
  365. package/dist/serve/layer.d.ts +98 -0
  366. package/dist/serve/layer.js +809 -0
  367. package/dist/serve/mcp/endpoint.d.ts +39 -0
  368. package/dist/serve/mcp/endpoint.js +187 -0
  369. package/dist/serve/mcp/tools.d.ts +37 -0
  370. package/dist/serve/mcp/tools.js +125 -0
  371. package/dist/serve/origin.d.ts +6 -0
  372. package/dist/serve/origin.js +21 -0
  373. package/dist/serve/sessions/feed.d.ts +79 -0
  374. package/dist/serve/sessions/feed.js +115 -0
  375. package/dist/serve/sessions/socket.d.ts +56 -0
  376. package/dist/serve/sessions/socket.js +212 -0
  377. package/dist/serve/sessions/sse.d.ts +27 -0
  378. package/dist/serve/sessions/sse.js +26 -0
  379. package/dist/serve/sessions/stream.d.ts +9 -0
  380. package/dist/serve/sessions/stream.js +9 -0
  381. package/dist/serve/sessions/watch.d.ts +12 -0
  382. package/dist/serve/sessions/watch.js +11 -0
  383. package/dist/serve/wire.d.ts +16 -0
  384. package/dist/serve/wire.js +50 -0
  385. package/dist/state/blob.d.ts +71 -0
  386. package/dist/state/blob.js +0 -0
  387. package/dist/state/migration.d.ts +53 -0
  388. package/dist/state/migration.js +29 -0
  389. package/dist/tables/fleet.d.ts +170 -0
  390. package/dist/tables/fleet.js +214 -0
  391. package/dist/tables/owned.d.ts +250 -0
  392. package/dist/tables/owned.js +233 -0
  393. package/dist/testing/actor-test.d.ts +360 -0
  394. package/dist/testing/actor-test.js +337 -0
  395. package/dist/testing/cluster.d.ts +93 -0
  396. package/dist/testing/cluster.js +296 -0
  397. package/dist/testing/conformance/access.d.ts +5 -0
  398. package/dist/testing/conformance/access.js +531 -0
  399. package/dist/testing/conformance/admission.d.ts +11 -0
  400. package/dist/testing/conformance/admission.js +182 -0
  401. package/dist/testing/conformance/adoption.d.ts +2 -0
  402. package/dist/testing/conformance/adoption.js +1019 -0
  403. package/dist/testing/conformance/assertions.d.ts +202 -0
  404. package/dist/testing/conformance/assertions.js +849 -0
  405. package/dist/testing/conformance/batches.d.ts +41 -0
  406. package/dist/testing/conformance/batches.js +388 -0
  407. package/dist/testing/conformance/blobs.d.ts +14 -0
  408. package/dist/testing/conformance/blobs.js +405 -0
  409. package/dist/testing/conformance/capacity.d.ts +8 -0
  410. package/dist/testing/conformance/capacity.js +433 -0
  411. package/dist/testing/conformance/client.d.ts +5 -0
  412. package/dist/testing/conformance/client.js +719 -0
  413. package/dist/testing/conformance/cold-serve.d.ts +16 -0
  414. package/dist/testing/conformance/cold-serve.js +254 -0
  415. package/dist/testing/conformance/connections/actors.d.ts +1143 -0
  416. package/dist/testing/conformance/connections/actors.js +180 -0
  417. package/dist/testing/conformance/connections/harness.d.ts +1754 -0
  418. package/dist/testing/conformance/connections/harness.js +142 -0
  419. package/dist/testing/conformance/connections/holders.d.ts +4 -0
  420. package/dist/testing/conformance/connections/holders.js +165 -0
  421. package/dist/testing/conformance/connections/lifecycle.d.ts +4 -0
  422. package/dist/testing/conformance/connections/lifecycle.js +113 -0
  423. package/dist/testing/conformance/connections/limits.d.ts +4 -0
  424. package/dist/testing/conformance/connections/limits.js +127 -0
  425. package/dist/testing/conformance/connections/reauthorization.d.ts +4 -0
  426. package/dist/testing/conformance/connections/reauthorization.js +170 -0
  427. package/dist/testing/conformance/connections/resync.d.ts +4 -0
  428. package/dist/testing/conformance/connections/resync.js +360 -0
  429. package/dist/testing/conformance/connections/takeover.d.ts +4 -0
  430. package/dist/testing/conformance/connections/takeover.js +287 -0
  431. package/dist/testing/conformance/connections.d.ts +4 -0
  432. package/dist/testing/conformance/connections.js +15 -0
  433. package/dist/testing/conformance/content-blobs.d.ts +16 -0
  434. package/dist/testing/conformance/content-blobs.js +534 -0
  435. package/dist/testing/conformance/counter.d.ts +16 -0
  436. package/dist/testing/conformance/counter.js +813 -0
  437. package/dist/testing/conformance/cron.d.ts +5 -0
  438. package/dist/testing/conformance/cron.js +665 -0
  439. package/dist/testing/conformance/drain.d.ts +26 -0
  440. package/dist/testing/conformance/drain.js +540 -0
  441. package/dist/testing/conformance/effect-control.d.ts +38 -0
  442. package/dist/testing/conformance/effect-control.js +1059 -0
  443. package/dist/testing/conformance/effects.d.ts +23 -0
  444. package/dist/testing/conformance/effects.js +432 -0
  445. package/dist/testing/conformance/events.d.ts +28 -0
  446. package/dist/testing/conformance/events.js +335 -0
  447. package/dist/testing/conformance/export.d.ts +2 -0
  448. package/dist/testing/conformance/export.js +368 -0
  449. package/dist/testing/conformance/fleet.d.ts +444 -0
  450. package/dist/testing/conformance/fleet.js +1009 -0
  451. package/dist/testing/conformance/groups.d.ts +7 -0
  452. package/dist/testing/conformance/groups.js +353 -0
  453. package/dist/testing/conformance/heap.d.ts +3 -0
  454. package/dist/testing/conformance/heap.js +149 -0
  455. package/dist/testing/conformance/http.d.ts +2809 -0
  456. package/dist/testing/conformance/http.js +1234 -0
  457. package/dist/testing/conformance/inspection-views.d.ts +8 -0
  458. package/dist/testing/conformance/inspection-views.js +272 -0
  459. package/dist/testing/conformance/inspector.d.ts +7 -0
  460. package/dist/testing/conformance/inspector.js +650 -0
  461. package/dist/testing/conformance/mint.d.ts +58 -0
  462. package/dist/testing/conformance/mint.js +692 -0
  463. package/dist/testing/conformance/multi-runner.d.ts +8 -0
  464. package/dist/testing/conformance/multi-runner.js +403 -0
  465. package/dist/testing/conformance/neki/plan.d.ts +19 -0
  466. package/dist/testing/conformance/neki/plan.js +30 -0
  467. package/dist/testing/conformance/observability.d.ts +3 -0
  468. package/dist/testing/conformance/observability.js +343 -0
  469. package/dist/testing/conformance/offline.d.ts +4 -0
  470. package/dist/testing/conformance/offline.js +474 -0
  471. package/dist/testing/conformance/operator-harness.d.ts +57 -0
  472. package/dist/testing/conformance/operator-harness.js +78 -0
  473. package/dist/testing/conformance/operator.d.ts +3 -0
  474. package/dist/testing/conformance/operator.js +379 -0
  475. package/dist/testing/conformance/outbox-cross-shard.d.ts +14 -0
  476. package/dist/testing/conformance/outbox-cross-shard.js +160 -0
  477. package/dist/testing/conformance/outbox.d.ts +36 -0
  478. package/dist/testing/conformance/outbox.js +437 -0
  479. package/dist/testing/conformance/payload-migrations.d.ts +3 -0
  480. package/dist/testing/conformance/payload-migrations.js +612 -0
  481. package/dist/testing/conformance/pipeline.d.ts +3 -0
  482. package/dist/testing/conformance/pipeline.js +1040 -0
  483. package/dist/testing/conformance/placement.d.ts +22 -0
  484. package/dist/testing/conformance/placement.js +539 -0
  485. package/dist/testing/conformance/platform.d.ts +40 -0
  486. package/dist/testing/conformance/platform.js +101 -0
  487. package/dist/testing/conformance/progress.d.ts +39 -0
  488. package/dist/testing/conformance/progress.js +666 -0
  489. package/dist/testing/conformance/properties.d.ts +6 -0
  490. package/dist/testing/conformance/properties.js +295 -0
  491. package/dist/testing/conformance/protocols.d.ts +4 -0
  492. package/dist/testing/conformance/protocols.js +618 -0
  493. package/dist/testing/conformance/provider/advertise.d.ts +21 -0
  494. package/dist/testing/conformance/provider/advertise.js +44 -0
  495. package/dist/testing/conformance/read-your-writes.d.ts +20 -0
  496. package/dist/testing/conformance/read-your-writes.js +192 -0
  497. package/dist/testing/conformance/reducers.d.ts +8 -0
  498. package/dist/testing/conformance/reducers.js +258 -0
  499. package/dist/testing/conformance/relay.d.ts +42 -0
  500. package/dist/testing/conformance/relay.js +1115 -0
  501. package/dist/testing/conformance/restore.d.ts +43 -0
  502. package/dist/testing/conformance/restore.js +341 -0
  503. package/dist/testing/conformance/retention.d.ts +14 -0
  504. package/dist/testing/conformance/retention.js +463 -0
  505. package/dist/testing/conformance/rls.d.ts +24 -0
  506. package/dist/testing/conformance/rls.js +576 -0
  507. package/dist/testing/conformance/simulation.d.ts +31 -0
  508. package/dist/testing/conformance/simulation.js +167 -0
  509. package/dist/testing/conformance/single-shard.d.ts +2 -0
  510. package/dist/testing/conformance/single-shard.js +125 -0
  511. package/dist/testing/conformance/singleton.d.ts +3 -0
  512. package/dist/testing/conformance/singleton.js +293 -0
  513. package/dist/testing/conformance/statements.d.ts +60 -0
  514. package/dist/testing/conformance/statements.js +108 -0
  515. package/dist/testing/conformance/streams.d.ts +7 -0
  516. package/dist/testing/conformance/streams.js +280 -0
  517. package/dist/testing/conformance/subscriptions/access.d.ts +4 -0
  518. package/dist/testing/conformance/subscriptions/access.js +98 -0
  519. package/dist/testing/conformance/subscriptions/actors.d.ts +4910 -0
  520. package/dist/testing/conformance/subscriptions/actors.js +372 -0
  521. package/dist/testing/conformance/subscriptions/cluster.d.ts +4 -0
  522. package/dist/testing/conformance/subscriptions/cluster.js +89 -0
  523. package/dist/testing/conformance/subscriptions/delivery.d.ts +4 -0
  524. package/dist/testing/conformance/subscriptions/delivery.js +253 -0
  525. package/dist/testing/conformance/subscriptions/deploys.d.ts +4 -0
  526. package/dist/testing/conformance/subscriptions/deploys.js +162 -0
  527. package/dist/testing/conformance/subscriptions/epochs.d.ts +4 -0
  528. package/dist/testing/conformance/subscriptions/epochs.js +169 -0
  529. package/dist/testing/conformance/subscriptions/failures.d.ts +4 -0
  530. package/dist/testing/conformance/subscriptions/failures.js +108 -0
  531. package/dist/testing/conformance/subscriptions/feeds.d.ts +4 -0
  532. package/dist/testing/conformance/subscriptions/feeds.js +218 -0
  533. package/dist/testing/conformance/subscriptions/harness.d.ts +124 -0
  534. package/dist/testing/conformance/subscriptions/harness.js +143 -0
  535. package/dist/testing/conformance/subscriptions/operator.d.ts +4 -0
  536. package/dist/testing/conformance/subscriptions/operator.js +128 -0
  537. package/dist/testing/conformance/subscriptions/retention.d.ts +4 -0
  538. package/dist/testing/conformance/subscriptions/retention.js +288 -0
  539. package/dist/testing/conformance/subscriptions/routing.d.ts +4 -0
  540. package/dist/testing/conformance/subscriptions/routing.js +179 -0
  541. package/dist/testing/conformance/subscriptions.d.ts +4 -0
  542. package/dist/testing/conformance/subscriptions.js +19 -0
  543. package/dist/testing/conformance/tables.d.ts +125 -0
  544. package/dist/testing/conformance/tables.js +664 -0
  545. package/dist/testing/conformance/transports/actors.d.ts +1907 -0
  546. package/dist/testing/conformance/transports/actors.js +163 -0
  547. package/dist/testing/conformance/transports/client.d.ts +3 -0
  548. package/dist/testing/conformance/transports/client.js +237 -0
  549. package/dist/testing/conformance/transports/feeds.d.ts +3 -0
  550. package/dist/testing/conformance/transports/feeds.js +232 -0
  551. package/dist/testing/conformance/transports/harness.d.ts +93 -0
  552. package/dist/testing/conformance/transports/harness.js +84 -0
  553. package/dist/testing/conformance/transports/streams.d.ts +3 -0
  554. package/dist/testing/conformance/transports/streams.js +96 -0
  555. package/dist/testing/conformance/transports/websocket.d.ts +3 -0
  556. package/dist/testing/conformance/transports/websocket.js +384 -0
  557. package/dist/testing/conformance/transports/wire.d.ts +141 -0
  558. package/dist/testing/conformance/transports/wire.js +204 -0
  559. package/dist/testing/conformance/transports.d.ts +3 -0
  560. package/dist/testing/conformance/transports.js +11 -0
  561. package/dist/testing/conformance/watch.d.ts +59 -0
  562. package/dist/testing/conformance/watch.js +879 -0
  563. package/dist/testing/conformance/workflow-engine.d.ts +97 -0
  564. package/dist/testing/conformance/workflow-engine.js +253 -0
  565. package/dist/testing/conformance/workflow-versions.d.ts +3 -0
  566. package/dist/testing/conformance/workflow-versions.js +545 -0
  567. package/dist/testing/conformance/workflows/access.d.ts +4 -0
  568. package/dist/testing/conformance/workflows/access.js +147 -0
  569. package/dist/testing/conformance/workflows/actors.d.ts +2317 -0
  570. package/dist/testing/conformance/workflows/actors.js +305 -0
  571. package/dist/testing/conformance/workflows/basics.d.ts +4 -0
  572. package/dist/testing/conformance/workflows/basics.js +144 -0
  573. package/dist/testing/conformance/workflows/engine.d.ts +4 -0
  574. package/dist/testing/conformance/workflows/engine.js +80 -0
  575. package/dist/testing/conformance/workflows/guards.d.ts +4 -0
  576. package/dist/testing/conformance/workflows/guards.js +172 -0
  577. package/dist/testing/conformance/workflows/harness.d.ts +14 -0
  578. package/dist/testing/conformance/workflows/harness.js +44 -0
  579. package/dist/testing/conformance/workflows/recovery.d.ts +4 -0
  580. package/dist/testing/conformance/workflows/recovery.js +181 -0
  581. package/dist/testing/conformance/workflows/starts.d.ts +4 -0
  582. package/dist/testing/conformance/workflows/starts.js +57 -0
  583. package/dist/testing/conformance/workflows/suspension.d.ts +4 -0
  584. package/dist/testing/conformance/workflows/suspension.js +106 -0
  585. package/dist/testing/conformance/workflows/waits.d.ts +4 -0
  586. package/dist/testing/conformance/workflows/waits.js +284 -0
  587. package/dist/testing/conformance/workflows.d.ts +4 -0
  588. package/dist/testing/conformance/workflows.js +19 -0
  589. package/dist/testing/conformance.d.ts +330 -0
  590. package/dist/testing/conformance.js +364 -0
  591. package/dist/testing/database.d.ts +31 -0
  592. package/dist/testing/database.js +70 -0
  593. package/dist/testing/foundation.d.ts +41 -0
  594. package/dist/testing/foundation.js +517 -0
  595. package/dist/testing/index.d.ts +20 -0
  596. package/dist/testing/index.js +12 -0
  597. package/dist/testing/property.d.ts +40 -0
  598. package/dist/testing/property.js +95 -0
  599. package/dist/testing/simulate-cluster.d.ts +112 -0
  600. package/dist/testing/simulate-cluster.js +257 -0
  601. package/dist/testing/simulate.d.ts +90 -0
  602. package/dist/testing/simulate.js +127 -0
  603. package/package.json +1 -0
@@ -0,0 +1,167 @@
1
+ import { Console, Effect, Layer, Schema } from "effect";
2
+ import { Actor } from "../../index.js";
3
+ import { ActorTest } from "../actor-test.js";
4
+ import { ActorCluster } from "../cluster.js";
5
+ import { clusterSimulationSeeds } from "../simulate-cluster.js";
6
+ const Add = Actor.command("Add", { payload: Schema.Int, success: Schema.Int });
7
+ const Credit = Actor.command("Credit", { payload: Schema.Int });
8
+ const Pay = Actor.command("Pay", {
9
+ payload: Schema.Struct({ to: Schema.String, amount: Schema.Int }),
10
+ });
11
+ const total = Actor.state({ total: Schema.Int.pipe(Schema.withDecodingDefault(Effect.succeed(0))) });
12
+ const Tally = Actor.make("SimClusterTally", { key: Schema.String, state: total, api: { Add } });
13
+ const Wallet = Actor.make("SimClusterWallet", {
14
+ key: Schema.String,
15
+ state: total,
16
+ api: {},
17
+ internal: { Credit },
18
+ });
19
+ const Payer = Actor.make("SimClusterPayer", { key: Schema.String, api: { Pay } });
20
+ export const simulationActors = Layer.mergeAll(Tally.toLayer(Effect.succeed({
21
+ Add: Effect.fnUntraced(function* (amount) {
22
+ const turn = yield* Tally.Turn;
23
+ yield* turn.state.set({ total: turn.state.total + amount });
24
+ return turn.state.total;
25
+ }),
26
+ })), Wallet.toLayer(Effect.succeed({
27
+ Credit: Effect.fnUntraced(function* (amount) {
28
+ const turn = yield* Wallet.Turn;
29
+ yield* turn.state.set({ total: turn.state.total + amount });
30
+ }),
31
+ })), Payer.toLayer(Effect.succeed({
32
+ Pay: Effect.fnUntraced(function* ({ to, amount }) {
33
+ yield* (yield* Wallet.intents(to)).Credit(amount);
34
+ }),
35
+ })));
36
+ /**
37
+ * Direct adds and relayed payments on a few actors, sent through `commands`
38
+ * commands of a seeded cluster simulation, then the totals each actor holds
39
+ * against the sums the script sent. Actor names carry `tag`, so scripts of
40
+ * several runs share a cluster without sharing state.
41
+ */
42
+ export const clusterScript = ({ expect, options, commands, tag = options.seed, }) => Effect.gen(function* () {
43
+ const cluster = yield* ActorCluster;
44
+ const expected = new Map();
45
+ const report = yield* ActorTest.simulateCluster({ ...options, commands }, (sim) => Effect.gen(function* () {
46
+ for (let index = 0; index < commands; index++) {
47
+ const amount = yield* sim.int(1, 9);
48
+ const name = `${tag}-${yield* sim.pick(["a", "b", "c"])}`;
49
+ if ((yield* sim.int(0, 1)) === 0) {
50
+ const reply = yield* sim.command(`add ${name}`, Tally.get(name).pipe(Effect.flatMap((tally) => tally.Add(amount))));
51
+ expected.set(`tally:${name}`, (expected.get(`tally:${name}`) ?? 0) + amount);
52
+ expect(reply).toBe(expected.get(`tally:${name}`));
53
+ }
54
+ else {
55
+ yield* sim.command(`pay ${name}`, Payer.get(`${tag}-payer`).pipe(Effect.flatMap((payer) => payer.Pay({ to: name, amount }))));
56
+ expected.set(`wallet:${name}`, (expected.get(`wallet:${name}`) ?? 0) + amount);
57
+ }
58
+ }
59
+ }));
60
+ const held = new Map();
61
+ for (const key of expected.keys()) {
62
+ const [kind, name] = key.split(":");
63
+ held.set(key, (yield* cluster.on(0)(Effect.gen(function* () {
64
+ const test = yield* ActorTest;
65
+ const handle = kind === "tally" ? yield* Tally.get(name) : yield* Wallet.get(name);
66
+ return yield* test.inspect(handle.ref);
67
+ }))).state);
68
+ }
69
+ return { report, expected, held };
70
+ });
71
+ const clusterOn = (environment, body) => Effect.gen(function* () {
72
+ const database = yield* environment.freshDatabase;
73
+ const context = yield* Layer.build(ActorTest.cluster({
74
+ database,
75
+ runners: 3,
76
+ shardLockExpiration: "3 seconds",
77
+ actors: simulationActors,
78
+ relay: { poll: "100 millis" },
79
+ }));
80
+ return yield* body.pipe(Effect.provideContext(context));
81
+ }).pipe(Effect.scoped);
82
+ const withCluster = (environment, body) => environment.run(clusterOn(environment, body));
83
+ export const sums = (expected) => new Map(Array.from(expected, ([key, sum]) => [key, { total: sum }]));
84
+ /**
85
+ * Each seed gets a cluster of its own: settling moves the runners' clocks, and
86
+ * a runner restarted by one seed's kill would start the next one behind them.
87
+ * The seeded case logs each seed's schedule tagged `CLUSTER_SIMULATION`, so a
88
+ * night's schedules can be read from its log.
89
+ */
90
+ export const simulationConformance = [
91
+ {
92
+ name: "keeps receipts and outbox delivery exactly once across seeded runner kills, lost heartbeats, crashes, and lost connections on three runners",
93
+ requiresIndependentConnections: true,
94
+ timeoutMs: 1_800_000,
95
+ run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
96
+ for (const seed of yield* clusterSimulationSeeds)
97
+ yield* clusterOn(environment, Effect.gen(function* () {
98
+ const { report, expected, held } = yield* clusterScript({
99
+ expect,
100
+ options: {
101
+ seed: `c${seed}`,
102
+ faults: [
103
+ "crashBeforeCommit",
104
+ "crashAfterCommit",
105
+ "dropReply",
106
+ "runnerKill",
107
+ "heartbeatLoss",
108
+ "connectionLoss",
109
+ ],
110
+ },
111
+ commands: 8,
112
+ });
113
+ yield* Console.error(`CLUSTER_SIMULATION seed=${seed} ${report.steps
114
+ .map(({ fault, point, landed }) => `${fault}${landed ? "+landed" : ""}@${point}`)
115
+ .join(" ")}`);
116
+ expect(report.steps.length).toBe(8);
117
+ expect(held).toEqual(sums(expected));
118
+ }));
119
+ })),
120
+ },
121
+ {
122
+ name: "reruns a seed on three runners to the same fault schedule and outcome",
123
+ requiresIndependentConnections: true,
124
+ timeoutMs: 300_000,
125
+ run: ({ expect, environment }) => withCluster(environment, Effect.gen(function* () {
126
+ const options = {
127
+ seed: "repeat",
128
+ faults: ["crashBeforeCommit", "crashAfterCommit", "dropReply", "connectionLoss"],
129
+ faultRate: 0.8,
130
+ };
131
+ const first = yield* clusterScript({ expect, options, commands: 6, tag: "first" });
132
+ const second = yield* clusterScript({ expect, options, commands: 6, tag: "second" });
133
+ const schedule = (run) => run.report.steps.map(({ label, fault, runner, point, landed }) => [
134
+ label.split(" ")[0],
135
+ fault,
136
+ runner,
137
+ point,
138
+ landed,
139
+ ]);
140
+ expect(schedule(second)).toEqual(schedule(first));
141
+ expect(first.report.steps.some(({ fault }) => fault === "connectionLoss")).toBe(true);
142
+ expect(Array.from(second.expected.values())).toEqual(Array.from(first.expected.values()));
143
+ expect(second.held).toEqual(sums(second.expected));
144
+ })),
145
+ },
146
+ {
147
+ name: "dies with the seed when a cluster program sends no command",
148
+ requiresIndependentConnections: true,
149
+ timeoutMs: 60_000,
150
+ run: ({ expect, environment }) => withCluster(environment, Effect.gen(function* () {
151
+ const failure = yield* ActorTest.simulateCluster({ seed: "empty", faults: ["runnerKill"] }, () => Effect.void).pipe(Effect.exit);
152
+ expect(String(failure)).toContain("Simulation failed with seed empty");
153
+ expect(String(failure)).toContain("the program sent no command");
154
+ })),
155
+ },
156
+ {
157
+ name: "refuses a primary failover without a primary to fail over or a command count",
158
+ requiresIndependentConnections: true,
159
+ timeoutMs: 60_000,
160
+ run: ({ expect, environment }) => withCluster(environment, Effect.gen(function* () {
161
+ const unwired = yield* ActorTest.simulateCluster({ seed: "failover", faults: ["primaryFailover"], commands: 1 }, () => Effect.void).pipe(Effect.exit);
162
+ expect(String(unwired)).toContain("primaryFailover needs the primary option");
163
+ const uncounted = yield* ActorTest.simulateCluster({ seed: "failover", faults: ["primaryFailover"], primary: Effect.void }, () => Effect.void).pipe(Effect.exit);
164
+ expect(String(uncounted)).toContain("primaryFailover needs the number of commands");
165
+ })),
166
+ },
167
+ ];
@@ -0,0 +1,2 @@
1
+ import type { ConformanceCase } from "../conformance.ts";
2
+ export declare const singleShardConformance: ReadonlyArray<ConformanceCase>;
@@ -0,0 +1,125 @@
1
+ import { Effect } from "effect";
2
+ import { SqlClient } from "effect/sql";
3
+ import { ActorTest } from "../actor-test.js";
4
+ import { touchesOneShard } from "./neki/plan.js";
5
+ import { mintSuite, mintWorkload, planAcrossShard } from "./mint.js";
6
+ import { placementWorkload } from "./placement.js";
7
+ import { scopeOf, statementLog } from "./statements.js";
8
+ /**
9
+ * Drives a turn, a wake, a due-work scan, and the parent families of the
10
+ * placement fixtures, and returns every statement the runtime compiled while it
11
+ * did. The suite's runtime stops meanwhile: the first runtime creates the
12
+ * actors, and a second one wakes them from storage, so the recorder sits on
13
+ * runtimes of this case alone. The suite's runtime is running again on return.
14
+ * Start-up runs its own migrations and registry reads, so recording starts
15
+ * only once a runtime has finished starting.
16
+ */
17
+ const frameworkStatements = (environment) => Effect.gen(function* () {
18
+ const log = statementLog();
19
+ const on = (effect, record) => Effect.acquireUseRelease(Effect.sync(() => environment.build({ observe: log.observe })), (runtime) => Effect.promise(() => runtime.runPromise(Effect.void)).pipe(Effect.andThen(Effect.sync(() => {
20
+ log.recording = record;
21
+ })), Effect.andThen(Effect.promise(() => runtime.runPromise(Effect.scoped(effect)))), Effect.ensuring(Effect.sync(() => {
22
+ log.recording = false;
23
+ }))), (runtime) => Effect.promise(() => runtime.dispose()));
24
+ yield* environment.stop;
25
+ yield* on(placementWorkload.create, false);
26
+ yield* on(Effect.gen(function* () {
27
+ yield* placementWorkload.wake;
28
+ yield* mintWorkload;
29
+ yield* (yield* ActorTest).advance("2 hours");
30
+ }), true).pipe(Effect.ensuring(environment.restart));
31
+ return Array.from(log.seen.values());
32
+ });
33
+ const byScope = (statements) => {
34
+ const scopes = {
35
+ "table-free": [],
36
+ keyed: [],
37
+ scan: [],
38
+ registry: [],
39
+ unkeyed: [],
40
+ };
41
+ for (const statement of statements)
42
+ scopes[scopeOf(statement.sql)].push(statement);
43
+ return scopes;
44
+ };
45
+ /** The statements whose Neki plan reaches anything other than one shard, with the plan. */
46
+ const scatteredOf = (environment, statements) => Effect.promise(() => environment.run(Effect.gen(function* () {
47
+ const sql = yield* SqlClient.SqlClient;
48
+ const scattered = [];
49
+ for (const { sql: statement, params } of statements) {
50
+ const rows = yield* sql
51
+ .unsafe(`EXPLAIN (NEKI_PLAN, COSTS OFF, FORMAT TEXT) ${statement}`, params)
52
+ .values.pipe(Effect.orDie);
53
+ const plan = rows.map(([line]) => String(line)).join("\n");
54
+ if (!touchesOneShard(plan))
55
+ scattered.push({ statement: statement.slice(0, 160), plan });
56
+ }
57
+ return scattered;
58
+ })));
59
+ export const singleShardConformance = [
60
+ {
61
+ name: "single-shard: a minted child's first turn touches only its own routing key, not its parent's outbox",
62
+ run: ({ expect, environment, fixtureOf }) => Effect.runPromise(Effect.gen(function* () {
63
+ const log = statementLog();
64
+ const fixture = fixtureOf(mintSuite);
65
+ let child;
66
+ yield* environment.stop;
67
+ yield* Effect.acquireUseRelease(Effect.sync(() => environment.build({ observe: log.observe })), (runtime) => Effect.promise(() => runtime.runPromise(Effect.gen(function* () {
68
+ child = yield* planAcrossShard("child-statements");
69
+ fixture.onTurn = (point, request) => {
70
+ if (request.ref.id !== child.ref.id)
71
+ return;
72
+ if (point === "afterClaim")
73
+ log.recording = true;
74
+ if (point === "beforeOutboxDelete")
75
+ log.recording = false;
76
+ };
77
+ yield* (yield* ActorTest).advance("1 minute");
78
+ }))), (runtime) => Effect.promise(() => runtime.dispose()).pipe(Effect.ensuring(Effect.sync(() => {
79
+ fixture.onTurn = undefined;
80
+ log.recording = false;
81
+ })))).pipe(Effect.ensuring(environment.restart));
82
+ const statements = Array.from(log.seen.values());
83
+ const scopes = byScope(statements);
84
+ expect(scopes.keyed.length > 0).toBe(true);
85
+ expect(scopes.unkeyed).toEqual([]);
86
+ expect(scopes.scan).toEqual([]);
87
+ expect(scopes.registry).toEqual([]);
88
+ expect(scopes.keyed
89
+ .filter(({ params }) => !params.some((value) => String(value) === String(child.childKey)))
90
+ .map(({ sql }) => sql)).toEqual([]);
91
+ expect(statements
92
+ .filter(({ params }) => params.some((value) => String(value) === String(child.parentKey)))
93
+ .map(({ sql }) => sql)).toEqual([]);
94
+ expect(statements.filter(({ sql }) => /\bactor_outbox\b/.test(sql))).toEqual([]);
95
+ })),
96
+ },
97
+ {
98
+ name: "single-shard: every framework statement of a turn, a wake, and a due-work scan names its routing key or its bucket range",
99
+ run: ({ expect, environment }) => Effect.runPromise(Effect.gen(function* () {
100
+ const scopes = byScope(yield* frameworkStatements(environment));
101
+ expect(scopes.keyed.length > 10).toBe(true);
102
+ expect(scopes.scan.length).toBe(2);
103
+ expect(scopes.scan.every(({ sql }) => /generate_series\(\$\d+::int, \$\d+::int\)/.test(sql))).toBe(true);
104
+ expect(scopes.unkeyed.map(({ sql }) => sql)).toEqual([]);
105
+ })),
106
+ },
107
+ {
108
+ name: "single-shard: EXPLAIN (NEKI_PLAN) plans every keyed framework statement of a turn and a wake on one shard",
109
+ requiresNeki: true,
110
+ timeoutMs: 120_000,
111
+ run: ({ expect, environment }) => Effect.runPromise(Effect.gen(function* () {
112
+ const scopes = byScope(yield* frameworkStatements(environment));
113
+ expect(yield* scatteredOf(environment, scopes.keyed)).toEqual([]);
114
+ })),
115
+ },
116
+ {
117
+ name: "single-shard: EXPLAIN (NEKI_PLAN) plans each due-work scan statement on one shard",
118
+ requiresNeki: true,
119
+ timeoutMs: 120_000,
120
+ run: ({ expect, environment }) => Effect.runPromise(Effect.gen(function* () {
121
+ const scopes = byScope(yield* frameworkStatements(environment));
122
+ expect(yield* scatteredOf(environment, scopes.scan)).toEqual([]);
123
+ })),
124
+ },
125
+ ];
@@ -0,0 +1,3 @@
1
+ import type { ConformanceCase } from "../conformance.ts";
2
+ /** Singleton cases: one activation and one background loop across three runners, and takeover by one survivor after a kill. */
3
+ export declare const singletonConformance: ReadonlyArray<ConformanceCase>;
@@ -0,0 +1,293 @@
1
+ import { Cause, DateTime, Effect, Exit, Layer, Option, Schedule, Schema } from "effect";
2
+ import { SqlClient } from "effect/sql";
3
+ import { Actor } from "../../index.js";
4
+ import { InternalActors } from "../../runtime/actors.js";
5
+ import { ActorTest } from "../actor-test.js";
6
+ import { ActorCluster } from "../cluster.js";
7
+ /** A tick from `loop`, committed by the activation whose loop is `by`. */
8
+ const Ticked = Actor.event("Ticked", { loop: Schema.String, by: Schema.String });
9
+ const Tick = Actor.command("Tick", { payload: Schema.String, success: Schema.Finite });
10
+ const Log = Actor.query("Log", {
11
+ success: Schema.Array(Schema.Struct({
12
+ cursor: Schema.String,
13
+ loop: Schema.String,
14
+ by: Schema.String,
15
+ at: Schema.Finite,
16
+ })),
17
+ });
18
+ const Beacon = Actor.make("Beacon", {
19
+ key: Actor.singleton,
20
+ state: Actor.state({ ticks: Schema.Finite.pipe(Schema.withDecodingDefault(Effect.succeed(0))) }),
21
+ events: [Ticked],
22
+ api: { Tick, Log },
23
+ });
24
+ /** Every loop each cluster's singleton started, keyed by the cluster's tenant. */
25
+ const loops = new Map();
26
+ /** The most loops of one tenant live at once, checked whenever a loop starts. */
27
+ const peaks = new Map();
28
+ const peakOf = (tenant) => peaks.get(tenant) ?? 0;
29
+ const startedLoops = () => [...loops.values()].reduce((total, started) => total + started.length, 0);
30
+ const liveOf = (tenant) => loopsOf(tenant).filter(({ live }) => live);
31
+ const loopsOf = (tenant) => loops.get(tenant) ?? [];
32
+ const TICK_INTERVAL = "50 millis";
33
+ /**
34
+ * A singleton whose build forks one background loop. The loop shows it ran
35
+ * only by sending `Tick` commands, so every tick it made is a committed turn.
36
+ */
37
+ const BeaconLive = Layer.mergeAll(Beacon.toLayer(Effect.gen(function* () {
38
+ const beacon = yield* Beacon.get();
39
+ const started = loops.get(beacon.ref.tenant) ?? [];
40
+ loops.set(beacon.ref.tenant, started);
41
+ const loop = {
42
+ id: `loop-${started.length + 1}`,
43
+ startedAt: performance.now(),
44
+ stoppedAt: undefined,
45
+ live: true,
46
+ closed: false,
47
+ attempts: 0,
48
+ refused: [],
49
+ };
50
+ started.push(loop);
51
+ peaks.set(beacon.ref.tenant, Math.max(peakOf(beacon.ref.tenant), started.filter(({ live }) => live).length));
52
+ yield* Effect.forkScoped(Effect.gen(function* () {
53
+ loop.attempts += 1;
54
+ yield* beacon.Tick(loop.id).pipe(Effect.catch((error) => Effect.sync(() => {
55
+ loop.refused.push(error.reason);
56
+ })));
57
+ }).pipe(Effect.repeat(Schedule.spaced(TICK_INTERVAL)), Effect.ensuring(Effect.sync(() => {
58
+ loop.live = false;
59
+ loop.stoppedAt = performance.now();
60
+ }))), { startImmediately: true });
61
+ yield* Effect.addFinalizer(() => Effect.sync(() => {
62
+ loop.closed = true;
63
+ }));
64
+ return {
65
+ Tick: Effect.fnUntraced(function* (from) {
66
+ const turn = yield* Beacon.Turn;
67
+ yield* turn.state.set({ ticks: turn.state.ticks + 1 });
68
+ yield* turn.emit(Ticked.make({ loop: from, by: loop.id }));
69
+ return turn.state.ticks;
70
+ }),
71
+ };
72
+ })), Beacon.toQueryLayer(Effect.succeed({
73
+ Log: Effect.fnUntraced(function* () {
74
+ const entries = yield* (yield* Beacon.Read).events(Ticked);
75
+ return entries.map(({ cursor, event, timestamp }) => ({
76
+ cursor,
77
+ loop: event.loop,
78
+ by: event.by,
79
+ at: DateTime.toEpochMillis(timestamp),
80
+ }));
81
+ }, Effect.orDie),
82
+ })));
83
+ const EXPIRATION_SECONDS = 3;
84
+ const singletonCluster = (database, runners) => ActorTest.cluster({
85
+ database,
86
+ runners,
87
+ shardLockExpiration: `${EXPIRATION_SECONDS} seconds`,
88
+ actors: BeaconLive,
89
+ });
90
+ /** Builds a fresh database and a cluster of `runners` serving the singleton. */
91
+ const withSingletonCluster = (environment, runners, body) => environment.run(Effect.gen(function* () {
92
+ const database = yield* environment.freshDatabase;
93
+ const context = yield* Layer.build(singletonCluster(database, runners));
94
+ return yield* body.pipe(Effect.provideContext(context));
95
+ }));
96
+ const on = (runner) => (effect) => Effect.gen(function* () {
97
+ const cluster = yield* ActorCluster;
98
+ return yield* cluster.on(runner)(effect);
99
+ });
100
+ const beaconRef = (runner) => on(runner)(Beacon.get().pipe(Effect.map((beacon) => beacon.ref)));
101
+ const logOf = (runner) => on(runner)(Beacon.get().pipe(Effect.flatMap((beacon) => beacon.Log())));
102
+ const tickFrom = (runner, from) => on(runner)(Beacon.get().pipe(Effect.flatMap((beacon) => beacon.Tick(from))));
103
+ const inspectOn = (runner, ref) => on(runner)(ActorTest.use((test) => test.inspect(ref)));
104
+ /** Polls `runner`'s view of the log until `accept` holds. */
105
+ const awaitLog = (runner, accept, what) => logOf(runner).pipe(Effect.repeat({ schedule: Schedule.spaced("20 millis"), until: accept }), Effect.timeoutOrElse({
106
+ duration: "30 seconds",
107
+ orElse: () => Effect.die(new Error(`Timed out waiting for ${what}`)),
108
+ }));
109
+ /** Polls until `check` holds. */
110
+ const awaitThat = (check, what) => Effect.sync(check).pipe(Effect.repeat({ schedule: Schedule.spaced("20 millis"), until: (held) => held }), Effect.timeoutOrElse({
111
+ duration: "30 seconds",
112
+ orElse: () => Effect.die(new Error(`Timed out waiting for ${what}`)),
113
+ }));
114
+ /** A shard lock row with database-clock times in epoch milliseconds. */
115
+ const lockOf = (runner, ref) => on(runner)(Effect.gen(function* () {
116
+ const sql = yield* SqlClient.SqlClient;
117
+ const shard = yield* (yield* InternalActors).shardId(ref);
118
+ const [row] = yield* sql `
119
+ SELECT address,
120
+ (EXTRACT(EPOCH FROM acquired_at) * 1000)::float8 AS acquired,
121
+ (EXTRACT(EPOCH FROM LOCALTIMESTAMP) * 1000)::float8 AS now
122
+ FROM cluster_locks WHERE shard_id = ${shard}`.pipe(Effect.orDie);
123
+ return row;
124
+ }));
125
+ /**
126
+ * Waits for the cluster's shards to settle and returns the one live loop once
127
+ * it has committed a tick; rebalancing while runners join may move the
128
+ * singleton, and so restart its loop, before that.
129
+ */
130
+ const settled = Effect.gen(function* () {
131
+ const cluster = yield* ActorCluster;
132
+ const ref = yield* beaconRef(0);
133
+ yield* cluster.ready;
134
+ yield* awaitThat(() => liveOf(ref.tenant).length === 1, "one live loop");
135
+ const loop = liveOf(ref.tenant)[0];
136
+ yield* awaitLog(0, (log) => log.some(({ by }) => by === loop.id), "a settled tick");
137
+ return { ref, loop, before: loopsOf(ref.tenant).length };
138
+ });
139
+ /**
140
+ * Waits until one loop is live and its activation committed the log's last
141
+ * five ticks, and returns that loop.
142
+ */
143
+ const steady = (runner, tenant) => Effect.gen(function* () {
144
+ const [live] = liveOf(tenant);
145
+ const tail = (yield* logOf(runner)).slice(-5);
146
+ return live !== undefined &&
147
+ liveOf(tenant).length === 1 &&
148
+ tail.length === 5 &&
149
+ tail.every(({ by }) => by === live.id)
150
+ ? Option.some(live)
151
+ : Option.none();
152
+ }).pipe(Effect.repeat({ schedule: Schedule.spaced("25 millis"), until: Option.isSome }), Effect.map(Option.getOrThrow), Effect.timeoutOrElse({
153
+ duration: "30 seconds",
154
+ orElse: () => Effect.die(new Error("Timed out waiting for one steady loop")),
155
+ }));
156
+ /**
157
+ * The activations that committed a log, in commit order with consecutive
158
+ * duplicates collapsed. Each activation's commits are one unbroken run when
159
+ * none commits after its successor has.
160
+ */
161
+ const runs = (log) => log.flatMap(({ by }, index) => (index === 0 || log[index - 1].by !== by ? [by] : []));
162
+ const unbroken = (log) => new Set(runs(log)).size === runs(log).length;
163
+ const contiguous = (log) => log.every(({ cursor }, index) => cursor === String(index + 1));
164
+ /** Singleton cases: one activation and one background loop across three runners, and takeover by one survivor after a kill. */
165
+ export const singletonConformance = [
166
+ {
167
+ name: "keeps one singleton activation and one background loop across three runners",
168
+ requiresIndependentConnections: true,
169
+ timeoutMs: 60_000,
170
+ run: ({ expect, environment }) => withSingletonCluster(environment, 3, Effect.gen(function* () {
171
+ const cluster = yield* ActorCluster;
172
+ const { ref, loop, before } = yield* settled;
173
+ for (const runner of [0, 1, 2])
174
+ yield* tickFrom(runner, `runner-${runner}`);
175
+ yield* awaitLog(1, (log) => log.filter(({ loop: from }) => from === loop.id).length >= 20, "twenty ticks from the settled loop");
176
+ const log = yield* logOf(2);
177
+ expect(peakOf(ref.tenant)).toBe(1);
178
+ expect(loopsOf(ref.tenant).length).toBe(before);
179
+ expect(liveOf(ref.tenant)).toEqual([loop]);
180
+ expect(unbroken(log)).toBe(true);
181
+ expect(runs(log).at(-1)).toBe(loop.id);
182
+ expect(contiguous(log)).toBe(true);
183
+ for (const runner of [0, 1, 2])
184
+ expect(log.find(({ loop: from }) => from === `runner-${runner}`)?.by).toBe(loop.id);
185
+ expect(loop.refused).toEqual([]);
186
+ const inspection = yield* inspectOn(1, ref);
187
+ expect(inspection.receipts).toBe(inspection.events);
188
+ expect(inspection.receipts >= log.length).toBe(true);
189
+ expect((yield* cluster.owner(ref)) === undefined).toBe(false);
190
+ })),
191
+ },
192
+ {
193
+ name: "registers a singleton's type before its entity can activate",
194
+ requiresIndependentConnections: true,
195
+ timeoutMs: 60_000,
196
+ run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
197
+ const database = yield* environment.freshDatabase;
198
+ yield* Effect.gen(function* () {
199
+ const context = yield* Layer.build(singletonCluster(database, 1));
200
+ yield* on(0)(Effect.gen(function* () {
201
+ const sql = yield* SqlClient.SqlClient;
202
+ yield* sql `INSERT INTO actor_routed_subscriptions (source_type, subscriber_type, subscription)
203
+ VALUES ('Beacon', 'Absent', 'Watch')`.pipe(Effect.orDie);
204
+ })).pipe(Effect.provideContext(context));
205
+ }).pipe(Effect.scoped);
206
+ const before = startedLoops();
207
+ const exit = yield* Layer.build(singletonCluster(database, 1)).pipe(Effect.scoped, Effect.exit);
208
+ expect(Exit.isFailure(exit) &&
209
+ Cause.pretty(exit.cause).includes("Actor Beacon is registered without the subscriber types that route from it")).toBe(true);
210
+ expect(startedLoops()).toBe(before);
211
+ })),
212
+ },
213
+ {
214
+ name: "moves the singleton and its loop to exactly one survivor after its runner is killed",
215
+ requiresIndependentConnections: true,
216
+ timeoutMs: 90_000,
217
+ run: ({ expect, environment }) => withSingletonCluster(environment, 3, Effect.gen(function* () {
218
+ const cluster = yield* ActorCluster;
219
+ const { ref, loop, before } = yield* settled;
220
+ const owner = (yield* cluster.owner(ref));
221
+ const survivor = (owner + 1) % 3;
222
+ const killed = (yield* lockOf(survivor, ref)).now;
223
+ yield* cluster.kill(owner);
224
+ const held = yield* lockOf(survivor, ref);
225
+ const taken = yield* lockOf(survivor, ref).pipe(Effect.repeat({
226
+ schedule: Schedule.spaced("20 millis"),
227
+ until: ({ address }) => address !== held.address,
228
+ }), Effect.timeoutOrElse({
229
+ duration: "30 seconds",
230
+ orElse: () => Effect.die(new Error("Timed out waiting for the shard's takeover")),
231
+ }));
232
+ yield* awaitThat(() => loopsOf(ref.tenant).length > before, "a survivor's loop");
233
+ const successor = loopsOf(ref.tenant)[before];
234
+ const log = yield* awaitLog(survivor, (entries) => entries.filter(({ by }) => by === successor.id).length >= 10, "the survivor's loop to tick");
235
+ const next = (yield* cluster.owner(ref));
236
+ expect(next === owner).toBe(false);
237
+ const expired = held.acquired + EXPIRATION_SECONDS * 1000;
238
+ expect(taken.acquired >= expired).toBe(true);
239
+ expect(taken.acquired >= killed).toBe(true);
240
+ expect(loopsOf(ref.tenant).length).toBe(before + 1);
241
+ expect(unbroken(log)).toBe(true);
242
+ expect(runs(log).slice(-2)).toEqual([loop.id, successor.id]);
243
+ expect(contiguous(log)).toBe(true);
244
+ const resumed = log.find(({ by }) => by === successor.id);
245
+ expect(resumed.at >= expired).toBe(true);
246
+ yield* awaitThat(() => !loop.live, "the dead runner's loop to stop");
247
+ expect(liveOf(ref.tenant)).toEqual([successor]);
248
+ expect(successor.refused).toEqual([]);
249
+ const inspection = yield* inspectOn(next, ref);
250
+ expect(inspection.receipts).toBe(inspection.events);
251
+ })),
252
+ },
253
+ {
254
+ name: "stops a heartbeat-paused singleton owner's loop before its successor starts and fences its commits",
255
+ requiresIndependentConnections: true,
256
+ timeoutMs: 90_000,
257
+ run: ({ expect, environment }) => withSingletonCluster(environment, 2, Effect.gen(function* () {
258
+ const cluster = yield* ActorCluster;
259
+ const { ref, loop: zombie, before } = yield* settled;
260
+ const paused = (yield* cluster.owner(ref));
261
+ const rival = 1 - paused;
262
+ const first = Number((yield* inspectOn(rival, ref)).generation);
263
+ const heartbeat = yield* cluster.pauseHeartbeat(paused);
264
+ yield* awaitThat(() => loopsOf(ref.tenant).length > before, "the rival's loop");
265
+ const successor = loopsOf(ref.tenant)[before];
266
+ yield* awaitLog(rival, (entries) => entries.filter(({ by }) => by === successor.id).length >= 10, "the rival's activation to commit");
267
+ expect(yield* cluster.owner(ref)).toBe(rival);
268
+ expect(zombie.live).toBe(false);
269
+ expect(zombie.stoppedAt < successor.startedAt).toBe(true);
270
+ yield* Effect.sleep(`${EXPIRATION_SECONDS} seconds`);
271
+ expect(loopsOf(ref.tenant).length).toBe(before + 1);
272
+ expect(liveOf(ref.tenant)).toEqual([successor]);
273
+ expect(peakOf(ref.tenant)).toBe(1);
274
+ const split = yield* logOf(rival);
275
+ expect(unbroken(split)).toBe(true);
276
+ expect(contiguous(split)).toBe(true);
277
+ const moved = split.findIndex(({ by }) => by === successor.id);
278
+ expect(split.slice(moved).some(({ by }) => by === zombie.id)).toBe(false);
279
+ yield* heartbeat.resume;
280
+ yield* cluster.ready;
281
+ const live = yield* steady(rival, ref.tenant);
282
+ yield* tickFrom(paused, "after-resume");
283
+ const log = yield* logOf(rival);
284
+ expect(unbroken(log)).toBe(true);
285
+ expect(contiguous(log)).toBe(true);
286
+ expect(log.find(({ loop }) => loop === "after-resume")?.by).toBe(live.id);
287
+ expect(liveOf(ref.tenant)).toEqual([live]);
288
+ const inspection = yield* inspectOn(rival, ref);
289
+ expect(inspection.receipts).toBe(inspection.events);
290
+ expect(Number(inspection.generation) > first).toBe(true);
291
+ })),
292
+ },
293
+ ];
@@ -0,0 +1,60 @@
1
+ import type { Statement } from "effect/sql";
2
+ export interface RecordedStatement {
3
+ /** The compiled text, whitespace collapsed. */
4
+ readonly sql: string;
5
+ /** The parameters of the first run of this text. */
6
+ readonly params: ReadonlyArray<unknown>;
7
+ }
8
+ /**
9
+ * Tables that hold one row per deployment, per actor type, or per runner
10
+ * rather than per actor, so no `routing_key` names them. Cluster's own
11
+ * `cluster_*` tables are the same: they stay together in one shard group.
12
+ */
13
+ export declare const REGISTRY_TABLES: ReadonlySet<string>;
14
+ export type StatementScope =
15
+ /** Reads no table: a clock, a setting, or a transaction command. */
16
+ "table-free"
17
+ /** Names a `routing_key` in a predicate or an insert list. */
18
+ | "keyed"
19
+ /** Probes an index range of `bucket`, the top bits of `routing_key`, without naming a key. */
20
+ | "scan"
21
+ /** Touches only per-deployment tables. */
22
+ | "registry"
23
+ /** Touches a table without naming a routing key. */
24
+ | "unkeyed";
25
+ export declare const scopeOf: (sql: string) => StatementScope;
26
+ /** The statements the runtime compiled while recording, first sighting of each text. */
27
+ export interface StatementLog {
28
+ recording: boolean;
29
+ readonly seen: Map<string, RecordedStatement>;
30
+ readonly observe: (statement: Statement.Statement<unknown>) => void;
31
+ }
32
+ export declare const statementLog: () => StatementLog;
33
+ /**
34
+ * Counts the statements a client sends on one Postgres connection from its
35
+ * protocol messages, for a relay that sees every byte the client writes:
36
+ * every extended-protocol statement ends its cycle with one Sync, and a
37
+ * simple query is one Query message. The startup and encryption requests
38
+ * that open a connection carry no type byte and are skipped.
39
+ */
40
+ export declare const wireStatements: () => (chunk: Buffer) => number;
41
+ /**
42
+ * What one external command to a warm activation costs across every pool,
43
+ * derived from the turn's two groups rather than measured. The admission
44
+ * flight sends `BEGIN`, the timeout `set_config`, and the fenced read that
45
+ * resolves the receipt. A command that runs its handler and dirties one key
46
+ * then sends the state upsert, the receipt insert, `COMMIT`, and the read of
47
+ * the commit version and the clock its expiry recheck uses: 2 flights and 7
48
+ * statements. A replay sends `ROLLBACK` and that same read instead: 2 flights
49
+ * and 5 statements. Nothing is read before delivery or after the turn.
50
+ */
51
+ export declare const SERVED_COMMAND: {
52
+ readonly warm: {
53
+ readonly flights: 2;
54
+ readonly statements: 7;
55
+ };
56
+ readonly replay: {
57
+ readonly flights: 2;
58
+ readonly statements: 5;
59
+ };
60
+ };