@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,816 @@
1
+ import { Cause, Clock, Crypto, Effect, Exit, Fiber, Option, Predicate, Queue, Random, Schedule, Schema, Scope, Stream, } from "effect";
2
+ import { SqlClient } from "effect/sql";
3
+ import { ActorError, ActorUnavailable, SessionEnded, Unauthorized } from "../../errors/actor.js";
4
+ import { connectionSecret } from "../../identity/connection.js";
5
+ import { FrameworkClock } from "../turn/admission.js";
6
+ import { shardClients } from "../database/shards.js";
7
+ import { ClientMessage, HolderItem, isWatchMember, watchedQuery, } from "./protocol.js";
8
+ /** The largest encoded inbound frame or open params a holder accepts. */
9
+ export const MAX_INBOUND_BYTES = 65_536;
10
+ /** Open connections one holder keeps at once. */
11
+ export const MAX_HELD_CONNECTIONS = 50_000;
12
+ /** Bytes buffered across one holder's connections, both directions. */
13
+ export const MAX_HELD_BYTES = 268_435_456;
14
+ /** Outbound frames one connection may have waiting for its client. */
15
+ export const MAX_OUTBOUND_FRAMES = 1_024;
16
+ /** Outbound bytes one connection may have waiting for its client. */
17
+ export const MAX_OUTBOUND_BYTES = 1_048_576;
18
+ /** How long a client has to answer `Resync` with `ResyncDone`. */
19
+ export const RESYNC_DEADLINE_MS = 30_000;
20
+ /** A third owner loss within this window ends the connection instead of resyncing again. */
21
+ export const RESYNC_WINDOW_MS = 300_000;
22
+ /** Inbound frames a connection may have in flight before its transport stops reading. */
23
+ export const MAX_INFLIGHT_FRAMES = 32;
24
+ const TICK = "100 millis";
25
+ const OWNER_CHECK_MS = 1_000;
26
+ const LIVENESS_MS = 10_000;
27
+ const MAX_INBOUND_FRAMES = 1_024;
28
+ const COMMAND_SKEW_MS = 1_000;
29
+ const utf8 = new TextEncoder();
30
+ /** The declared failure an `open` handler returned, still encoded. */
31
+ export class OpenRejected extends Schema.TaggedError()("OpenRejected", {
32
+ value: Schema.String,
33
+ }) {
34
+ }
35
+ const actorKey = (ref) => `${ref.tenant}\u0000${ref.actor}\u0000${ref.id}`;
36
+ const ended = (cause, resync, retryAfterMs) => ActorError.make({
37
+ reason: SessionEnded.make({
38
+ cause,
39
+ resync,
40
+ retryAfterMs,
41
+ }),
42
+ });
43
+ /**
44
+ * The socket side of connections on one runner: it holds each connection's
45
+ * buffers, caller, and authorization clock, orders inbound frames, applies the
46
+ * owner's ordered messages, and resyncs its connections in place when their
47
+ * owner dies. Actor activations never hold a socket.
48
+ *
49
+ * Authorization: nothing reaches a client or an owner past the connection's
50
+ * authorization bound. A session past its credential's expiry reports that;
51
+ * otherwise its last check is too old. A credential's expiry caps the session and
52
+ * its buffered frames go with it. An answer that arrives past the bound never
53
+ * extends it, and a credential that expired while authorization ran opens nothing.
54
+ * A holder that cannot confirm its rows for a whole bound stops serving them; a
55
+ * connection opened since the checks began failing counts from its open. A
56
+ * revoked client receives nothing more, including frames already queued.
57
+ *
58
+ * Buffering: a member frame evicts buffered progress oldest first before the
59
+ * connection counts as a slow consumer. A newer progress frame that would not fit
60
+ * is dropped and the waiting one stays. A progress marker delivers the newest
61
+ * frame of its job, or nothing if it was discarded.
62
+ *
63
+ * Owner ordering: an owner acknowledges each message before sending the next, so
64
+ * the first message a record sees follows everything its connections could have
65
+ * missed. Redelivered messages were already applied, and late messages from a
66
+ * dead or superseded generation are dropped. A gap makes every connection replay
67
+ * from its cursor. A newer generation over an unsealed older one means the older
68
+ * owner died, and every connection resyncs in place; a loss during a resync
69
+ * restarts it from the same cursor and keeps the frames it deferred. An older
70
+ * owner's progress never reaches a client after a newer owner's messages, and a
71
+ * ping answered after a newer owner was observed says nothing about that owner.
72
+ * Live frames wait until a resync's replay is acknowledged, and inbound frames are
73
+ * delivered one at a time after any pending resync. Acknowledgments before the new
74
+ * owner answered, or before the member's replay finished, are ignored. Until the
75
+ * new owner answers, the resync deadline bounds the takeover; then the client's
76
+ * acknowledgment does.
77
+ *
78
+ * Opening and closing: a connection registers before the owner commits so frames
79
+ * flushed after that commit find it. The owner may still commit an open the holder
80
+ * gave up on; such a late row is closed again. A lost owner's opening frames and
81
+ * unflushed broadcasts may be gone. An open handler that closed the connection
82
+ * leaves it ended with `ServerClosed`. On close the owner deletes the row, and the
83
+ * holder deletes its own if the owner cannot. Rows an unreachable owner dropped
84
+ * end their connections so clients reconnect. A graceful shutdown ends every
85
+ * connection with a resync hint and deletes its rows. A feed connection is
86
+ * authorized as each event tag it reads, all of which must pass.
87
+ */
88
+ export const connectionHolder = Effect.fnUntraced(function* (options) {
89
+ const sql = yield* SqlClient.SqlClient;
90
+ const shards = yield* shardClients;
91
+ const crypto = yield* Crypto.Crypto;
92
+ const clock = yield* FrameworkClock;
93
+ const scope = yield* Effect.scope;
94
+ const actors = new Map();
95
+ const held = new Map();
96
+ let heldBytes = 0;
97
+ let lastLiveness = 0;
98
+ let livenessFailedSince = undefined;
99
+ let checkingLiveness = false;
100
+ const now = Effect.map(Clock.currentTimeMillis, (millis) => millis + clock.offsetMillis());
101
+ const address = (connection) => {
102
+ const transport = options.transport();
103
+ return {
104
+ ref: connection.ref,
105
+ connectionId: connection.id,
106
+ holder: transport.holder,
107
+ holderEpoch: transport.epoch,
108
+ };
109
+ };
110
+ const actorOf = (ref) => {
111
+ const key = actorKey(ref);
112
+ const found = actors.get(key);
113
+ if (found !== undefined)
114
+ return found;
115
+ const created = {
116
+ generation: 0n,
117
+ seq: 0,
118
+ sealed: true,
119
+ through: "0",
120
+ owner: "",
121
+ ownerEpoch: "",
122
+ lastCheck: 0,
123
+ fresh: true,
124
+ connections: new Map(),
125
+ };
126
+ actors.set(key, created);
127
+ return created;
128
+ };
129
+ const deleteRow = (connection) => sql `DELETE FROM actor_connections WHERE routing_key = ${connection.type.routingKey(connection.ref)}
130
+ AND tenant_id = ${connection.ref.tenant} AND actor_type = ${connection.ref.actor}
131
+ AND actor_id = ${connection.ref.id} AND connection_id = ${connection.id}
132
+ AND holder_epoch = ${options.transport().epoch}`.pipe(Effect.ignore);
133
+ const release = (connection) => {
134
+ heldBytes -= connection.outBytes + connection.inBytes + (connection.resync?.deferredBytes ?? 0);
135
+ if (connection.resync !== undefined)
136
+ connection.resync.deferredBytes = 0;
137
+ connection.outBytes = 0;
138
+ connection.inBytes = 0;
139
+ connection.inbound.length = 0;
140
+ connection.progress.clear();
141
+ held.delete(connection.id);
142
+ const actor = actors.get(connection.key);
143
+ actor?.connections.delete(connection.id);
144
+ if (actor !== undefined && actor.connections.size === 0)
145
+ actors.delete(connection.key);
146
+ };
147
+ const end = (connection, error, deleteOwnRow) => Effect.gen(function* () {
148
+ if (connection.ended)
149
+ return;
150
+ connection.ended = true;
151
+ connection.open = false;
152
+ release(connection);
153
+ if (Predicate.isTagged(error.reason, "Unauthorized"))
154
+ yield* Effect.ignore(Queue.clear(connection.outbound));
155
+ yield* Queue.fail(connection.outbound, error);
156
+ yield* Queue.offer(connection.wake, undefined);
157
+ yield* Queue.offer(connection.drained, undefined);
158
+ if (deleteOwnRow)
159
+ yield* deleteRow(connection);
160
+ });
161
+ const discardProgress = (connection, jobId) => {
162
+ const pending = connection.progress.get(jobId);
163
+ if (pending === undefined)
164
+ return;
165
+ connection.progress.delete(jobId);
166
+ connection.outFrames -= 1;
167
+ connection.outBytes -= pending.bytes;
168
+ heldBytes -= pending.bytes;
169
+ };
170
+ const fits = (connection, bytes) => connection.outFrames + 1 <= MAX_OUTBOUND_FRAMES &&
171
+ connection.outBytes + bytes <= MAX_OUTBOUND_BYTES &&
172
+ heldBytes + bytes <= MAX_HELD_BYTES;
173
+ /**
174
+ * Buffers a progress frame. A newer frame of the same job replaces the
175
+ * waiting one in place; one that does not fit is dropped. Progress never
176
+ * ends a session.
177
+ */
178
+ const pushProgress = (connection, message) => Effect.gen(function* () {
179
+ if (connection.ended || connection.resync !== undefined)
180
+ return;
181
+ const bytes = utf8.encode(message.frame).byteLength;
182
+ const waiting = connection.progress.get(message.jobId);
183
+ if (waiting !== undefined) {
184
+ if (connection.outBytes - waiting.bytes + bytes > MAX_OUTBOUND_BYTES ||
185
+ heldBytes - waiting.bytes + bytes > MAX_HELD_BYTES)
186
+ return;
187
+ connection.outBytes += bytes - waiting.bytes;
188
+ heldBytes += bytes - waiting.bytes;
189
+ waiting.message = message;
190
+ waiting.bytes = bytes;
191
+ return;
192
+ }
193
+ if (!fits(connection, bytes))
194
+ return;
195
+ connection.progress.set(message.jobId, { message, bytes });
196
+ connection.outFrames += 1;
197
+ connection.outBytes += bytes;
198
+ heldBytes += bytes;
199
+ yield* Queue.offer(connection.outbound, message);
200
+ });
201
+ const push = (connection, message, control) => Effect.gen(function* () {
202
+ if (connection.ended)
203
+ return;
204
+ const bytes = ClientMessage.guards.Frame(message) ? utf8.encode(message.frame).byteLength : 0;
205
+ if (!control)
206
+ for (const jobId of connection.progress.keys()) {
207
+ if (fits(connection, bytes))
208
+ break;
209
+ discardProgress(connection, jobId);
210
+ }
211
+ if (!control &&
212
+ (connection.outFrames + 1 > MAX_OUTBOUND_FRAMES ||
213
+ connection.outBytes + bytes > MAX_OUTBOUND_BYTES ||
214
+ heldBytes + bytes > MAX_HELD_BYTES))
215
+ return yield* end(connection, ended("SlowConsumer", true), true);
216
+ connection.outFrames += 1;
217
+ connection.outBytes += bytes;
218
+ heldBytes += bytes;
219
+ yield* Queue.offer(connection.outbound, message);
220
+ });
221
+ const takenProgress = (connection, marker) => Effect.sync(() => {
222
+ const pending = connection.progress.get(marker.jobId);
223
+ if (connection.ended || pending === undefined)
224
+ return Option.none();
225
+ discardProgress(connection, marker.jobId);
226
+ return Option.some(pending.message);
227
+ });
228
+ const taken = (connection, message) => Effect.sync(() => {
229
+ if (connection.ended)
230
+ return;
231
+ const bytes = ClientMessage.guards.Frame(message) ? utf8.encode(message.frame).byteLength : 0;
232
+ connection.outFrames -= 1;
233
+ connection.outBytes -= bytes;
234
+ heldBytes -= bytes;
235
+ });
236
+ const ownerLost = (actor) => Effect.gen(function* () {
237
+ if (actor.sealed)
238
+ return;
239
+ actor.sealed = true;
240
+ const at = yield* now;
241
+ for (const connection of actor.connections.values()) {
242
+ if (connection.open)
243
+ yield* resync(actor, connection, at);
244
+ }
245
+ });
246
+ const resync = (actor, connection, at, from) => Effect.gen(function* () {
247
+ connection.resyncs = connection.resyncs.filter((time) => at - time < RESYNC_WINDOW_MS);
248
+ connection.resyncs.push(at);
249
+ if (connection.resyncs.length >= 3) {
250
+ const retryAfterMs = yield* Random.nextIntBetween(1_000, 5_000);
251
+ yield* end(connection, ended("OwnerLost", true, retryAfterMs), true);
252
+ return;
253
+ }
254
+ const previous = connection.resync;
255
+ const after = previous !== undefined
256
+ ? previous.after
257
+ : (from ?? actor.through) === "0"
258
+ ? undefined
259
+ : (from ?? actor.through);
260
+ connection.resync = {
261
+ after,
262
+ replayed: false,
263
+ sent: false,
264
+ answered: false,
265
+ deadline: at + connection.type.takeoverMs,
266
+ deferred: previous?.deferred ?? [],
267
+ deferredBytes: previous?.deferredBytes ?? 0,
268
+ replayedEvents: previous?.replayedEvents ?? new Set(),
269
+ };
270
+ yield* push(connection, ClientMessage.cases.Resync.make({
271
+ after,
272
+ reason: "OwnerLost",
273
+ deadlineMs: RESYNC_DEADLINE_MS,
274
+ }), true);
275
+ yield* Queue.offer(connection.wake, undefined);
276
+ });
277
+ const observe = (actor, owner) => Effect.gen(function* () {
278
+ const generation = BigInt(owner.generation);
279
+ if (generation < actor.generation)
280
+ return false;
281
+ if (generation > actor.generation) {
282
+ for (const connection of actor.connections.values())
283
+ for (const jobId of connection.progress.keys())
284
+ discardProgress(connection, jobId);
285
+ if (actor.generation > 0n)
286
+ yield* ownerLost(actor);
287
+ actor.generation = generation;
288
+ actor.seq = 0;
289
+ actor.sealed = false;
290
+ }
291
+ actor.owner = owner.owner;
292
+ actor.ownerEpoch = owner.ownerEpoch;
293
+ return true;
294
+ });
295
+ const deliver = (message) => Effect.gen(function* () {
296
+ const actor = actors.get(actorKey(message.ref));
297
+ const unknown = [];
298
+ if (actor === undefined) {
299
+ for (const item of message.items)
300
+ if (HolderItem.guards.Frame(item))
301
+ unknown.push(...item.to);
302
+ return { wrongEpoch: false, unknown };
303
+ }
304
+ if (!(yield* observe(actor, message)))
305
+ return { wrongEpoch: false, unknown };
306
+ if (actor.fresh) {
307
+ actor.fresh = false;
308
+ actor.seq = message.seq - 1;
309
+ }
310
+ if (message.seq <= actor.seq)
311
+ return { wrongEpoch: false, unknown };
312
+ if (message.seq !== actor.seq + 1) {
313
+ for (const connection of actor.connections.values())
314
+ yield* end(connection, ended("SlowConsumer", true), true);
315
+ actor.seq = message.seq;
316
+ return { wrongEpoch: false, unknown };
317
+ }
318
+ actor.seq = message.seq;
319
+ const at = yield* now;
320
+ for (const item of message.items)
321
+ yield* HolderItem.match(item, {
322
+ Frame: (frame) => Effect.forEach(frame.to, (id) => {
323
+ const connection = actor.connections.get(id);
324
+ if (connection === undefined || connection.member !== frame.member) {
325
+ unknown.push(id);
326
+ return Effect.void;
327
+ }
328
+ if (at >= authorizedUntil(connection))
329
+ return end(connection, lapsed(connection, at), true);
330
+ const out = ClientMessage.cases.Frame.make({
331
+ frame: frame.frame,
332
+ cursor: frame.stamp ? message.through : undefined,
333
+ event: frame.stamp ? frame.event : undefined,
334
+ });
335
+ const pending = connection.resync;
336
+ if (pending !== undefined && frame.replay !== true) {
337
+ const bytes = utf8.encode(out.frame).byteLength;
338
+ if (pending.deferred.length + connection.outFrames >= MAX_OUTBOUND_FRAMES ||
339
+ pending.deferredBytes + connection.outBytes + bytes > MAX_OUTBOUND_BYTES ||
340
+ heldBytes + bytes > MAX_HELD_BYTES)
341
+ return end(connection, ended("SlowConsumer", true), true);
342
+ pending.deferred.push(out);
343
+ pending.deferredBytes += bytes;
344
+ heldBytes += bytes;
345
+ return Effect.void;
346
+ }
347
+ if (pending !== undefined && frame.event !== undefined)
348
+ pending.replayedEvents.add(frame.event);
349
+ return push(connection, out, false);
350
+ }, { discard: true }),
351
+ Flushed: (flushed) => Effect.sync(() => {
352
+ actor.through = flushed.through;
353
+ }),
354
+ End: (item) => {
355
+ const connection = actor.connections.get(item.connectionId);
356
+ return connection === undefined
357
+ ? Effect.void
358
+ : end(connection, ActorError.make({ reason: item.ended }), false);
359
+ },
360
+ Seal: () => Effect.sync(() => {
361
+ actor.sealed = true;
362
+ }),
363
+ Progress: (item) => Effect.forEach(item.to, (id) => {
364
+ const connection = actor.connections.get(id);
365
+ if (connection === undefined || connection.member !== item.member) {
366
+ unknown.push(id);
367
+ return Effect.void;
368
+ }
369
+ if (at >= authorizedUntil(connection))
370
+ return end(connection, lapsed(connection, at), true);
371
+ return pushProgress(connection, ClientMessage.cases.Progress.make({
372
+ job: item.job,
373
+ jobId: item.jobId,
374
+ attempt: item.attempt,
375
+ seq: item.seq,
376
+ frame: item.frame,
377
+ }));
378
+ }, { discard: true }),
379
+ ProgressEnd: (item) => Effect.sync(() => {
380
+ for (const connection of actor.connections.values())
381
+ discardProgress(connection, item.jobId);
382
+ }),
383
+ });
384
+ return { wrongEpoch: false, unknown };
385
+ });
386
+ const retried = (connection, effect, refused = () => false) => effect.pipe(Effect.retry({
387
+ while: (error) => error.isRetryable && !connection.ended && !refused(error),
388
+ schedule: Schedule.min([
389
+ Schedule.exponential("10 millis", 2),
390
+ Schedule.spaced("250 millis"),
391
+ ]),
392
+ }));
393
+ const retrying = (connection, effect, deadlineMs) => retried(connection, effect).pipe(Effect.timeoutOrElse({
394
+ duration: deadlineMs,
395
+ orElse: () => Effect.fail(ended("ActorUnavailable", true)),
396
+ }));
397
+ const authorizedUntil = (connection) => Math.min(connection.lastAuthorized + connection.type.reauthorizeMs, connection.expiresAt ?? Number.POSITIVE_INFINITY);
398
+ const unauthorized = ActorError.make({
399
+ reason: Unauthorized.make({ code: "reauthorization_unavailable" }),
400
+ });
401
+ const credentialExpired = ActorError.make({ reason: Unauthorized.make({ code: "expired" }) });
402
+ const lapsed = (connection, at) => connection.expiresAt !== undefined && at >= connection.expiresAt
403
+ ? credentialExpired
404
+ : unauthorized;
405
+ const expired = (connection) => Effect.gen(function* () {
406
+ const at = yield* now;
407
+ if (at < authorizedUntil(connection))
408
+ return false;
409
+ yield* end(connection, lapsed(connection, at), true);
410
+ return true;
411
+ });
412
+ const commandsOf = (connection, seq, issuedAt) => ({
413
+ secret: connection.secret,
414
+ seq,
415
+ issuedAt,
416
+ expiresAt: issuedAt + connection.type.retryWindowMs,
417
+ });
418
+ const inboundLoop = (connection) => Effect.gen(function* () {
419
+ while (!connection.ended) {
420
+ const pending = connection.resync;
421
+ if (pending !== undefined && !pending.sent) {
422
+ if (yield* expired(connection))
423
+ return;
424
+ pending.sent = true;
425
+ const answer = yield* retrying(connection, connection.type.channel.resync({
426
+ ...address(connection),
427
+ after: pending.after,
428
+ authorizedUntil: authorizedUntil(connection),
429
+ }), Math.max(0, Math.min(authorizedUntil(connection), pending.deadline) - (yield* now))).pipe(Effect.exit);
430
+ if (connection.ended)
431
+ return;
432
+ if (yield* expired(connection))
433
+ return;
434
+ if (Exit.isFailure(answer)) {
435
+ yield* end(connection, ended("OwnerLost", true), true);
436
+ return;
437
+ }
438
+ if (Predicate.isTagged(answer.value, "Closed")) {
439
+ yield* end(connection, ActorError.make({ reason: answer.value.ended }), true);
440
+ return;
441
+ }
442
+ yield* observe(actorOf(connection.ref), answer.value);
443
+ pending.answered = true;
444
+ pending.deadline = (yield* now) + RESYNC_DEADLINE_MS;
445
+ if (connection.type.hasResync(connection.member)) {
446
+ pending.replayed = true;
447
+ yield* push(connection, ClientMessage.cases.ResyncReplayed.make({}), true);
448
+ }
449
+ continue;
450
+ }
451
+ if (pending !== undefined || connection.inbound.length === 0) {
452
+ yield* Queue.take(connection.wake);
453
+ continue;
454
+ }
455
+ if (yield* expired(connection))
456
+ return;
457
+ const { frame, issuedAt } = connection.inbound.shift();
458
+ const bytes = utf8.encode(frame).byteLength;
459
+ connection.inBytes -= bytes;
460
+ heldBytes -= bytes;
461
+ yield* Queue.offer(connection.drained, undefined);
462
+ connection.nextSeq += 1;
463
+ const seq = connection.nextSeq;
464
+ const answer = yield* retrying(connection, connection.type.channel.frame({
465
+ ...address(connection),
466
+ seq,
467
+ frame,
468
+ authorizedUntil: authorizedUntil(connection),
469
+ commands: commandsOf(connection, seq, issuedAt),
470
+ }), Math.min(connection.type.deliveryMs, authorizedUntil(connection) - (yield* now))).pipe(Effect.exit);
471
+ if (connection.ended)
472
+ return;
473
+ if (yield* expired(connection))
474
+ return;
475
+ if (Exit.isFailure(answer)) {
476
+ const failure = Cause.findErrorOption(answer.cause);
477
+ yield* end(connection, Option.isSome(failure) ? failure.value : ended("ActorUnavailable", true), true);
478
+ return;
479
+ }
480
+ if (Predicate.isTagged(answer.value, "Closed")) {
481
+ yield* end(connection, ActorError.make({ reason: answer.value.ended }), false);
482
+ return;
483
+ }
484
+ yield* observe(actorOf(connection.ref), answer.value);
485
+ }
486
+ });
487
+ const check = (session, feed, kind) => isWatchMember(session.member)
488
+ ? options.authorize({
489
+ caller: session.caller,
490
+ ref: session.ref,
491
+ command: watchedQuery(session.member),
492
+ kind: kind === "first" ? "watch" : "reauthorize",
493
+ of: kind === "first" ? undefined : "watch",
494
+ })
495
+ : feed === undefined
496
+ ? options.authorize({
497
+ caller: session.caller,
498
+ ref: session.ref,
499
+ command: session.member,
500
+ kind: kind === "first" ? "open" : "reauthorize",
501
+ of: kind === "first" ? undefined : "open",
502
+ })
503
+ : Effect.forEach(feed, (tag) => options.authorize({
504
+ caller: session.caller,
505
+ ref: session.ref,
506
+ command: tag,
507
+ kind: kind === "first" ? "feed" : "reauthorize",
508
+ of: kind === "first" ? undefined : "feed",
509
+ })).pipe(Effect.map((answers) => answers.every(Boolean)));
510
+ const reauthorize = (connection, at) => Effect.gen(function* () {
511
+ connection.checking = true;
512
+ const allowed = yield* check(connection, connection.feed, "reauthorize").pipe(Effect.exit);
513
+ connection.checking = false;
514
+ if (connection.ended)
515
+ return;
516
+ const answered = yield* now;
517
+ if (Exit.isSuccess(allowed) && allowed.value && answered >= authorizedUntil(connection))
518
+ yield* end(connection, lapsed(connection, answered), true);
519
+ else if (Exit.isSuccess(allowed) && allowed.value)
520
+ connection.lastAuthorized = at;
521
+ else if (Exit.isSuccess(allowed))
522
+ yield* end(connection, ActorError.make({ reason: Unauthorized.make({ code: "access_denied" }) }), true);
523
+ });
524
+ const liveness = (at) => Effect.gen(function* () {
525
+ const transport = options.transport();
526
+ const checked = [...held.values()].filter((connection) => connection.open);
527
+ const rows = (yield* Effect.forEach(shards, ({ sql, range }) => sql `
528
+ SELECT c.connection_id
529
+ FROM generate_series(${range.first}::int, ${range.last}::int) AS b(bucket)
530
+ CROSS JOIN LATERAL (
531
+ SELECT connection_id FROM actor_connections
532
+ WHERE actor_connections.bucket = b.bucket AND holder = ${transport.holder}
533
+ AND holder_epoch = ${transport.epoch}
534
+ ) c`)).flat();
535
+ lastLiveness = at;
536
+ livenessFailedSince = undefined;
537
+ const present = new Set(rows.map((row) => row.connection_id));
538
+ for (const connection of checked)
539
+ if (!present.has(connection.id))
540
+ yield* end(connection, ended("ServerClosed", true), false);
541
+ }).pipe(Effect.catchCause((cause) => Effect.andThen(Effect.sync(() => (livenessFailedSince ??= at)), Effect.logWarning("Holder liveness check failed", cause))));
542
+ const tick = Effect.gen(function* () {
543
+ const at = yield* now;
544
+ for (const connection of held.values()) {
545
+ if (!connection.open)
546
+ continue;
547
+ const every = connection.type.reauthorizeMs;
548
+ if (livenessFailedSince !== undefined &&
549
+ at - Math.max(livenessFailedSince, connection.openedAt) >= every) {
550
+ yield* end(connection, ended("ActorUnavailable", true), false);
551
+ continue;
552
+ }
553
+ if (connection.expiresAt !== undefined && at >= connection.expiresAt) {
554
+ yield* end(connection, credentialExpired, true);
555
+ continue;
556
+ }
557
+ if (at >= connection.lastAuthorized + every) {
558
+ yield* end(connection, unauthorized, true);
559
+ continue;
560
+ }
561
+ if (!connection.checking &&
562
+ at >= connection.lastAuthorized + every - Math.min(10_000, every / 2))
563
+ yield* reauthorize(connection, at).pipe(Effect.forkIn(scope));
564
+ if (connection.resync !== undefined && at >= connection.resync.deadline)
565
+ yield* end(connection, ended("OwnerLost", true), true);
566
+ }
567
+ const transport = options.transport();
568
+ const every = Math.min(LIVENESS_MS, ...[...held.values()].map((connection) => connection.type.reauthorizeMs));
569
+ if (!checkingLiveness && held.size > 0 && at - lastLiveness >= every) {
570
+ checkingLiveness = true;
571
+ yield* liveness(at).pipe(Effect.ensuring(Effect.sync(() => (checkingLiveness = false))), Effect.forkIn(scope));
572
+ }
573
+ for (const actor of actors.values()) {
574
+ if (actor.sealed || actor.owner === "" || at - actor.lastCheck < OWNER_CHECK_MS)
575
+ continue;
576
+ actor.lastCheck = at;
577
+ if (actor.owner === transport.holder && actor.ownerEpoch === transport.epoch)
578
+ continue;
579
+ const { owner, ownerEpoch, generation } = actor;
580
+ yield* transport.ping(owner, ownerEpoch).pipe(Effect.flatMap((alive) => alive ||
581
+ actor.generation !== generation ||
582
+ actor.owner !== owner ||
583
+ actor.ownerEpoch !== ownerEpoch
584
+ ? Effect.void
585
+ : ownerLost(actor)), Effect.forkIn(scope));
586
+ }
587
+ });
588
+ yield* tick.pipe(Effect.repeat(Schedule.spaced(TICK)), Effect.forkIn(scope));
589
+ /**
590
+ * Refuses an open the holder can't take, before anything is held: an
591
+ * unregistered actor or member, oversized params, a full holder, an expired
592
+ * credential, or a caller `authorize` denies. Expiry is checked again after
593
+ * `authorize`, which may have outlasted the credential. Answers the actor type.
594
+ */
595
+ const admit = (request) => Effect.gen(function* () {
596
+ const type = options.actorType(request.ref.actor);
597
+ if (type === undefined)
598
+ return yield* ActorError.make({
599
+ reason: ActorUnavailable.make({ cause: new Error("Actor not registered") }),
600
+ });
601
+ if (!type.hasMember(request.member))
602
+ return yield* ActorError.make({
603
+ reason: ActorUnavailable.make({ cause: new Error("Connection not declared") }),
604
+ });
605
+ if (utf8.encode(request.params).byteLength > MAX_INBOUND_BYTES)
606
+ return yield* Effect.die(new Error("Connection params exceed 64 KiB"));
607
+ if (held.size >= MAX_HELD_CONNECTIONS)
608
+ return yield* ActorError.make({
609
+ reason: ActorUnavailable.make({ cause: new Error("Holder is at its connection limit") }),
610
+ });
611
+ if (request.expiresAt !== undefined && (yield* now) >= request.expiresAt)
612
+ return yield* credentialExpired;
613
+ const allowed = yield* check(request, request.feed, "first");
614
+ if (!allowed)
615
+ return yield* ActorError.make({ reason: Unauthorized.make({ code: "access_denied" }) });
616
+ if (request.expiresAt !== undefined && (yield* now) >= request.expiresAt)
617
+ return yield* credentialExpired;
618
+ return type;
619
+ });
620
+ /** A new, not yet open connection, held on this holder and its actor. */
621
+ const hold = (request, type) => Effect.gen(function* () {
622
+ const connection = {
623
+ id: yield* crypto.randomUUIDv7.pipe(Effect.orDie),
624
+ ref: request.ref,
625
+ key: actorKey(request.ref),
626
+ member: request.member,
627
+ feed: request.feed,
628
+ caller: request.caller,
629
+ type,
630
+ outbound: yield* Queue.unbounded(),
631
+ secret: connectionSecret(yield* crypto.randomBytes(32).pipe(Effect.orDie)),
632
+ inbound: [],
633
+ wake: yield* Queue.sliding(1),
634
+ drained: yield* Queue.sliding(1),
635
+ expiresAt: request.expiresAt,
636
+ open: false,
637
+ ended: false,
638
+ outFrames: 0,
639
+ outBytes: 0,
640
+ inBytes: 0,
641
+ nextSeq: 0,
642
+ lastAuthorized: yield* now,
643
+ openedAt: 0,
644
+ checking: false,
645
+ resync: undefined,
646
+ resyncs: [],
647
+ loop: undefined,
648
+ progress: new Map(),
649
+ };
650
+ const actor = actorOf(request.ref);
651
+ actor.connections.set(connection.id, connection);
652
+ held.set(connection.id, connection);
653
+ return { actor, connection };
654
+ });
655
+ /**
656
+ * Asks the owner to open the connection, within the delivery timeout. A
657
+ * caller that stops waiting abandons the open: the connection is released
658
+ * and, should the owner still answer `Opened`, closed there again.
659
+ */
660
+ const openAtOwner = (request, connection) => Effect.gen(function* () {
661
+ const { type } = connection;
662
+ const issuedAt = (yield* now) - COMMAND_SKEW_MS;
663
+ const openCall = type.channel.open({
664
+ ...address(connection),
665
+ member: request.member,
666
+ caller: request.caller,
667
+ params: request.params,
668
+ commands: {
669
+ secret: connection.secret,
670
+ seq: 0,
671
+ issuedAt,
672
+ expiresAt: issuedAt + type.retryWindowMs,
673
+ },
674
+ });
675
+ const attempt = yield* retried(connection, openCall, (error) => isWatchMember(request.member) && Predicate.isTagged(error.reason, "RunnerAtCapacity")).pipe(Effect.forkIn(scope));
676
+ const abandon = Effect.gen(function* () {
677
+ connection.ended = true;
678
+ release(connection);
679
+ yield* deleteRow(connection);
680
+ yield* Fiber.await(attempt).pipe(Effect.flatMap((exit) => Exit.isSuccess(exit) && Predicate.isTagged(exit.value, "Opened")
681
+ ? retrying(connection, type.channel.close({
682
+ ...address(connection),
683
+ cause: SessionEnded.make({ cause: "ActorUnavailable", resync: true }),
684
+ }), type.deliveryMs).pipe(Effect.catch(() => deleteRow(connection)))
685
+ : Effect.void), Effect.forkIn(scope));
686
+ });
687
+ const answer = yield* Fiber.join(attempt).pipe(Effect.timeoutOrElse({
688
+ duration: type.deliveryMs,
689
+ orElse: () => Effect.fail(ended("ActorUnavailable", true)),
690
+ }), Effect.onError(() => abandon));
691
+ if (Predicate.isTagged(answer, "Failed")) {
692
+ release(connection);
693
+ return yield* OpenRejected.make({ value: answer.value });
694
+ }
695
+ return answer;
696
+ });
697
+ /**
698
+ * Marks an opened connection live under the owner that answered: its
699
+ * inbound loop starts, and a connection the owner recovered resyncs from
700
+ * its baseline first.
701
+ */
702
+ const start = (actor, connection, answer) => Effect.gen(function* () {
703
+ yield* observe(actor, answer);
704
+ if (BigInt(answer.baseline) > BigInt(actor.through))
705
+ actor.through = answer.baseline;
706
+ if (connection.ended)
707
+ return;
708
+ connection.openedAt = yield* now;
709
+ connection.open = true;
710
+ if (answer.recovered === true)
711
+ yield* resync(actor, connection, yield* now, answer.baseline);
712
+ connection.loop = yield* inboundLoop(connection).pipe(Effect.forkIn(scope));
713
+ });
714
+ /** The client's messages: frames as they are taken, and progress still current. */
715
+ const clientMessages = (connection) => Stream.fromQueue(connection.outbound).pipe(Stream.mapEffect((message) => ClientMessage.guards.Progress(message)
716
+ ? takenProgress(connection, message)
717
+ : Effect.as(taken(connection, message), Option.some(message))), Stream.filter(Option.isSome), Stream.map((message) => message.value));
718
+ /** Queues one client frame for the inbound loop; a client over the held limits is slow. */
719
+ const receive = (connection, frame) => Effect.gen(function* () {
720
+ if (connection.ended)
721
+ return yield* ended("ClientClosed", false);
722
+ const bytes = utf8.encode(frame).byteLength;
723
+ if (bytes > MAX_INBOUND_BYTES)
724
+ return yield* Effect.die(new Error("Connection frame exceeds 64 KiB"));
725
+ if (heldBytes + bytes > MAX_HELD_BYTES || connection.inbound.length >= MAX_INBOUND_FRAMES)
726
+ return yield* end(connection, ended("SlowConsumer", true), true);
727
+ connection.inbound.push({ frame, issuedAt: (yield* now) - COMMAND_SKEW_MS });
728
+ connection.inBytes += bytes;
729
+ heldBytes += bytes;
730
+ yield* Queue.offer(connection.wake, undefined);
731
+ });
732
+ /**
733
+ * Ends a resync once the owner answered it and, for a member with a resync
734
+ * handler, replayed it: the messages deferred meanwhile go out, less the
735
+ * events the replay already carried.
736
+ */
737
+ const finishResync = (connection) => Effect.gen(function* () {
738
+ const pending = connection.resync;
739
+ if (pending === undefined ||
740
+ !pending.answered ||
741
+ (connection.type.hasResync(connection.member) && !pending.replayed))
742
+ return;
743
+ connection.resync = undefined;
744
+ heldBytes -= pending.deferredBytes;
745
+ pending.deferredBytes = 0;
746
+ for (const message of pending.deferred)
747
+ if (!ClientMessage.guards.Frame(message) ||
748
+ message.event === undefined ||
749
+ !pending.replayedEvents.has(message.event))
750
+ yield* push(connection, message, false);
751
+ yield* Queue.offer(connection.wake, undefined);
752
+ });
753
+ /**
754
+ * Renews a connection's authorization; any refusal ends the session. The
755
+ * answer must come back before the current authorization lapses, and within
756
+ * the new credential's expiry.
757
+ */
758
+ const reauthenticate = (connection, expiresAt) => Effect.gen(function* () {
759
+ const fail = (error) => Effect.andThen(end(connection, error, true), Effect.fail(error));
760
+ if (connection.ended)
761
+ return yield* ended("ClientClosed", false);
762
+ const at = yield* now;
763
+ if (expiresAt !== undefined && at >= expiresAt)
764
+ return yield* fail(credentialExpired);
765
+ const allowed = yield* check(connection, connection.feed, "reauthorize");
766
+ if (connection.ended)
767
+ return yield* ended("ClientClosed", false);
768
+ const answered = yield* now;
769
+ if (answered >= authorizedUntil(connection))
770
+ return yield* fail(lapsed(connection, answered));
771
+ if (!allowed)
772
+ return yield* fail(ActorError.make({ reason: Unauthorized.make({ code: "access_denied" }) }));
773
+ if (expiresAt !== undefined && answered >= expiresAt)
774
+ return yield* fail(credentialExpired);
775
+ connection.lastAuthorized = at;
776
+ connection.expiresAt = expiresAt;
777
+ });
778
+ /** Ends a connection its client closed, and closes it at the owner. */
779
+ const closeByClient = (connection) => Effect.gen(function* () {
780
+ if (connection.ended)
781
+ return;
782
+ const cause = SessionEnded.make({ cause: "ClientClosed", resync: false });
783
+ yield* end(connection, ActorError.make({ reason: cause }), false);
784
+ yield* retrying(connection, connection.type.channel.close({ ...address(connection), cause }), connection.type.deliveryMs).pipe(Effect.catch(() => deleteRow(connection)));
785
+ });
786
+ const open = Effect.fnUntraced(function* (request) {
787
+ const type = yield* admit(request);
788
+ const { actor, connection } = yield* hold(request, type);
789
+ const answer = yield* openAtOwner(request, connection);
790
+ yield* start(actor, connection, answer);
791
+ return {
792
+ connectionId: connection.id,
793
+ cursor: answer.baseline,
794
+ messages: clientMessages(connection),
795
+ send: (frame) => receive(connection, frame),
796
+ resyncDone: finishResync(connection),
797
+ authorized: Effect.map(now, (at) => !connection.ended && at < authorizedUntil(connection)),
798
+ writable: Effect.gen(function* () {
799
+ while (!connection.ended && connection.inbound.length >= MAX_INFLIGHT_FRAMES)
800
+ yield* Queue.take(connection.drained);
801
+ }),
802
+ reauthenticate: (expiresAt) => reauthenticate(connection, expiresAt),
803
+ close: closeByClient(connection),
804
+ };
805
+ });
806
+ yield* Effect.addFinalizer(() => Effect.forEach([...held.values()], (connection) => end(connection, ended("HolderShutdown", true), true), {
807
+ discard: true,
808
+ }));
809
+ return {
810
+ open,
811
+ deliver,
812
+ size: () => held.size,
813
+ /** The clock authorization and credential expiry are measured on, in epoch milliseconds. */
814
+ now,
815
+ };
816
+ });