@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,7 @@
1
+ import type { ConformanceCase } from "../conformance.ts";
2
+ /**
3
+ * Group commit cases: warm turns of different actors share one transaction,
4
+ * and each keeps its own fence, receipt, failure, interruption and statement
5
+ * outcome.
6
+ */
7
+ export declare const groupsConformance: ReadonlyArray<ConformanceCase>;
@@ -0,0 +1,353 @@
1
+ import { Cause, Clock, Crypto, Deferred, Duration, Option, Effect, Exit, Fiber, Layer, Redacted, Schedule, Schema, } from "effect";
2
+ import { SqlClient } from "effect/sql";
3
+ import { Actor, Actors } from "../../index.js";
4
+ import { TurnGroupSettings } from "../../runtime/turn/group.js";
5
+ import { ActorTest } from "../actor-test.js";
6
+ import { transactions } from "./batches.js";
7
+ class Refused extends Schema.TaggedError()("GroupRefused", {}) {
8
+ }
9
+ const Add = Actor.command("Add", { payload: Schema.Finite, success: Schema.Finite });
10
+ const Refuse = Actor.command("Refuse", { payload: Schema.Finite, error: Refused });
11
+ const Explode = Actor.command("Explode", { payload: Schema.Finite });
12
+ /**
13
+ * Warm actors without owned tables, so concurrent turns of different ones
14
+ * share a group. A short execution timeout lets a case interrupt one member.
15
+ */
16
+ const Tally = Actor.make("GroupTally", {
17
+ key: Schema.String,
18
+ state: Actor.state({ count: Schema.Finite.pipe(Schema.withDecodingDefault(Effect.succeed(0))) }),
19
+ api: { Add, Refuse, Explode },
20
+ policy: { executionTimeout: "2 seconds" },
21
+ });
22
+ /** Handler runs per actor id. */
23
+ const runs = new Map();
24
+ const ran = Effect.gen(function* () {
25
+ const turn = yield* Tally.Turn;
26
+ runs.set(turn.id, (runs.get(turn.id) ?? 0) + 1);
27
+ return turn;
28
+ });
29
+ const tallyLive = Tally.toLayer(Effect.succeed({
30
+ Add: Effect.fnUntraced(function* (amount) {
31
+ const turn = yield* ran;
32
+ yield* turn.state.set({ count: turn.state.count + amount });
33
+ return turn.state.count;
34
+ }),
35
+ Refuse: Effect.fnUntraced(function* (amount) {
36
+ const turn = yield* ran;
37
+ yield* turn.state.set({ count: turn.state.count + amount });
38
+ return yield* Refused.make({});
39
+ }),
40
+ Explode: Effect.fnUntraced(function* (amount) {
41
+ const turn = yield* ran;
42
+ yield* turn.state.set({ count: turn.state.count + amount });
43
+ return yield* Effect.die(new Error("Group member defect"));
44
+ }),
45
+ }));
46
+ /** Runs `body` on a runner over a fresh database whose closed groups wait `wait` for members. */
47
+ const withGroups = (environment, wait, body) => environment.run(Effect.service(Crypto.Crypto)).then((crypto) => Effect.runPromise(Effect.gen(function* () {
48
+ yield* Effect.acquireRelease(environment.stop, () => environment.restart);
49
+ const database = yield* environment.freshDatabase;
50
+ if (!Redacted.isRedacted(database))
51
+ return yield* Effect.die(new Error("The group cases need a Postgres database"));
52
+ const context = yield* Layer.build(tallyLive.pipe(Layer.provideMerge(ActorTest.layer({ database })), Layer.provide(Layer.succeed(TurnGroupSettings, { wait: Duration.fromInputUnsafe(wait) }))));
53
+ return yield* body.pipe(Effect.provideContext(context));
54
+ }).pipe(Effect.scoped, Effect.provideService(Crypto.Crypto, crypto))));
55
+ /**
56
+ * Warms each actor with one `Add(1)`, then sends every call at once and holds
57
+ * each turn before its handler until all of them reached it, so they joined
58
+ * one group before any member handed over its writes.
59
+ */
60
+ const together = Effect.fnUntraced(function* (calls) {
61
+ const test = yield* ActorTest;
62
+ for (const { id } of calls) {
63
+ const warm = yield* (yield* Tally.get(id)).Add(1);
64
+ if (warm !== 1)
65
+ return yield* Effect.die(new Error(`Warming ${id} returned ${warm}`));
66
+ }
67
+ const pauses = yield* Effect.forEach(calls, ({ commandId }) => test.pauseNext("beforeHandler", { commandId }));
68
+ const fibers = yield* Effect.forEach(calls, ({ id, commandId, call }) => Effect.flatMap(Tally.get(id), (tally) => Effect.forkChild(call(tally).pipe(Actor.commandId(commandId), Effect.exit))));
69
+ yield* Effect.forEach(pauses, ({ reached }) => reached, { concurrency: "unbounded" });
70
+ return { fibers, release: Effect.forEach(pauses, ({ release }) => release, { discard: true }) };
71
+ });
72
+ const mintAll = Effect.fnUntraced(function* (count) {
73
+ const actors = yield* Actors;
74
+ return yield* Effect.forEach(Array.from({ length: count }), () => actors.mintCommandId);
75
+ });
76
+ /** The transaction that committed `commandId` on actor `id`, if it committed. */
77
+ const committedIn = Effect.fnUntraced(function* (id, commandId) {
78
+ return (yield* transactions((yield* Tally.get(id)).ref)).get(commandId);
79
+ });
80
+ /**
81
+ * Waits until a turn waits for a generation row lock, which only a group
82
+ * still holding a departed member's fenced read can hold here.
83
+ */
84
+ const lockWaiter = Effect.gen(function* () {
85
+ const sql = yield* SqlClient.SqlClient;
86
+ const [row] = yield* sql `SELECT count(*)::int AS waiting
87
+ FROM pg_stat_activity WHERE wait_event_type = 'Lock' AND datname = current_database()`;
88
+ if (row.waiting === 0)
89
+ return yield* Effect.fail("no lock waiter yet");
90
+ }).pipe(Effect.retry(Schedule.spaced("20 millis")), Effect.orDie);
91
+ const stateOf = Effect.fnUntraced(function* (id) {
92
+ const test = yield* ActorTest;
93
+ return (yield* test.inspect((yield* Tally.get(id)).ref)).state;
94
+ });
95
+ /**
96
+ * Group commit cases: warm turns of different actors share one transaction,
97
+ * and each keeps its own fence, receipt, failure, interruption and statement
98
+ * outcome.
99
+ */
100
+ export const groupsConformance = [
101
+ {
102
+ name: "group commit: concurrent warm turns commit in one transaction; a declared failure keeps only its receipt and a defect leaves only itself out",
103
+ requiresIndependentConnections: true,
104
+ requiresFreshDatabase: true,
105
+ timeoutMs: 60_000,
106
+ run: ({ expect, environment }) => withGroups(environment, "10 seconds", Effect.gen(function* () {
107
+ const [a, b, refused, exploded, e] = yield* mintAll(5);
108
+ const ids = ["one", "two", "refused", "exploded", "five"].map((id) => `group-${id}`);
109
+ const { fibers, release } = yield* together([
110
+ { id: ids[0], commandId: a, call: (tally) => tally.Add(10) },
111
+ { id: ids[1], commandId: b, call: (tally) => tally.Add(20) },
112
+ { id: ids[2], commandId: refused, call: (tally) => tally.Refuse(30) },
113
+ { id: ids[3], commandId: exploded, call: (tally) => tally.Explode(40) },
114
+ { id: ids[4], commandId: e, call: (tally) => tally.Add(50) },
115
+ ]);
116
+ runs.clear();
117
+ yield* release;
118
+ const [one, two, refusal, defect, five] = yield* Effect.forEach(fibers, Fiber.join);
119
+ expect([one, two, five]).toEqual([Exit.succeed(11), Exit.succeed(21), Exit.succeed(51)]);
120
+ expect(Exit.isFailure(refusal) && Cause.squash(refusal.cause)).toBeInstanceOf(Refused);
121
+ expect(Exit.isFailure(defect) && Cause.hasDies(defect.cause)).toBe(true);
122
+ const shared = yield* committedIn(ids[0], a);
123
+ expect(shared).not.toBe(undefined);
124
+ expect(yield* committedIn(ids[1], b)).toBe(shared);
125
+ expect(yield* committedIn(ids[2], refused)).toBe(shared);
126
+ expect(yield* committedIn(ids[4], e)).toBe(shared);
127
+ expect(yield* committedIn(ids[3], exploded)).toBe(undefined);
128
+ expect(yield* stateOf(ids[2])).toEqual({ count: 1 });
129
+ expect(yield* stateOf(ids[3])).toEqual({ count: 1 });
130
+ expect(ids.map((id) => runs.get(id))).toEqual([1, 1, 1, 1, 1]);
131
+ })),
132
+ },
133
+ {
134
+ name: "group commit: a member fenced by a newer generation leaves its group before its handler runs, runs again alone, and its neighbours commit together",
135
+ requiresIndependentConnections: true,
136
+ requiresFreshDatabase: true,
137
+ timeoutMs: 60_000,
138
+ run: ({ expect, environment }) => withGroups(environment, "10 seconds", Effect.gen(function* () {
139
+ const sql = yield* SqlClient.SqlClient;
140
+ const test = yield* ActorTest;
141
+ const [a, fenced, c] = yield* mintAll(3);
142
+ const ids = ["group-left", "group-fenced", "group-right"];
143
+ for (const id of ids)
144
+ expect(yield* (yield* Tally.get(id)).Add(1)).toBe(1);
145
+ yield* sql `UPDATE actor_generations SET generation = generation + 1
146
+ WHERE actor_type = 'GroupTally' AND actor_id = ${ids[1]}`;
147
+ const pauses = yield* Effect.forEach([a, c], (commandId) => test.pauseNext("beforeHandler", { commandId }));
148
+ runs.clear();
149
+ const fibers = yield* Effect.forEach([
150
+ [ids[0], a],
151
+ [ids[1], fenced],
152
+ [ids[2], c],
153
+ ], ([id, commandId]) => Effect.flatMap(Tally.get(id), (tally) => Effect.forkChild(tally.Add(1).pipe(Actor.commandId(commandId)))));
154
+ yield* Effect.forEach(pauses, ({ reached }) => reached, { concurrency: "unbounded" });
155
+ yield* lockWaiter;
156
+ expect(runs.size).toBe(0);
157
+ yield* Effect.forEach(pauses, ({ release }) => release, { discard: true });
158
+ expect(yield* Effect.forEach(fibers, Fiber.join)).toEqual([2, 2, 2]);
159
+ const shared = yield* committedIn(ids[0], a);
160
+ expect(yield* committedIn(ids[2], c)).toBe(shared);
161
+ expect(yield* committedIn(ids[1], fenced)).not.toBe(shared);
162
+ expect(ids.map((id) => runs.get(id))).toEqual([1, 1, 1]);
163
+ expect(yield* test.receiptsFor((yield* Tally.get(ids[1])).ref, "Add")).toBe(2);
164
+ })),
165
+ },
166
+ {
167
+ name: "group commit: a member interrupted after handing over its writes is withdrawn, and the group commits its neighbour",
168
+ requiresIndependentConnections: true,
169
+ requiresFreshDatabase: true,
170
+ timeoutMs: 60_000,
171
+ run: ({ expect, environment }) => withGroups(environment, "30 seconds", Effect.gen(function* () {
172
+ const test = yield* ActorTest;
173
+ const [early, late] = yield* mintAll(2);
174
+ const ids = ["group-early", "group-late"];
175
+ for (const id of ids)
176
+ expect(yield* (yield* Tally.get(id)).Add(1)).toBe(1);
177
+ const lateHeld = yield* test.pauseNext("beforeHandler", { commandId: late });
178
+ const earlyHeld = yield* test.pauseNext("beforeHandler", { commandId: early });
179
+ runs.clear();
180
+ const earlyCall = yield* Effect.forkChild((yield* Tally.get(ids[0])).Add(10).pipe(Actor.commandId(early)));
181
+ yield* earlyHeld.reached;
182
+ yield* Effect.sleep("1 second");
183
+ const lateCall = yield* Effect.forkChild((yield* Tally.get(ids[1])).Add(20).pipe(Actor.commandId(late)));
184
+ yield* lateHeld.reached;
185
+ yield* earlyHeld.release;
186
+ yield* lockWaiter;
187
+ expect(runs.get(ids[0])).toBe(1);
188
+ expect(yield* committedIn(ids[0], early)).toBe(undefined);
189
+ expect(yield* stateOf(ids[0])).toEqual({ count: 1 });
190
+ yield* lateHeld.release;
191
+ expect(yield* Fiber.join(lateCall)).toBe(21);
192
+ expect(yield* Fiber.join(earlyCall)).toBe(11);
193
+ expect(runs.get(ids[0])).toBe(2);
194
+ expect(runs.get(ids[1])).toBe(1);
195
+ expect(yield* committedIn(ids[0], early)).not.toBe(yield* committedIn(ids[1], late));
196
+ expect(yield* stateOf(ids[0])).toEqual({ count: 11 });
197
+ })),
198
+ },
199
+ {
200
+ name: "group commit: a member still running when the group's wait ends is evicted, runs again alone, and commits once",
201
+ requiresIndependentConnections: true,
202
+ requiresFreshDatabase: true,
203
+ timeoutMs: 60_000,
204
+ run: ({ expect, environment }) => withGroups(environment, "50 millis", Effect.gen(function* () {
205
+ const test = yield* ActorTest;
206
+ const [quick, slow] = yield* mintAll(2);
207
+ const ids = ["group-quick", "group-slow"];
208
+ const { fibers, release } = yield* together([
209
+ { id: ids[0], commandId: quick, call: (tally) => tally.Add(10) },
210
+ { id: ids[1], commandId: slow, call: (tally) => tally.Add(20) },
211
+ ]);
212
+ const slowHeld = yield* test.pauseNext("beforeCommit", { commandId: slow });
213
+ runs.clear();
214
+ yield* release;
215
+ yield* slowHeld.reached;
216
+ expect(yield* Fiber.join(fibers[0])).toEqual(Exit.succeed(11));
217
+ expect(yield* committedIn(ids[1], slow)).toBe(undefined);
218
+ yield* Effect.sleep("200 millis");
219
+ yield* slowHeld.release;
220
+ expect(yield* Fiber.join(fibers[1])).toEqual(Exit.succeed(21));
221
+ expect(runs.get(ids[0])).toBe(1);
222
+ expect(runs.get(ids[1])).toBe(2);
223
+ expect(yield* committedIn(ids[1], slow)).not.toBe(yield* committedIn(ids[0], quick));
224
+ expect(yield* test.receiptsFor((yield* Tally.get(ids[1])).ref, "Add")).toBe(2);
225
+ expect(yield* stateOf(ids[1])).toEqual({ count: 21 });
226
+ })),
227
+ },
228
+ {
229
+ name: "group commit: a statement error in one member's writes rolls the group back; that member fails and its neighbours commit alone, once each",
230
+ requiresIndependentConnections: true,
231
+ requiresFreshDatabase: true,
232
+ timeoutMs: 60_000,
233
+ run: ({ expect, environment }) => withGroups(environment, "10 seconds", Effect.gen(function* () {
234
+ const sql = yield* SqlClient.SqlClient;
235
+ const [poisoned, b, c] = yield* mintAll(3);
236
+ const ids = ["group-poisoned", "group-b", "group-c"];
237
+ yield* sql.unsafe(`CREATE FUNCTION group_poison() RETURNS trigger LANGUAGE plpgsql AS $$
238
+ BEGIN
239
+ IF NEW.command_id = '${poisoned}' THEN RAISE EXCEPTION 'poisoned receipt'; END IF;
240
+ RETURN NEW;
241
+ END $$`);
242
+ yield* sql.unsafe(`CREATE TRIGGER group_poison BEFORE INSERT ON actor_receipts
243
+ FOR EACH ROW EXECUTE FUNCTION group_poison()`);
244
+ const { fibers, release } = yield* together([
245
+ { id: ids[0], commandId: poisoned, call: (tally) => tally.Add(10) },
246
+ { id: ids[1], commandId: b, call: (tally) => tally.Add(20) },
247
+ { id: ids[2], commandId: c, call: (tally) => tally.Add(30) },
248
+ ]);
249
+ runs.clear();
250
+ yield* release;
251
+ const [failed, second, third] = yield* Effect.forEach(fibers, Fiber.join);
252
+ expect(Exit.isFailure(failed) && Cause.hasDies(failed.cause)).toBe(true);
253
+ expect([second, third]).toEqual([Exit.succeed(21), Exit.succeed(31)]);
254
+ expect(runs.get(ids[1])).toBe(2);
255
+ expect(runs.get(ids[2])).toBe(2);
256
+ expect(yield* committedIn(ids[0], poisoned)).toBe(undefined);
257
+ expect(yield* committedIn(ids[1], b)).not.toBe(yield* committedIn(ids[2], c));
258
+ expect(yield* stateOf(ids[0])).toEqual({ count: 1 });
259
+ expect(yield* stateOf(ids[1])).toEqual({ count: 21 });
260
+ })),
261
+ },
262
+ {
263
+ name: "group commit: a member whose next batch rides behind the COMMIT, interrupted while that COMMIT runs, never gets the session back with its chained transaction open",
264
+ requiresIndependentConnections: true,
265
+ requiresFreshDatabase: true,
266
+ timeoutMs: 60_000,
267
+ run: ({ expect, environment }) => withGroups(environment, "30 seconds", Effect.gen(function* () {
268
+ const sql = yield* SqlClient.SqlClient;
269
+ const test = yield* ActorTest;
270
+ const [a1, a2, b1] = yield* mintAll(3);
271
+ const ids = ["group-handoff", "group-neighbour"];
272
+ for (const id of ids)
273
+ expect(yield* (yield* Tally.get(id)).Add(1)).toBe(1);
274
+ yield* sql.unsafe(`CREATE FUNCTION group_slow_commit() RETURNS trigger LANGUAGE plpgsql AS $$
275
+ BEGIN PERFORM pg_sleep(1.4); RETURN NULL; END $$`);
276
+ yield* sql.unsafe(`CREATE CONSTRAINT TRIGGER group_slow_commit AFTER INSERT ON actor_receipts
277
+ DEFERRABLE INITIALLY DEFERRED FOR EACH ROW WHEN (NEW.command_id = '${a1}')
278
+ EXECUTE FUNCTION group_slow_commit()`);
279
+ const a1Held = yield* test.pauseNext("beforeHandler", { commandId: a1 });
280
+ const b1Held = yield* test.pauseNext("beforeHandler", { commandId: b1 });
281
+ const handoff = yield* Tally.get(ids[0]);
282
+ const first = yield* Effect.forkChild(handoff.Add(10).pipe(Actor.commandId(a1), Effect.exit));
283
+ yield* a1Held.reached;
284
+ const second = yield* Effect.forkChild(handoff.Add(100).pipe(Actor.commandId(a2), Effect.exit));
285
+ yield* Effect.sleep("900 millis");
286
+ const neighbour = yield* Effect.forkChild((yield* Tally.get(ids[1])).Add(20).pipe(Actor.commandId(b1), Effect.exit));
287
+ yield* b1Held.reached;
288
+ yield* a1Held.release;
289
+ yield* b1Held.release;
290
+ expect(yield* Fiber.join(neighbour)).toEqual(Exit.succeed(21));
291
+ const seen = [];
292
+ const deadline = (yield* Clock.currentTimeMillis) + 4_000;
293
+ while ((yield* Clock.currentTimeMillis) < deadline) {
294
+ const rows = yield* sql `
295
+ SELECT pid, state, wait_event_type AS waiting FROM pg_stat_activity
296
+ WHERE datname = current_database() AND pid <> pg_backend_pid()
297
+ AND clock_timestamp() - state_change > interval '300 milliseconds'
298
+ AND (state = 'idle in transaction' OR wait_event_type = 'Lock')`;
299
+ for (const row of rows)
300
+ seen.push(`${row.pid}:${row.state}:${row.waiting}`);
301
+ yield* Effect.sleep("25 millis");
302
+ }
303
+ expect([...new Set(seen)]).toEqual([]);
304
+ expect(yield* Fiber.join(first)).toEqual(Exit.succeed(11));
305
+ expect(yield* Fiber.join(second)).toEqual(Exit.succeed(111));
306
+ expect(yield* stateOf(ids[0])).toEqual({ count: 111 });
307
+ expect(yield* test.receiptsFor(handoff.ref, "Add")).toBe(3);
308
+ })),
309
+ },
310
+ {
311
+ name: "group commit: a member whose generation row another transaction holds is skipped, and its neighbours commit together without waiting for that lock",
312
+ requiresIndependentConnections: true,
313
+ requiresFreshDatabase: true,
314
+ timeoutMs: 60_000,
315
+ run: ({ expect, environment }) => withGroups(environment, "10 seconds", Effect.gen(function* () {
316
+ const sql = yield* SqlClient.SqlClient;
317
+ const test = yield* ActorTest;
318
+ const [l, x, y] = yield* mintAll(3);
319
+ const ids = ["group-locked", "group-x", "group-y"];
320
+ for (const id of ids)
321
+ expect(yield* (yield* Tally.get(id)).Add(1)).toBe(1);
322
+ const locked = Deferred.makeUnsafe();
323
+ const unlock = Deferred.makeUnsafe();
324
+ const holder = yield* Effect.forkChild(sql.withTransaction(Effect.gen(function* () {
325
+ yield* sql `SELECT 1 FROM actor_generations
326
+ WHERE actor_type = 'GroupTally' AND actor_id = ${ids[0]} FOR UPDATE`;
327
+ yield* Deferred.succeed(locked, undefined);
328
+ yield* Deferred.await(unlock);
329
+ })));
330
+ yield* Deferred.await(locked);
331
+ const pauses = yield* Effect.forEach([x, y], (commandId) => test.pauseNext("beforeHandler", { commandId }));
332
+ runs.clear();
333
+ const lockedCall = yield* Effect.forkChild((yield* Tally.get(ids[0])).Add(5).pipe(Actor.commandId(l), Effect.exit));
334
+ yield* Effect.sleep("20 millis");
335
+ const others = yield* Effect.forEach([
336
+ [ids[1], x],
337
+ [ids[2], y],
338
+ ], ([id, commandId]) => Effect.flatMap(Tally.get(id), (tally) => Effect.forkChild(tally.Add(5).pipe(Actor.commandId(commandId), Effect.exit))));
339
+ const reached = yield* Effect.forEach(pauses, ({ reached }) => reached, {
340
+ concurrency: "unbounded",
341
+ }).pipe(Effect.timeoutOption("1500 millis"));
342
+ expect(reached._tag).toBe("Some");
343
+ yield* Effect.forEach(pauses, ({ release }) => release, { discard: true });
344
+ const answered = yield* Effect.forEach(others, Fiber.join).pipe(Effect.timeoutOption("1500 millis"));
345
+ expect(answered).toEqual(Option.some([Exit.succeed(6), Exit.succeed(6)]));
346
+ expect(yield* committedIn(ids[1], x)).toBe(yield* committedIn(ids[2], y));
347
+ yield* Deferred.succeed(unlock, undefined);
348
+ yield* Fiber.join(holder);
349
+ expect(yield* Fiber.join(lockedCall)).toEqual(Exit.succeed(6));
350
+ expect(yield* committedIn(ids[0], l)).not.toBe(yield* committedIn(ids[1], x));
351
+ })),
352
+ },
353
+ ];
@@ -0,0 +1,3 @@
1
+ import type { ConformanceCase } from "../conformance.ts";
2
+ /** Heap cases: bounded retained heap once activations hibernate and once Cluster forgets processed request ids. */
3
+ export declare const heapConformance: ReadonlyArray<ConformanceCase>;
@@ -0,0 +1,149 @@
1
+ import { Crypto, Effect, Layer, ManagedRuntime, Schedule, Schema } from "effect";
2
+ import { Actor, Actors } from "../../index.js";
3
+ import { ActorTest } from "../actor-test.js";
4
+ import { onBun } from "./platform.js";
5
+ const Touch = Actor.command("Touch", { success: Schema.Finite });
6
+ const Sleeper = Actor.make("HeapSleeper", {
7
+ key: Schema.String,
8
+ state: Actor.state({ count: Schema.Finite.pipe(Schema.withDecodingDefault(Effect.succeed(0))) }),
9
+ api: { Touch },
10
+ policy: { hibernateAfter: "250 millis" },
11
+ });
12
+ const SleeperLive = Sleeper.toLayer(Effect.succeed({
13
+ Touch: Effect.fnUntraced(function* () {
14
+ const turn = yield* Sleeper.Turn;
15
+ yield* turn.state.set({ count: turn.state.count + 1 });
16
+ return turn.state.count;
17
+ }),
18
+ }));
19
+ const ACTORS = 1000;
20
+ const COMMANDS = 4_096;
21
+ const HOT_ACTORS = 32;
22
+ let cachedGc;
23
+ /**
24
+ * Node's collector, made reachable once: building its vm realm allocates, so
25
+ * doing that for each sample would charge the realm to the heap it measures.
26
+ */
27
+ const nodeGc = Effect.gen(function* () {
28
+ if (cachedGc !== undefined)
29
+ return cachedGc;
30
+ const v8 = yield* Effect.promise(() => import("node:v8"));
31
+ const vm = yield* Effect.promise(() => import("node:vm"));
32
+ v8.setFlagsFromString("--expose-gc");
33
+ cachedGc = vm.runInNewContext("gc");
34
+ return cachedGc;
35
+ });
36
+ /**
37
+ * Live JavaScript heap after a full collection. ArrayBuffer memory is left
38
+ * out: an in-process database keeps its pages there, and they grow with
39
+ * stored rows rather than with anything the runtime retains. Bun counts every
40
+ * live cell; V8 counts the objects that inherit `Object.prototype`, which is
41
+ * every object but a null-prototype one, so the two counts differ in scale
42
+ * but each rises with each object the runtime retains. The count is taken
43
+ * before the byte size so counting is not charged to the sample. `bun:jsc` and `node:v8`
44
+ * are loaded only when the case runs, so importing the testing entry needs
45
+ * neither runtime's helpers.
46
+ */
47
+ const retained = Effect.gen(function* () {
48
+ if (!onBun) {
49
+ const v8 = yield* Effect.promise(() => import("node:v8"));
50
+ const gc = yield* nodeGc;
51
+ gc({ type: "major" });
52
+ gc({ type: "major" });
53
+ const objects = v8.queryObjects(Object, { format: "count" });
54
+ return { bytes: v8.getHeapStatistics().used_heap_size, objects };
55
+ }
56
+ const { heapStats } = yield* Effect.promise(() => import("bun:jsc"));
57
+ Bun.gc(true);
58
+ const stats = heapStats();
59
+ return { bytes: stats.heapSize - stats.extraMemorySize, objects: stats.objectCount };
60
+ });
61
+ /**
62
+ * Samples the heap once a second until two samples agree to within one object
63
+ * per actor, or 60 seconds pass. Cluster's reaper sweeps every 5 seconds and
64
+ * releases a whole sweep's activations at once, so a settled heap means the
65
+ * sweeps have run.
66
+ */
67
+ const settled = Effect.gen(function* () {
68
+ let previous = yield* retained;
69
+ return yield* Effect.gen(function* () {
70
+ const next = yield* retained;
71
+ const done = Math.abs(previous.objects - next.objects) < ACTORS;
72
+ previous = next;
73
+ return done ? next : yield* Effect.fail("unsettled");
74
+ }).pipe(Effect.delay("1 second"), Effect.retry({ schedule: Schedule.recurs(60) }), Effect.orElseSucceed(() => previous));
75
+ });
76
+ const perActor = (before, after) => ({
77
+ objects: (after.objects - before.objects) / ACTORS,
78
+ bytes: (after.bytes - before.bytes) / ACTORS,
79
+ });
80
+ /** Heap cases: bounded retained heap once activations hibernate and once Cluster forgets processed request ids. */
81
+ export const heapConformance = [
82
+ {
83
+ name: "retains bounded heap for touched actors once every activation hibernates",
84
+ timeoutMs: 120_000,
85
+ run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
86
+ const database = yield* environment.freshDatabase;
87
+ const runtime = yield* Effect.acquireRelease(Effect.map(Crypto.Crypto, (crypto) => ManagedRuntime.make(SleeperLive.pipe(Layer.provideMerge(ActorTest.layer({ database })), Layer.provide(Layer.succeed(Crypto.Crypto, crypto)), Layer.orDie))), (runtime) => Effect.promise(() => runtime.dispose()));
88
+ const touch = (id) => Sleeper.get(id).pipe(Effect.flatMap((sleeper) => sleeper.Touch()));
89
+ const touchAll = (prefix) => Effect.forEach(Array.from({ length: ACTORS }, (_, index) => `${prefix}-${index}`), touch, { concurrency: 32, discard: true });
90
+ const hibernate = Effect.andThen(Effect.sleep("6 seconds"), settled);
91
+ const { growth, generations } = yield* Effect.promise(() => runtime.runPromise(Effect.gen(function* () {
92
+ yield* touchAll("warm");
93
+ const before = yield* hibernate;
94
+ yield* touchAll("actor");
95
+ const growth = perActor(before, yield* hibernate);
96
+ const test = yield* ActorTest;
97
+ const generations = yield* Effect.forEach([0, 250, 500, 750, 999], (index) => Effect.gen(function* () {
98
+ const sample = yield* Sleeper.get(`actor-${index}`);
99
+ yield* sample.Touch();
100
+ return (yield* test.inspect(sample.ref)).generation;
101
+ }));
102
+ return { growth, generations };
103
+ })));
104
+ expect(generations).toEqual(["2", "2", "2", "2", "2"]);
105
+ expect({ ...growth, bounded: growth.objects < 10 && growth.bytes < 1024 }).toMatchObject({
106
+ bounded: true,
107
+ });
108
+ })),
109
+ },
110
+ {
111
+ name: "retains bounded heap per command once Cluster forgets processed request ids",
112
+ requiresIndependentConnections: true,
113
+ timeoutMs: 120_000,
114
+ run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
115
+ const database = yield* environment.freshDatabase;
116
+ const runtime = yield* Effect.acquireRelease(Effect.map(Crypto.Crypto, (crypto) => ManagedRuntime.make(SleeperLive.pipe(Layer.provideMerge(ActorTest.layer({ database })), Layer.provide(Layer.succeed(Crypto.Crypto, crypto)), Layer.orDie))), (runtime) => Effect.promise(() => runtime.dispose()));
117
+ const touch = (id) => Sleeper.get(id).pipe(Effect.flatMap((sleeper) => sleeper.Touch()));
118
+ const touchMany = Effect.forEach(Array.from({ length: COMMANDS }, (_, index) => `hot-${index % HOT_ACTORS}`), touch, { concurrency: HOT_ACTORS, discard: true });
119
+ const forget = Effect.andThen(Effect.sleep("11 seconds"), retained);
120
+ const { growth, first, replayed, count } = yield* Effect.promise(() => runtime.runPromise(Effect.gen(function* () {
121
+ const id = yield* (yield* Actors).mintCommandId;
122
+ const saved = Sleeper.get("hot-0").pipe(Effect.flatMap((sleeper) => sleeper.Touch().pipe(Actor.commandId(id))));
123
+ const first = yield* saved;
124
+ yield* touchMany;
125
+ yield* forget;
126
+ yield* touchMany;
127
+ const before = yield* forget;
128
+ yield* touchMany;
129
+ const after = yield* forget;
130
+ const replayed = yield* saved;
131
+ const count = yield* touch("hot-0");
132
+ return {
133
+ growth: {
134
+ objects: (after.objects - before.objects) / COMMANDS,
135
+ bytes: (after.bytes - before.bytes) / COMMANDS,
136
+ },
137
+ first,
138
+ replayed,
139
+ count,
140
+ };
141
+ })));
142
+ expect({ first, replayed }).toEqual({ first: 1, replayed: 1 });
143
+ expect(count).toBe((3 * COMMANDS) / HOT_ACTORS + 2);
144
+ expect({ ...growth, bounded: growth.objects < 0.5 && growth.bytes < 64 }).toMatchObject({
145
+ bounded: true,
146
+ });
147
+ })),
148
+ },
149
+ ];