@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,474 @@
1
+ import { Effect, Schedule, Schema } from "effect";
2
+ import { Offline, OfflineStoreError, } from "../../client/offline/store.js";
3
+ import { ActorError } from "../../errors/actor.js";
4
+ import { InternalActors } from "../../runtime/actors.js";
5
+ import { Full, HttpRoom, HttpTally, posted, receipts, runs, serveHttp, tenantOf, httpSuite, } from "./http.js";
6
+ const baseFetch = globalThis.fetch.bind(globalThis);
7
+ const wire = () => {
8
+ const state = {
9
+ down: false,
10
+ blocked: () => false,
11
+ loseNextCommand: false,
12
+ sent: [],
13
+ fetch: (input, init) => {
14
+ const url = new URL(input instanceof Request ? input.url : input);
15
+ const key = new Headers(init?.headers).get("idempotency-key");
16
+ if (state.down || state.blocked(url.pathname))
17
+ return Promise.reject(new TypeError("network down"));
18
+ state.sent.push({ path: url.pathname, key });
19
+ return baseFetch(input, init).then((response) => {
20
+ if (!state.loseNextCommand || key === null)
21
+ return response;
22
+ state.loseNextCommand = false;
23
+ state.down = true;
24
+ return response.text().then(() => Promise.reject(new TypeError("reply lost")));
25
+ });
26
+ },
27
+ commands: (member) => state.sent.filter((sent) => sent.path.endsWith(`/${member}`)).map((sent) => sent.key),
28
+ };
29
+ return state;
30
+ };
31
+ const until = (condition) => Effect.suspend(() => (condition() ? Effect.void : Effect.fail("waiting"))).pipe(Effect.retry({ schedule: Schedule.spaced("10 millis"), times: 1_000 }), Effect.orDie);
32
+ const settle = (promise) => Effect.tryPromise(() => promise).pipe(Effect.match({
33
+ onSuccess: (value) => ({ ok: true, value }),
34
+ onFailure: (failure) => ({ ok: false, error: failure.cause }),
35
+ }));
36
+ const isActorError = Schema.is(ActorError);
37
+ /** A rejected call's framework reason as `{ tag, ...fields }`, or undefined. */
38
+ const reasonOf = (settled) => {
39
+ if (settled.ok || !isActorError(settled.error))
40
+ return undefined;
41
+ const reason = settled.error.reason;
42
+ return Object.assign({ tag: reason._tag }, reason);
43
+ };
44
+ const queueOf = (client) => client.offline;
45
+ const idsOf = (queue) => queue.pending.map((pending) => pending.commandId);
46
+ const savedIds = (store) => Effect.promise(() => store.entries()).pipe(Effect.map((entries) => entries.map((entry) => entry.commandId)));
47
+ const bearer = (tenant) => ({ authorization: `Bearer ${tenant}:alice` });
48
+ export const offlineConformance = [
49
+ {
50
+ name: "offline client queues commands while the network is down, then replays them in order under their original ids, each applied once",
51
+ run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
52
+ const server = yield* serveHttp();
53
+ const tenant = yield* tenantOf;
54
+ const network = wire();
55
+ const store = Offline.memory();
56
+ const rooms = HttpRoom.client({
57
+ baseUrl: server.url,
58
+ headers: bearer(tenant),
59
+ fetch: network.fetch,
60
+ offline: store,
61
+ identity: () => `${tenant}/alice`,
62
+ timeoutInMs: 300,
63
+ });
64
+ const queue = queueOf(rooms);
65
+ yield* Effect.addFinalizer(() => Effect.sync(() => queue.close()));
66
+ yield* Effect.promise(() => queue.ready);
67
+ yield* Effect.promise(() => rooms.commandId());
68
+ network.down = true;
69
+ const firstPost = posted.length;
70
+ const ran = runs.count;
71
+ const room = rooms.get("queued");
72
+ const calls = ["one", "two", "three"].map((text) => room.Post({ text }));
73
+ const settled = yield* Effect.promise(() => Promise.allSettled(calls));
74
+ expect(settled.map((call) => call.status)).toEqual(["rejected", "rejected", "rejected"]);
75
+ const queued = idsOf(queue);
76
+ expect(queued.length).toBe(3);
77
+ expect(new Set(queued).size).toBe(3);
78
+ expect(queue.pending.map((pending) => pending.status)).toEqual([
79
+ "queued",
80
+ "queued",
81
+ "queued",
82
+ ]);
83
+ expect(yield* savedIds(store)).toEqual(queued);
84
+ expect(posted.length).toBe(firstPost);
85
+ expect(runs.count).toBe(ran);
86
+ expect(yield* receipts(tenant, "HttpRoom", "queued")).toBe(0);
87
+ network.down = false;
88
+ queue.flush();
89
+ yield* until(() => queue.pending.length === 0);
90
+ expect(posted.slice(firstPost)).toEqual(["one", "two", "three"]);
91
+ expect(runs.count - ran).toBe(3);
92
+ expect(yield* receipts(tenant, "HttpRoom", "queued")).toBe(3);
93
+ expect(network.commands("Post")).toEqual(queued);
94
+ expect(yield* savedIds(store)).toEqual([]);
95
+ })),
96
+ },
97
+ {
98
+ name: "offline client replays a command whose reply was lost, after a reload, with its original id: the receipt answers and the handler ran once",
99
+ run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
100
+ const server = yield* serveHttp();
101
+ const tenant = yield* tenantOf;
102
+ const network = wire();
103
+ const store = Offline.memory();
104
+ const ran = runs.count;
105
+ const before = HttpRoom.client({
106
+ baseUrl: server.url,
107
+ headers: bearer(tenant),
108
+ fetch: network.fetch,
109
+ offline: store,
110
+ identity: () => `${tenant}/alice`,
111
+ timeoutInMs: 300,
112
+ });
113
+ const first = queueOf(before);
114
+ yield* Effect.addFinalizer(() => Effect.sync(() => first.close()));
115
+ yield* Effect.promise(() => first.ready);
116
+ yield* Effect.promise(() => before.commandId());
117
+ network.loseNextCommand = true;
118
+ const lost = yield* settle(before.get("reload").Post({ text: "once" }));
119
+ const id = idsOf(first)[0];
120
+ expect(reasonOf(lost)).toMatchObject({ tag: "Timeout", commandId: id });
121
+ expect(runs.count - ran).toBe(1);
122
+ expect(yield* receipts(tenant, "HttpRoom", "reload")).toBe(1);
123
+ expect(yield* savedIds(store)).toEqual([id]);
124
+ first.close();
125
+ network.down = false;
126
+ const after = HttpRoom.client({
127
+ baseUrl: server.url,
128
+ headers: bearer(tenant),
129
+ fetch: network.fetch,
130
+ offline: store,
131
+ identity: () => `${tenant}/alice`,
132
+ });
133
+ const second = queueOf(after);
134
+ yield* Effect.addFinalizer(() => Effect.sync(() => second.close()));
135
+ yield* until(() => second.pending.length === 0 && network.commands("Post").length >= 2);
136
+ expect(network.commands("Post").slice(0, 2)).toEqual([id, id]);
137
+ expect(runs.count - ran).toBe(1);
138
+ expect(yield* receipts(tenant, "HttpRoom", "reload")).toBe(1);
139
+ expect(yield* savedIds(store)).toEqual([]);
140
+ })),
141
+ },
142
+ {
143
+ name: "offline client fails a queued command older than the id window as CommandExpired without sending it or minting another id",
144
+ run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
145
+ const server = yield* serveHttp();
146
+ const actors = yield* InternalActors;
147
+ const tenant = yield* tenantOf;
148
+ const network = wire();
149
+ const store = Offline.memory();
150
+ const expired = yield* server.mint(-actors.retryWindowMs - 1);
151
+ const stale = {
152
+ commandId: expired,
153
+ sequence: 0,
154
+ baseUrl: server.url,
155
+ principal: `${tenant}/alice`,
156
+ target: "/actors/HttpRoom/stale",
157
+ member: "Post",
158
+ body: '{"text":"old"}',
159
+ status: "queued",
160
+ answer: undefined,
161
+ };
162
+ yield* Effect.promise(() => store.save(stale));
163
+ const rooms = HttpRoom.client({
164
+ baseUrl: server.url,
165
+ headers: bearer(tenant),
166
+ fetch: network.fetch,
167
+ offline: store,
168
+ identity: () => `${tenant}/alice`,
169
+ });
170
+ const queue = queueOf(rooms);
171
+ const ran = runs.count;
172
+ yield* Effect.addFinalizer(() => Effect.sync(() => queue.close()));
173
+ yield* Effect.promise(() => queue.ready);
174
+ expect(queue.pending.map((pending) => pending.status)).toEqual(["expired"]);
175
+ expect(queue.pending[0]?.failure).toBeInstanceOf(ActorError);
176
+ expect(queue.pending[0]?.input).toEqual({ text: "old" });
177
+ const explicit = yield* settle(rooms.get("stale").Post({ text: "old" }, { commandId: expired }));
178
+ expect(reasonOf(explicit)).toMatchObject({ tag: "CommandExpired", commandId: expired });
179
+ expect(network.commands("Post")).toEqual([]);
180
+ expect(runs.count).toBe(ran);
181
+ expect(yield* receipts(tenant, "HttpRoom", "stale")).toBe(0);
182
+ expect(yield* savedIds(store)).toEqual([expired]);
183
+ yield* Effect.promise(() => queue.discard(expired));
184
+ expect(yield* savedIds(store)).toEqual([]);
185
+ const fresh = yield* settle(rooms.get("stale").Post({ text: "new" }));
186
+ expect(fresh).toEqual({ ok: true, value: 1 });
187
+ expect(network.commands("Post").length).toBe(1);
188
+ expect(network.commands("Post")[0]).not.toBe(expired);
189
+ expect(runs.count - ran).toBe(1);
190
+ })),
191
+ },
192
+ {
193
+ name: "offline client joins a repeated id to the queued command, and the receipt replays a committed id or refuses it with other input",
194
+ run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
195
+ const server = yield* serveHttp();
196
+ const tenant = yield* tenantOf;
197
+ const network = wire();
198
+ const store = Offline.memory();
199
+ const rooms = HttpRoom.client({
200
+ baseUrl: server.url,
201
+ headers: bearer(tenant),
202
+ fetch: network.fetch,
203
+ offline: store,
204
+ identity: () => `${tenant}/alice`,
205
+ timeoutInMs: 300,
206
+ });
207
+ const queue = queueOf(rooms);
208
+ const room = rooms.get("dedup");
209
+ yield* Effect.addFinalizer(() => Effect.sync(() => queue.close()));
210
+ yield* Effect.promise(() => queue.ready);
211
+ const id = yield* Effect.promise(() => rooms.commandId());
212
+ network.down = true;
213
+ const ran = runs.count;
214
+ const both = yield* Effect.promise(() => Promise.allSettled([
215
+ room.Post({ text: "a" }, { commandId: id }),
216
+ room.Post({ text: "a" }, { commandId: id }),
217
+ ]));
218
+ expect(both.map((call) => call.status)).toEqual(["rejected", "rejected"]);
219
+ expect(yield* savedIds(store)).toEqual([id]);
220
+ network.down = false;
221
+ queue.flush();
222
+ yield* until(() => queue.pending.length === 0);
223
+ expect(runs.count - ran).toBe(1);
224
+ expect(yield* receipts(tenant, "HttpRoom", "dedup")).toBe(1);
225
+ const replay = yield* settle(room.Post({ text: "a" }, { commandId: id }));
226
+ expect(replay).toEqual({ ok: true, value: 1 });
227
+ expect(runs.count - ran).toBe(1);
228
+ const other = yield* settle(room.Post({ text: "different" }, { commandId: id }));
229
+ expect(reasonOf(other)).toMatchObject({ tag: "CommandConflict", commandId: id });
230
+ expect(runs.count - ran).toBe(1);
231
+ expect(yield* receipts(tenant, "HttpRoom", "dedup")).toBe(1);
232
+ expect(queue.pending.map((pending) => pending.status)).toEqual(["failed"]);
233
+ yield* Effect.promise(() => queue.discard(id));
234
+ expect(yield* savedIds(store)).toEqual([]);
235
+ })),
236
+ },
237
+ {
238
+ name: "offline client keeps each actor's commands in call order while another actor's commands are not held back",
239
+ run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
240
+ const server = yield* serveHttp();
241
+ const tenant = yield* tenantOf;
242
+ const network = wire();
243
+ const store = Offline.memory();
244
+ const rooms = HttpRoom.client({
245
+ baseUrl: server.url,
246
+ headers: bearer(tenant),
247
+ fetch: network.fetch,
248
+ offline: store,
249
+ identity: () => `${tenant}/alice`,
250
+ timeoutInMs: 200,
251
+ });
252
+ const queue = queueOf(rooms);
253
+ yield* Effect.addFinalizer(() => Effect.sync(() => queue.close()));
254
+ yield* Effect.promise(() => queue.ready);
255
+ yield* Effect.promise(() => rooms.commandId());
256
+ network.blocked = (path) => path.includes("/blocked/");
257
+ const start = posted.length;
258
+ const calls = [
259
+ rooms.get("blocked").Post({ text: "blocked-1" }),
260
+ rooms.get("open").Post({ text: "open-1" }),
261
+ rooms.get("blocked").Post({ text: "blocked-2" }),
262
+ rooms.get("open").Post({ text: "open-2" }),
263
+ ];
264
+ yield* Effect.promise(() => Promise.allSettled(calls));
265
+ yield* until(() => posted.slice(start).length === 2);
266
+ expect(posted.slice(start)).toEqual(["open-1", "open-2"]);
267
+ expect(queue.pending.map((pending) => pending.target)).toEqual([
268
+ "/actors/HttpRoom/blocked",
269
+ "/actors/HttpRoom/blocked",
270
+ ]);
271
+ network.blocked = () => false;
272
+ queue.flush();
273
+ yield* until(() => queue.pending.length === 0);
274
+ expect(posted.slice(start)).toEqual(["open-1", "open-2", "blocked-1", "blocked-2"]);
275
+ expect(yield* receipts(tenant, "HttpRoom", "blocked")).toBe(2);
276
+ })),
277
+ },
278
+ {
279
+ name: "offline client keeps a command the server rejected for good, decoded as its declared error after a reload, until the application discards it",
280
+ run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
281
+ const server = yield* serveHttp();
282
+ const tenant = yield* tenantOf;
283
+ const network = wire();
284
+ const store = Offline.memory();
285
+ const options = {
286
+ baseUrl: server.url,
287
+ headers: bearer(tenant),
288
+ fetch: network.fetch,
289
+ offline: store,
290
+ identity: () => `${tenant}/alice`,
291
+ };
292
+ const rooms = HttpRoom.client({ ...options, timeoutInMs: 200 });
293
+ const queue = queueOf(rooms);
294
+ yield* Effect.addFinalizer(() => Effect.sync(() => queue.close()));
295
+ yield* Effect.promise(() => queue.ready);
296
+ yield* Effect.promise(() => rooms.commandId());
297
+ network.down = true;
298
+ const call = rooms.get("rejected").Post({ text: "full" });
299
+ const timedOut = yield* settle(call);
300
+ expect(reasonOf(timedOut)).toMatchObject({ tag: "Timeout" });
301
+ const id = idsOf(queue)[0];
302
+ network.down = false;
303
+ queue.flush();
304
+ yield* until(() => queue.pending[0]?.status === "failed");
305
+ queue.close();
306
+ const reloaded = queueOf(HttpRoom.client(options));
307
+ yield* Effect.addFinalizer(() => Effect.sync(() => reloaded.close()));
308
+ yield* Effect.promise(() => reloaded.ready);
309
+ expect(reloaded.pending.map((pending) => pending.status)).toEqual(["failed"]);
310
+ expect(reloaded.pending[0]?.failure).toBeInstanceOf(Full);
311
+ expect(network.commands("Post")).toEqual([id]);
312
+ expect(yield* receipts(tenant, "HttpRoom", "rejected")).toBe(1);
313
+ yield* Effect.promise(() => reloaded.discard(id));
314
+ expect(yield* savedIds(store)).toEqual([]);
315
+ })),
316
+ },
317
+ {
318
+ name: "offline client stops an actor's queue on a rejected credential and resumes it under the same id once a valid one is supplied",
319
+ run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
320
+ const server = yield* serveHttp();
321
+ const tenant = yield* tenantOf;
322
+ const network = wire();
323
+ const store = Offline.memory();
324
+ let token = `${tenant}:alice`;
325
+ const rooms = HttpRoom.client({
326
+ baseUrl: server.url,
327
+ headers: () => ({ authorization: `Bearer ${token}` }),
328
+ fetch: network.fetch,
329
+ offline: store,
330
+ identity: () => `${tenant}/alice`,
331
+ timeoutInMs: 300,
332
+ });
333
+ const queue = queueOf(rooms);
334
+ yield* Effect.addFinalizer(() => Effect.sync(() => queue.close()));
335
+ yield* Effect.promise(() => queue.ready);
336
+ yield* Effect.promise(() => rooms.commandId());
337
+ token = "malformed";
338
+ const ran = runs.count;
339
+ const call = yield* settle(rooms.get("signed-out").Post({ text: "held" }));
340
+ const id = idsOf(queue)[0];
341
+ expect(reasonOf(call)).toMatchObject({ tag: "Timeout", commandId: id });
342
+ expect(queue.pending[0]?.status).toBe("queued");
343
+ expect(runs.count).toBe(ran);
344
+ token = `${tenant}:alice`;
345
+ queue.flush();
346
+ yield* until(() => queue.pending.length === 0);
347
+ expect(runs.count - ran).toBe(1);
348
+ expect(new Set(network.commands("Post"))).toEqual(new Set([id]));
349
+ expect(yield* receipts(tenant, "HttpRoom", "signed-out")).toBe(1);
350
+ })),
351
+ },
352
+ {
353
+ name: "offline client holds the commands another principal queued on a shared store, sends only the signed-in principal's, and delivers the held ones once their principal signs back in",
354
+ run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
355
+ const server = yield* serveHttp();
356
+ const tenant = yield* tenantOf;
357
+ const network = wire();
358
+ const store = Offline.memory();
359
+ const signIn = (subject) => Effect.gen(function* () {
360
+ const client = HttpRoom.client({
361
+ baseUrl: server.url,
362
+ headers: { authorization: `Bearer ${tenant}:${subject}` },
363
+ identity: () => `${tenant}/${subject}`,
364
+ fetch: network.fetch,
365
+ offline: store,
366
+ timeoutInMs: 300,
367
+ });
368
+ const queue = queueOf(client);
369
+ yield* Effect.addFinalizer(() => Effect.sync(() => queue.close()));
370
+ yield* Effect.promise(() => queue.ready);
371
+ yield* Effect.promise(() => client.commandId());
372
+ return { client, queue };
373
+ });
374
+ const alice = yield* signIn("alice");
375
+ network.down = true;
376
+ const ran = runs.count;
377
+ const queued = yield* settle(alice.client.get("shared").Post({ text: "from alice" }));
378
+ const aliceId = idsOf(alice.queue)[0];
379
+ expect(reasonOf(queued)).toMatchObject({ tag: "Timeout", commandId: aliceId });
380
+ alice.queue.close();
381
+ network.down = false;
382
+ const bob = yield* signIn("bob");
383
+ yield* until(() => bob.queue.pending[0]?.status === "held");
384
+ bob.queue.flush();
385
+ const own = yield* settle(bob.client.get("bobs").Post({ text: "from bob" }));
386
+ expect(own.ok).toBe(true);
387
+ yield* Effect.sleep("200 millis");
388
+ expect(runs.count - ran).toBe(1);
389
+ expect(network.commands("Post").includes(aliceId)).toBe(false);
390
+ expect(yield* receipts(tenant, "HttpRoom", "shared")).toBe(0);
391
+ expect(bob.queue.pending.map((pending) => [pending.commandId, pending.status])).toEqual([
392
+ [aliceId, "held"],
393
+ ]);
394
+ bob.queue.close();
395
+ const back = yield* signIn("alice");
396
+ back.queue.flush();
397
+ yield* until(() => back.queue.pending.length === 0);
398
+ expect(runs.count - ran).toBe(2);
399
+ expect(yield* receipts(tenant, "HttpRoom", "shared")).toBe(1);
400
+ expect(yield* savedIds(store)).toEqual([]);
401
+ })),
402
+ },
403
+ {
404
+ name: "offline client rejects a command its store could not save, and never sends it",
405
+ run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
406
+ const server = yield* serveHttp();
407
+ const tenant = yield* tenantOf;
408
+ const network = wire();
409
+ const base = Offline.memory();
410
+ const full = {
411
+ ...base,
412
+ save: () => Promise.reject(new Error("quota exceeded")),
413
+ };
414
+ const rooms = HttpRoom.client({
415
+ baseUrl: server.url,
416
+ headers: bearer(tenant),
417
+ fetch: network.fetch,
418
+ offline: full,
419
+ identity: () => `${tenant}/alice`,
420
+ });
421
+ const queue = queueOf(rooms);
422
+ yield* Effect.addFinalizer(() => Effect.sync(() => queue.close()));
423
+ yield* Effect.promise(() => queue.ready);
424
+ const ran = runs.count;
425
+ const result = yield* settle(rooms.get("unsaved").Post({ text: "lost" }));
426
+ expect(result.ok).toBe(false);
427
+ expect(result.ok ? undefined : result.error).toBeInstanceOf(OfflineStoreError);
428
+ expect(network.commands("Post")).toEqual([]);
429
+ expect(runs.count).toBe(ran);
430
+ expect(yield* receipts(tenant, "HttpRoom", "unsaved")).toBe(0);
431
+ expect(queue.pending).toEqual([]);
432
+ })),
433
+ },
434
+ {
435
+ name: "offline client keeps an optimistic reducer applied through the outage and settles on the committed state once replayed",
436
+ run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
437
+ const server = yield* serveHttp();
438
+ const tenant = yield* tenantOf;
439
+ const network = wire();
440
+ const store = Offline.memory();
441
+ const tallies = HttpTally.client({
442
+ baseUrl: server.url,
443
+ headers: bearer(tenant),
444
+ fetch: network.fetch,
445
+ offline: store,
446
+ identity: () => `${tenant}/alice`,
447
+ timeoutInMs: 200,
448
+ });
449
+ const queue = queueOf(tallies);
450
+ const tally = tallies.get("outage");
451
+ yield* Effect.addFinalizer(() => Effect.sync(() => queue.close()));
452
+ yield* Effect.promise(() => queue.ready);
453
+ yield* Effect.promise(() => tallies.commandId());
454
+ tally.state.reconcile({ count: 0 });
455
+ network.down = true;
456
+ const calls = [tally.Bump(), tally.Bump()];
457
+ yield* Effect.promise(() => Promise.allSettled(calls));
458
+ expect(tally.state.current).toEqual({ count: 2 });
459
+ expect(tally.state.pending.length).toBe(2);
460
+ network.down = false;
461
+ queue.flush();
462
+ yield* until(() => queue.pending.length === 0 && tally.state.pending.length === 0);
463
+ expect(tally.state.current).toEqual({ count: 2 });
464
+ const committed = yield* Effect.promise(() => HttpTally.client({ baseUrl: server.url, headers: bearer(tenant) })
465
+ .get("outage")
466
+ .Snapshot());
467
+ expect(committed).toEqual({ count: 2 });
468
+ })),
469
+ },
470
+ ];
471
+ /** Offline cases call the served HTTP actors. */
472
+ export const offlineSuite = {
473
+ uses: [httpSuite],
474
+ };
@@ -0,0 +1,57 @@
1
+ import { Crypto, Effect, Layer, Schema, type Scope } from "effect";
2
+ import { SqlClient } from "effect/sql";
3
+ import { type Actors } from "../../index.ts";
4
+ import type { InternalActors } from "../../runtime/actors.ts";
5
+ import type { Capability } from "../../runtime/operators/grants.ts";
6
+ import { ActorTest } from "../actor-test.ts";
7
+ import type { ConformanceEnvironment } from "../conformance.ts";
8
+ /** An operator answer: its HTTP status and decoded JSON body. */
9
+ export interface Answer {
10
+ readonly status: number;
11
+ readonly body: unknown;
12
+ }
13
+ /** What a case sees of the runtime that serves the operator routes. */
14
+ export interface Harness {
15
+ readonly tenant: string;
16
+ /** Gives `token` a grant of these capabilities from now on. */
17
+ readonly grant: (token: string, capabilities: ReadonlyArray<Capability>) => Effect.Effect<void>;
18
+ /** Sends one operator request with `token` as its bearer credential. */
19
+ readonly send: (method: "GET" | "POST", path: string, token: string | undefined, body?: Schema.Json) => Effect.Effect<Answer>;
20
+ readonly deadLetters: Effect.Effect<ReadonlyArray<{
21
+ job_id: string;
22
+ job: string;
23
+ ambiguous: boolean;
24
+ }>>;
25
+ /**
26
+ * Every audit row in the order the requests wrote them. `at_ms` has
27
+ * millisecond resolution and back-to-back requests can share one, so ties
28
+ * break by the writing transaction's id, which grows with each sequential
29
+ * request, never by the random audit id.
30
+ */
31
+ readonly audit: Effect.Effect<ReadonlyArray<AuditRow>>;
32
+ }
33
+ /** One `durable.operator_audit` row. */
34
+ export interface AuditRow {
35
+ readonly operator: string;
36
+ readonly action: string;
37
+ readonly actor_id: string | null;
38
+ readonly target: string | null;
39
+ readonly capability: string | null;
40
+ readonly reason: string | null;
41
+ readonly outcome: string;
42
+ }
43
+ /**
44
+ * A runtime of its own on a fresh database, running `live` and serving
45
+ * `Operators.serve` with these tokens through an in-memory web handler.
46
+ * `reset` runs first, so a fixture starts each case clean. The retry window
47
+ * is the suite's, so command ids the suite runtime mints are valid here, and
48
+ * `grants` starts from `tokens` so a case can add one once it knows the ids
49
+ * it names.
50
+ */
51
+ export declare const operatorHarness: <A, E>({ environment, live, reset, tokens, body, }: {
52
+ readonly environment: ConformanceEnvironment;
53
+ readonly live: Layer.Layer<never, never, InternalActors>;
54
+ readonly reset: () => void;
55
+ readonly tokens: Record<string, ReadonlyArray<Capability>>;
56
+ readonly body: (harness: Harness) => Effect.Effect<A, E, Actors | ActorTest | SqlClient.SqlClient | Crypto.Crypto | Scope.Scope>;
57
+ }) => Promise<A>;
@@ -0,0 +1,78 @@
1
+ import { Context, Crypto, Effect, Layer, Schema } from "effect";
2
+ import { HttpRouter } from "effect/http";
3
+ import { SqlClient } from "effect/sql";
4
+ import { Unauthorized } from "../../index.js";
5
+ import { OperatorAuth } from "../../runtime/operators/auth.js";
6
+ import { Operators } from "../../runtime/operators/routes.js";
7
+ import { bearerToken } from "../../serve/auth.js";
8
+ import { ActorTest } from "../actor-test.js";
9
+ /**
10
+ * A runtime of its own on a fresh database, running `live` and serving
11
+ * `Operators.serve` with these tokens through an in-memory web handler.
12
+ * `reset` runs first, so a fixture starts each case clean. The retry window
13
+ * is the suite's, so command ids the suite runtime mints are valid here, and
14
+ * `grants` starts from `tokens` so a case can add one once it knows the ids
15
+ * it names.
16
+ */
17
+ export const operatorHarness = ({ environment, live, reset, tokens, body, }) => environment.run(Effect.gen(function* () {
18
+ const crypto = yield* Crypto.Crypto;
19
+ const database = yield* environment.freshDatabase;
20
+ reset();
21
+ const services = yield* Layer.buildWithMemoMap(live.pipe(Layer.provideMerge(ActorTest.layer({
22
+ database,
23
+ retryWindowMs: 60_000,
24
+ })), Layer.provide(Layer.succeed(Crypto.Crypto, crypto)), Layer.orDie), yield* Layer.makeMemoMap, yield* Effect.scope);
25
+ const grants = new Map(Object.entries(tokens).map(([token, capabilities]) => [
26
+ token,
27
+ { operator: `op-${token}`, capabilities },
28
+ ]));
29
+ const auth = OperatorAuth.make((request) => Effect.flatMap(bearerToken(request), (token) => {
30
+ const grant = grants.get(token);
31
+ return grant === undefined
32
+ ? Effect.fail(Unauthorized.make({ code: "invalid_credentials" }))
33
+ : Effect.succeed(grant);
34
+ }));
35
+ const web = HttpRouter.toWebHandler(Operators.serve({ auth }).pipe(Layer.provide(Layer.succeedContext(services))), { disableLogger: true });
36
+ yield* Effect.addFinalizer(() => Effect.promise(() => web.dispose()));
37
+ const sql = Context.get(services, SqlClient.SqlClient);
38
+ const tenant = Context.get(services, ActorTest).tenant;
39
+ const harness = {
40
+ tenant,
41
+ grant: (token, capabilities) => Effect.sync(() => {
42
+ grants.set(token, { operator: `op-${token}`, capabilities });
43
+ }),
44
+ send: (method, path, token, payload) => Effect.gen(function* () {
45
+ const encoded = payload === undefined ? undefined : yield* encodeJson(payload).pipe(Effect.orDie);
46
+ const response = yield* Effect.promise(() => web.handler(encoded === undefined
47
+ ? new Request(`http://runner${path}`, {
48
+ method,
49
+ headers: requestHeaders(token, encoded),
50
+ })
51
+ : new Request(`http://runner${path}`, {
52
+ method: "POST",
53
+ headers: requestHeaders(token, encoded),
54
+ body: encoded,
55
+ })));
56
+ const text = yield* Effect.promise(() => response.text());
57
+ return {
58
+ status: response.status,
59
+ body: text.length === 0 ? null : yield* decodeJson(text).pipe(Effect.orDie),
60
+ };
61
+ }),
62
+ deadLetters: sql `
63
+ SELECT job_id, job, ambiguous FROM actor_dead_letters ORDER BY dead_at_ms`.pipe(Effect.orDie),
64
+ audit: sql `SELECT operator, action, actor_id, target, capability, reason, outcome
65
+ FROM actor_operator_audit ORDER BY at_ms, xmin::text::bigint`.pipe(Effect.orDie),
66
+ };
67
+ return yield* body(harness).pipe(Effect.provideContext(services));
68
+ }));
69
+ const requestHeaders = (token, body) => {
70
+ const headers = new Headers();
71
+ if (token !== undefined)
72
+ headers.set("authorization", `Bearer ${token}`);
73
+ if (body !== undefined)
74
+ headers.set("content-type", "application/json");
75
+ return headers;
76
+ };
77
+ const encodeJson = Schema.encodeEffect(Schema.fromJsonString(Schema.Unknown));
78
+ const decodeJson = Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.Unknown));
@@ -0,0 +1,3 @@
1
+ import type { ConformanceCase } from "../conformance.ts";
2
+ /** Operator cases: application credentials are refused, grants are scoped by action and resource with audited denials, and inspection and repair follow their scopes. */
3
+ export declare const operatorConformance: ReadonlyArray<ConformanceCase>;