@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,192 @@
1
+ import { Effect } from "effect";
2
+ import { SqlClient } from "effect/sql";
3
+ import type { EmittedEvent } from "../members.ts";
4
+ /**
5
+ * The statement that appends a turn's events inside its transaction, and the
6
+ * stamp it records once it replies. The caller already holds the actor's
7
+ * generation row lock, so reserving the next sequence numbers there gives one
8
+ * gap-free order per actor even when activations race; the counter lives on
9
+ * the generation row so pruning never lets a sequence be reused. The
10
+ * reservation and the insert share a statement, so nothing waits on the
11
+ * reserved numbers.
12
+ *
13
+ * The same statement probes the actor's subscription tag summary by key and,
14
+ * when some subscription follows an emitted class, upserts the actor's one
15
+ * feed row, due now. So the turn costs the same with no subscribers or ten
16
+ * thousand, and the relay fans the events out after commit; the stamp's `fed`
17
+ * says the relay should wake. The upsert resets `attempts`, so a relay
18
+ * expanding the feed while this commits keeps it due. Routed subscriptions
19
+ * registered here that name an emitted class get their missing source-side
20
+ * rows first, starting at this turn's first event. Those rows are widened,
21
+ * never narrowed, so an older runner cannot shrink one back, and their tag
22
+ * summary moves in the same statement by the tags the upsert added. The
23
+ * statement locks the routed rows it reads and builds each upserted row from
24
+ * the locked version, so the lock precedes the write whatever the plan: a
25
+ * settle that widened a row, or a cleanup that deleted one, after this
26
+ * statement's snapshot is read as committed, never counted twice or lost.
27
+ */
28
+ export declare const eventsStatement: (request: {
29
+ readonly ref: {
30
+ readonly tenant: string;
31
+ readonly actor: string;
32
+ readonly id: string;
33
+ };
34
+ readonly caller: {
35
+ readonly _tag: "Anonymous";
36
+ } | {
37
+ readonly _tag: "System";
38
+ readonly source: "actor" | "cron" | "job" | "process" | "subscription" | "timer" | "workflow";
39
+ readonly ref?: {
40
+ readonly tenant: string;
41
+ readonly actor: string;
42
+ readonly id: string;
43
+ } | undefined;
44
+ readonly onBehalfOf?: {
45
+ readonly subject: string;
46
+ } | undefined;
47
+ readonly mint?: {
48
+ readonly commandId: string;
49
+ readonly ordinal: number;
50
+ } | undefined;
51
+ } | {
52
+ readonly _tag: "User";
53
+ readonly subject: string;
54
+ };
55
+ readonly command: string;
56
+ readonly commandId: string;
57
+ readonly payload: string;
58
+ readonly external?: boolean | undefined;
59
+ readonly clockOffset?: number | undefined;
60
+ readonly redelivered?: boolean | undefined;
61
+ readonly intent?: {
62
+ readonly tenant: string;
63
+ readonly actor: string;
64
+ readonly id: string;
65
+ } | undefined;
66
+ readonly delivery?: {
67
+ readonly subscription: string;
68
+ readonly sourceType: string;
69
+ readonly sourceId: string;
70
+ readonly epoch: string;
71
+ readonly kind: "event" | "gap" | "rejected";
72
+ readonly position: string;
73
+ } | undefined;
74
+ readonly queuedAtMs?: number | undefined;
75
+ readonly usageToken?: string | undefined;
76
+ }, routingKey: bigint, events: readonly EmittedEvent[]) => Effect.Effect<{
77
+ statement: Effect.Effect<void, import("effect/sql/SqlError").SqlError, never>;
78
+ stamp: {
79
+ emittedAtMs: number;
80
+ fed: boolean;
81
+ };
82
+ }, never, SqlClient.SqlClient>;
83
+ /**
84
+ * Re-arms the timers of this actor's workflows that wait for one of the
85
+ * emitted classes; the result says whether the relay should wake.
86
+ */
87
+ export declare const notifyEvents: (request: {
88
+ readonly ref: {
89
+ readonly tenant: string;
90
+ readonly actor: string;
91
+ readonly id: string;
92
+ };
93
+ readonly caller: {
94
+ readonly _tag: "Anonymous";
95
+ } | {
96
+ readonly _tag: "System";
97
+ readonly source: "actor" | "cron" | "job" | "process" | "subscription" | "timer" | "workflow";
98
+ readonly ref?: {
99
+ readonly tenant: string;
100
+ readonly actor: string;
101
+ readonly id: string;
102
+ } | undefined;
103
+ readonly onBehalfOf?: {
104
+ readonly subject: string;
105
+ } | undefined;
106
+ readonly mint?: {
107
+ readonly commandId: string;
108
+ readonly ordinal: number;
109
+ } | undefined;
110
+ } | {
111
+ readonly _tag: "User";
112
+ readonly subject: string;
113
+ };
114
+ readonly command: string;
115
+ readonly commandId: string;
116
+ readonly payload: string;
117
+ readonly external?: boolean | undefined;
118
+ readonly clockOffset?: number | undefined;
119
+ readonly redelivered?: boolean | undefined;
120
+ readonly intent?: {
121
+ readonly tenant: string;
122
+ readonly actor: string;
123
+ readonly id: string;
124
+ } | undefined;
125
+ readonly delivery?: {
126
+ readonly subscription: string;
127
+ readonly sourceType: string;
128
+ readonly sourceId: string;
129
+ readonly epoch: string;
130
+ readonly kind: "event" | "gap" | "rejected";
131
+ readonly position: string;
132
+ } | undefined;
133
+ readonly queuedAtMs?: number | undefined;
134
+ readonly usageToken?: string | undefined;
135
+ }, routingKey: bigint, events: readonly EmittedEvent[], waited: ReadonlySet<string>) => Effect.Effect<boolean, import("effect/sql/SqlError").SqlError, import("effect/Crypto").Crypto | SqlClient.SqlClient>;
136
+ /**
137
+ * Appends a turn's events and notifies their waiting workflows, one statement
138
+ * at a time; the result says whether the relay should wake, and when the
139
+ * events were stamped.
140
+ */
141
+ export declare const appendEvents: (request: {
142
+ readonly ref: {
143
+ readonly tenant: string;
144
+ readonly actor: string;
145
+ readonly id: string;
146
+ };
147
+ readonly caller: {
148
+ readonly _tag: "Anonymous";
149
+ } | {
150
+ readonly _tag: "System";
151
+ readonly source: "actor" | "cron" | "job" | "process" | "subscription" | "timer" | "workflow";
152
+ readonly ref?: {
153
+ readonly tenant: string;
154
+ readonly actor: string;
155
+ readonly id: string;
156
+ } | undefined;
157
+ readonly onBehalfOf?: {
158
+ readonly subject: string;
159
+ } | undefined;
160
+ readonly mint?: {
161
+ readonly commandId: string;
162
+ readonly ordinal: number;
163
+ } | undefined;
164
+ } | {
165
+ readonly _tag: "User";
166
+ readonly subject: string;
167
+ };
168
+ readonly command: string;
169
+ readonly commandId: string;
170
+ readonly payload: string;
171
+ readonly external?: boolean | undefined;
172
+ readonly clockOffset?: number | undefined;
173
+ readonly redelivered?: boolean | undefined;
174
+ readonly intent?: {
175
+ readonly tenant: string;
176
+ readonly actor: string;
177
+ readonly id: string;
178
+ } | undefined;
179
+ readonly delivery?: {
180
+ readonly subscription: string;
181
+ readonly sourceType: string;
182
+ readonly sourceId: string;
183
+ readonly epoch: string;
184
+ readonly kind: "event" | "gap" | "rejected";
185
+ readonly position: string;
186
+ } | undefined;
187
+ readonly queuedAtMs?: number | undefined;
188
+ readonly usageToken?: string | undefined;
189
+ }, routingKey: bigint, events: readonly EmittedEvent[], waited?: ReadonlySet<string> | undefined) => Effect.Effect<{
190
+ notified: boolean;
191
+ emittedAtMs: number;
192
+ }, import("effect/sql/SqlError").SqlError, import("effect/Crypto").Crypto | SqlClient.SqlClient>;
@@ -0,0 +1,128 @@
1
+ import { Effect, Schema } from "effect";
2
+ import { SqlClient } from "effect/sql";
3
+ import { System } from "../../identity/caller.js";
4
+ import { FrameworkClock } from "../turn/admission.js";
5
+ import { bucketOf, CallerJson, OutboxRuntime, textArray } from "../turn/outbox.js";
6
+ import { compress } from "../storage/codec.js";
7
+ import { notifyWaits } from "../workflows/engine.js";
8
+ import { summarize } from "../subscriptions/storage.js";
9
+ /** The outbox key of an actor's feed row, which tells the relay to expand its subscriptions. */
10
+ const FEED_KEY = "$feed";
11
+ /**
12
+ * The statement that appends a turn's events inside its transaction, and the
13
+ * stamp it records once it replies. The caller already holds the actor's
14
+ * generation row lock, so reserving the next sequence numbers there gives one
15
+ * gap-free order per actor even when activations race; the counter lives on
16
+ * the generation row so pruning never lets a sequence be reused. The
17
+ * reservation and the insert share a statement, so nothing waits on the
18
+ * reserved numbers.
19
+ *
20
+ * The same statement probes the actor's subscription tag summary by key and,
21
+ * when some subscription follows an emitted class, upserts the actor's one
22
+ * feed row, due now. So the turn costs the same with no subscribers or ten
23
+ * thousand, and the relay fans the events out after commit; the stamp's `fed`
24
+ * says the relay should wake. The upsert resets `attempts`, so a relay
25
+ * expanding the feed while this commits keeps it due. Routed subscriptions
26
+ * registered here that name an emitted class get their missing source-side
27
+ * rows first, starting at this turn's first event. Those rows are widened,
28
+ * never narrowed, so an older runner cannot shrink one back, and their tag
29
+ * summary moves in the same statement by the tags the upsert added. The
30
+ * statement locks the routed rows it reads and builds each upserted row from
31
+ * the locked version, so the lock precedes the write whatever the plan: a
32
+ * settle that widened a row, or a cleanup that deleted one, after this
33
+ * statement's snapshot is read as committed, never counted twice or lost.
34
+ */
35
+ export const eventsStatement = Effect.fnUntraced(function* (request, routingKey, events) {
36
+ const sql = yield* SqlClient.SqlClient;
37
+ const clock = yield* FrameworkClock;
38
+ const outbox = yield* OutboxRuntime;
39
+ const { tenant, actor, id } = request.ref;
40
+ const stamp = { emittedAtMs: 0, fed: false };
41
+ const emitted = [...new Set(events.map((event) => event.tag))];
42
+ const routed = outbox
43
+ .routed(actor)
44
+ .filter((sub) => sub.events.some((tag) => emitted.includes(tag)));
45
+ const values = sql.csv(events.map((event, index) => sql `(${index + 1}::bigint, ${event.tag}::text, ${compress(event.value)}::bytea, ${event.version}::int)`));
46
+ const source = (alias) => sql `${sql(alias)}.routing_key = ${routingKey} AND ${sql(alias)}.tenant_id = ${tenant}
47
+ AND ${sql(alias)}.source_type = ${actor} AND ${sql(alias)}.source_id = ${id}`;
48
+ const caller = yield* Schema.encodeEffect(CallerJson)(System.make({ source: "actor", ref: request.ref })).pipe(Effect.orDie);
49
+ const routedRows = routed.length === 0
50
+ ? sql.literal("")
51
+ : sql `, routed_want (subscriber_type, subscription, events) AS (
52
+ VALUES ${sql.csv(routed.map((sub) => sql `(${sub.subscriberType}::text, ${sub.tag}::text, ${textArray({ sql, values: sub.events })})`))}),
53
+ routed_old AS MATERIALIZED (
54
+ SELECT s.subscriber_type, s.subscription, s.events FROM actor_subscriptions s
55
+ JOIN routed_want w USING (subscriber_type, subscription)
56
+ WHERE ${source("s")} AND s.subscriber_id = ''
57
+ FOR UPDATE OF s),
58
+ routed_new AS (
59
+ INSERT INTO actor_subscriptions (routing_key, tenant_id, source_type, source_id,
60
+ subscriber_type, subscription, subscriber_id, events, epoch, active, delivered, bucket)
61
+ SELECT ${routingKey}, ${tenant}, ${actor}, ${id}, w.subscriber_type, w.subscription, '',
62
+ CASE WHEN o.events IS NULL THEN w.events
63
+ ELSE ARRAY(SELECT DISTINCT e FROM unnest(o.events || w.events) AS u(e) ORDER BY e) END,
64
+ 0, true, reserved.base, ${bucketOf(routingKey)}
65
+ FROM routed_want w LEFT JOIN routed_old o USING (subscriber_type, subscription), reserved
66
+ ON CONFLICT (routing_key, tenant_id, source_type, source_id, subscriber_type, subscription, subscriber_id)
67
+ DO UPDATE SET events = EXCLUDED.events
68
+ WHERE NOT actor_subscriptions.events @> EXCLUDED.events
69
+ RETURNING subscriber_type, subscription, events),
70
+ routed_changed AS (
71
+ SELECT ${routingKey}::bigint AS routing_key, ${tenant}::text AS tenant_id,
72
+ ${actor}::text AS source_type, ${id}::text AS source_id,
73
+ coalesce(o.events, '{}'::text[]) AS was, n.events AS now
74
+ FROM routed_new n LEFT JOIN routed_old o USING (subscriber_type, subscription)),
75
+ ${summarize({ sql, changed: "routed_changed" })}`;
76
+ const statement = Effect.map(sql `WITH reserved AS (
77
+ UPDATE actor_generations SET event_sequence = event_sequence + ${events.length}
78
+ WHERE routing_key = ${routingKey} AND tenant_id = ${tenant} AND actor_type = ${actor} AND actor_id = ${id}
79
+ RETURNING event_sequence - ${events.length} AS base,
80
+ floor(extract(epoch FROM clock_timestamp()) * 1000)::bigint + ${clock.offsetMillis()} AS now
81
+ ),
82
+ appended AS (
83
+ INSERT INTO actor_events (routing_key, tenant_id, actor_type, actor_id, sequence, event, command_id, value, emitted_at_ms, payload_version)
84
+ SELECT ${routingKey}, ${tenant}, ${actor}, ${id}, reserved.base + staged.ordinal, staged.event,
85
+ ${request.commandId}, staged.value, reserved.now, staged.version
86
+ FROM reserved, (VALUES ${values}) AS staged (ordinal, event, value, version)
87
+ RETURNING 1)
88
+ ${routedRows},
89
+ feed AS (
90
+ INSERT INTO actor_outbox (routing_key, intent_id, kind, bucket, due_at_ms, scheduled_at_ms,
91
+ tenant_id, actor_type, actor_id, timer_key, target_type, target_id, command, payload, caller)
92
+ SELECT ${routingKey}, gen_random_uuid()::text, 'feed', ${bucketOf(routingKey)}, reserved.now,
93
+ reserved.now, ${tenant}, ${actor}, ${id}, ${FEED_KEY}, ${actor}, ${id}, ${FEED_KEY}, '', ${caller}
94
+ FROM reserved
95
+ WHERE EXISTS (SELECT 1 FROM actor_subscription_tags t
96
+ WHERE ${source("t")} AND t.event IN ${sql.in(emitted)})
97
+ ${routed.length === 0 ? sql.literal("") : sql.literal("OR EXISTS (SELECT 1 FROM routed_new)")}
98
+ ON CONFLICT (routing_key, tenant_id, actor_type, actor_id, timer_key) WHERE timer_key IS NOT NULL
99
+ DO UPDATE SET due_at_ms = least(actor_outbox.due_at_ms, EXCLUDED.due_at_ms), attempts = 0
100
+ RETURNING 1)
101
+ SELECT reserved.now::text AS emitted_at_ms, (SELECT count(*) FROM feed)::int AS fed
102
+ FROM reserved`, (rows) => {
103
+ stamp.emittedAtMs = Number(rows[0].emitted_at_ms);
104
+ stamp.fed = rows[0].fed > 0;
105
+ });
106
+ return { statement, stamp };
107
+ });
108
+ /**
109
+ * Re-arms the timers of this actor's workflows that wait for one of the
110
+ * emitted classes; the result says whether the relay should wake.
111
+ */
112
+ export const notifyEvents = Effect.fnUntraced(function* (request, routingKey, events, waited) {
113
+ const tags = [...new Set(events.map((event) => event.tag))].filter((tag) => waited.has(tag));
114
+ return tags.length === 0 ? false : yield* notifyWaits(routingKey, request.ref, tags);
115
+ });
116
+ /**
117
+ * Appends a turn's events and notifies their waiting workflows, one statement
118
+ * at a time; the result says whether the relay should wake, and when the
119
+ * events were stamped.
120
+ */
121
+ export const appendEvents = Effect.fnUntraced(function* (request, routingKey, events, waited = new Set()) {
122
+ if (events.length === 0)
123
+ return { notified: false, emittedAtMs: 0 };
124
+ const { statement, stamp } = yield* eventsStatement(request, routingKey, events);
125
+ yield* statement;
126
+ const notified = yield* notifyEvents(request, routingKey, events, waited);
127
+ return { notified: notified || stamp.fed, emittedAtMs: stamp.emittedAtMs };
128
+ });
@@ -0,0 +1,2 @@
1
+ /** True for a canonical cursor a stream could have issued. */
2
+ export declare const isCursor: (cursor: string) => boolean;
@@ -0,0 +1,5 @@
1
+ /** A cursor is an event sequence: a non-negative 64-bit integer in canonical decimal. */
2
+ const CURSOR = /^(0|[1-9][0-9]{0,18})$/;
3
+ const MAX_SEQUENCE = 2n ** 63n - 1n;
4
+ /** True for a canonical cursor a stream could have issued. */
5
+ export const isCursor = (cursor) => CURSOR.test(cursor) && BigInt(cursor) <= MAX_SEQUENCE;
@@ -0,0 +1,20 @@
1
+ import { Effect } from "effect";
2
+ import { SqlClient } from "effect/sql";
3
+ import { RetentionGap, UnknownCursor } from "../../errors/events.ts";
4
+ import type { StoredEvent } from "../members.ts";
5
+ /**
6
+ * Replays committed events of the given tags after an exclusive cursor, up to `head`,
7
+ * the last sequence committed when the query read state. Every event up to
8
+ * `head` had committed by then, so a later read sees each of them unless it
9
+ * was pruned; the oldest retained event and the matching rows come from one
10
+ * statement, and because pruning only removes a prefix, an oldest event past
11
+ * the cursor's successor means history is missing. A page stops after
12
+ * `limit` matching events.
13
+ */
14
+ export declare const replayEvents: (ref: {
15
+ readonly tenant: string;
16
+ readonly actor: string;
17
+ readonly id: string;
18
+ }, routingKey: bigint, tags: readonly string[], after: string | undefined, head: bigint, limit: number) => Effect.Effect<(StoredEvent & {
19
+ readonly tag: string;
20
+ })[], RetentionGap | import("effect/sql/SqlError").SqlError | UnknownCursor, SqlClient.SqlClient>;
@@ -0,0 +1,45 @@
1
+ import { Effect } from "effect";
2
+ import { SqlClient } from "effect/sql";
3
+ import { RetentionGap, UnknownCursor } from "../../errors/events.js";
4
+ import { decompress } from "../storage/codec.js";
5
+ import { isCursor } from "./cursor.js";
6
+ /**
7
+ * Replays committed events of the given tags after an exclusive cursor, up to `head`,
8
+ * the last sequence committed when the query read state. Every event up to
9
+ * `head` had committed by then, so a later read sees each of them unless it
10
+ * was pruned; the oldest retained event and the matching rows come from one
11
+ * statement, and because pruning only removes a prefix, an oldest event past
12
+ * the cursor's successor means history is missing. A page stops after
13
+ * `limit` matching events.
14
+ */
15
+ export const replayEvents = Effect.fnUntraced(function* (ref, routingKey, tags, after, head, limit) {
16
+ const cursor = after ?? "0";
17
+ if (!isCursor(cursor) || BigInt(cursor) > head)
18
+ return yield* UnknownCursor.make({ cursor });
19
+ const position = BigInt(cursor);
20
+ const sql = yield* SqlClient.SqlClient;
21
+ const owner = (alias) => sql `${sql(alias)}.routing_key = ${routingKey} AND ${sql(alias)}.tenant_id = ${ref.tenant}
22
+ AND ${sql(alias)}.actor_type = ${ref.actor} AND ${sql(alias)}.actor_id = ${ref.id}`;
23
+ const rows = yield* sql `
24
+ SELECT (SELECT min(o.sequence)::text FROM actor_events o WHERE ${owner("o")}) AS oldest,
25
+ e.sequence::text AS sequence, e.event, e.command_id, e.value, e.payload_version,
26
+ e.emitted_at_ms::text AS emitted_at_ms
27
+ FROM (VALUES (1)) AS one (x)
28
+ LEFT JOIN actor_events e ON ${owner("e")} AND e.sequence > ${position}
29
+ AND e.sequence <= ${head} AND e.event IN ${sql.in(tags)}
30
+ ORDER BY e.sequence
31
+ LIMIT ${limit}`;
32
+ const oldest = rows[0]?.oldest;
33
+ if (position < head && (oldest == null || BigInt(oldest) > position + 1n))
34
+ return yield* RetentionGap.make({ cursor });
35
+ return rows
36
+ .filter((row) => row.sequence !== null)
37
+ .map((row) => ({
38
+ cursor: row.sequence,
39
+ tag: row.event,
40
+ commandId: row.command_id,
41
+ value: decompress(row.value),
42
+ version: row.payload_version,
43
+ timestampMs: Number(row.emitted_at_ms),
44
+ }));
45
+ });
@@ -0,0 +1,26 @@
1
+ import { Context, Crypto, Effect } from "effect";
2
+ import { Sharding } from "effect/cluster";
3
+ import { SqlClient } from "effect/sql";
4
+ import { ActorError } from "../errors/actor.ts";
5
+ import type { InternalActors } from "./actors.ts";
6
+ import type { Registration } from "./members.ts";
7
+ import type { Request } from "./request.ts";
8
+ import type { ActorRef } from "../identity/caller.ts";
9
+ import type { Transport } from "./connections/transport.ts";
10
+ import type { FrameworkClock } from "./turn/admission.ts";
11
+ /**
12
+ * The runtime's feeds to one subscriber: a page of an actor's committed
13
+ * events after a cursor, upcast to their current version, and a stream
14
+ * member's live items from the actor's connection entity. A stream whose
15
+ * owner lives on another runner is pinged and ends with `SessionEnded` once
16
+ * that owner is gone.
17
+ */
18
+ export declare const eventFeeds: ({ registrations, services, allow, sharding, entityId, frameworkClock, transport, }: {
19
+ readonly registrations: ReadonlyMap<string, Registration>;
20
+ readonly services: Context.Context<SqlClient.SqlClient | Crypto.Crypto | Sharding.Sharding>;
21
+ readonly allow: (request: Request, kind?: "command" | "query" | "stream") => Effect.Effect<void, ActorError>;
22
+ readonly sharding: Sharding.Sharding["Service"];
23
+ readonly entityId: (ref: ActorRef) => Effect.Effect<string>;
24
+ readonly frameworkClock: (typeof FrameworkClock)["Service"];
25
+ readonly transport: Transport;
26
+ }) => Pick<InternalActors["Service"], "readFeed" | "subscribe">;
@@ -0,0 +1,100 @@
1
+ import { Cause, Clock, Context, Crypto, Deferred, Effect, Option, Schedule, Schema, Stream, } from "effect";
2
+ import { Sharding } from "effect/cluster";
3
+ import { SqlClient, SqlError } from "effect/sql";
4
+ import { ActorError, ActorUnavailable, NotCreated, SessionEnded } from "../errors/actor.js";
5
+ import { StreamFailed, StreamItem } from "./connections/protocol.js";
6
+ import { connectionEntity } from "./entity/register.js";
7
+ import { withTenant } from "./database/tenancy.js";
8
+ import { replayEvents } from "./events/replay.js";
9
+ import { routingKey } from "./storage/codec.js";
10
+ /** How often a subscriber checks that a stream's owner on another runner is alive. */
11
+ const OWNER_CHECK_INTERVAL = "1 second";
12
+ const activationEnded = () => ActorError.make({ reason: SessionEnded.make({ cause: "ActivationEnded", resync: false }) });
13
+ /**
14
+ * The runtime's feeds to one subscriber: a page of an actor's committed
15
+ * events after a cursor, upcast to their current version, and a stream
16
+ * member's live items from the actor's connection entity. A stream whose
17
+ * owner lives on another runner is pinged and ends with `SessionEnded` once
18
+ * that owner is gone.
19
+ */
20
+ export const eventFeeds = ({ registrations, services, allow, sharding, entityId, frameworkClock, transport, }) => ({
21
+ readFeed: Effect.fnUntraced(function* (ref, tags, after, limit) {
22
+ const registration = registrations.get(ref.actor);
23
+ if (registration === undefined)
24
+ return yield* ActorError.make({
25
+ reason: ActorUnavailable.make({ cause: new Error("Actor not registered") }),
26
+ });
27
+ const key = routingKey({ ref, placement: registration.placement });
28
+ const sql = yield* SqlClient.SqlClient;
29
+ const events = yield* Effect.gen(function* () {
30
+ const [row] = yield* sql `
31
+ SELECT event_sequence::text AS head FROM actor_generations
32
+ WHERE routing_key = ${key} AND tenant_id = ${ref.tenant}
33
+ AND actor_type = ${ref.actor} AND actor_id = ${ref.id}`;
34
+ if (row === undefined)
35
+ return yield* ActorError.make({ reason: NotCreated.make({}) });
36
+ return yield* replayEvents(ref, key, tags, after, BigInt(row.head), limit);
37
+ }).pipe(withTenant(ref.tenant));
38
+ return yield* Effect.forEach(events, (event) => registration.upcastEvent(event.tag, event.version, event.value).pipe(Effect.map((value) => ({
39
+ cursor: event.cursor,
40
+ tag: event.tag,
41
+ commandId: event.commandId,
42
+ value,
43
+ timestampMs: event.timestampMs,
44
+ }))));
45
+ }, Effect.provideContext(services), Effect.catchIf(SqlError.isSqlError, (cause) => Effect.fail(ActorError.make({ reason: ActorUnavailable.make({ cause }) })))),
46
+ subscribe: (request) => Stream.unwrap(Effect.gen(function* () {
47
+ const registration = registrations.get(request.ref.actor);
48
+ if (registration === undefined || !registration.streams.has(request.command))
49
+ return yield* ActorError.make({
50
+ reason: ActorUnavailable.make({ cause: new Error("Stream not registered") }),
51
+ });
52
+ yield* allow(request, "stream");
53
+ const client = (yield* sharding.makeClient(connectionEntity(request.ref.actor)))(yield* entityId(request.ref));
54
+ const authorizedUntil = (yield* Clock.currentTimeMillis) +
55
+ frameworkClock.offsetMillis() +
56
+ registration.policy.reauthorizeMs;
57
+ const started = yield* Deferred.make();
58
+ const lost = yield* Deferred.make();
59
+ let owner;
60
+ yield* Deferred.await(started).pipe(Effect.flatMap(({ owner, ownerEpoch }) => owner === transport.holder
61
+ ? Effect.never
62
+ : transport.ping(owner, ownerEpoch).pipe(Effect.repeat({
63
+ schedule: Schedule.spaced(OWNER_CHECK_INTERVAL),
64
+ while: (alive) => alive,
65
+ }), Effect.andThen(Deferred.fail(lost, activationEnded())))), Effect.forkScoped);
66
+ let finished = false;
67
+ return client
68
+ .Subscribe({
69
+ member: request.command,
70
+ caller: request.caller,
71
+ input: request.payload,
72
+ authorizedUntil,
73
+ })
74
+ .pipe(Stream.tap((item) => Effect.gen(function* () {
75
+ if (StreamItem.guards.Done(item))
76
+ finished = true;
77
+ if (!StreamItem.guards.Started(item))
78
+ return;
79
+ if (owner !== undefined)
80
+ return yield* activationEnded();
81
+ owner = item;
82
+ yield* Deferred.succeed(started, item);
83
+ })), Stream.takeWhile((item) => !StreamItem.guards.Done(item)), Stream.filter(StreamItem.guards.Element), Stream.map((item) => item.value), Stream.concat(Stream.fromEffect(Effect.suspend(() => (finished ? Effect.void : activationEnded()))).pipe(Stream.drain)), Stream.interruptWhen(Deferred.await(lost)), Stream.catchCause((cause) => {
84
+ const failure = Cause.findErrorOption(cause);
85
+ if (Option.isSome(failure)) {
86
+ if (Schema.is(ActorError)(failure.value))
87
+ return Stream.fail(failure.value);
88
+ if (Schema.is(StreamFailed)(failure.value))
89
+ return Stream.fail({ failure: failure.value.value });
90
+ }
91
+ if (Cause.hasInterruptsOnly(cause))
92
+ return Stream.fromEffect(Effect.interrupt);
93
+ return Stream.fail(owner === undefined
94
+ ? ActorError.make({
95
+ reason: ActorUnavailable.make({ cause: Cause.squash(cause) }),
96
+ })
97
+ : activationEnded());
98
+ }));
99
+ }).pipe(Effect.provideContext(services))),
100
+ });
@@ -0,0 +1,17 @@
1
+ import { Effect } from "effect";
2
+ import { SqlClient } from "effect/sql";
3
+ import type { AnyFleetView } from "../../tables/fleet.ts";
4
+ import { type ResolvedView } from "./maintainer.ts";
5
+ /** Resolves each view's source and derived table schemas on this database. */
6
+ export declare const resolveViews: (views: readonly AnyFleetView[]) => Effect.Effect<ResolvedView[], import("effect/sql/SqlError").SqlError, SqlClient.SqlClient>;
7
+ /**
8
+ * Refuses to start fleet views on a database that cannot maintain them, each
9
+ * time naming the fix: `wal_level` below logical, a login without
10
+ * `REPLICATION`, a source outside the publication or without full replica
11
+ * identity, a missing or lost slot, a source whose actor type is not placed
12
+ * by tenant, a source without an index leading with
13
+ * `(routing_key, tenant_id, …group columns)`, a missing derived table, and a
14
+ * derived table the tenant role owns, which would let a turn bypass its
15
+ * policy. Then records each view, marking one whose definition changed stale.
16
+ */
17
+ export declare const checkFleet: (views: readonly AnyFleetView[], tenantRole: string | undefined) => Effect.Effect<ResolvedView[], import("effect/sql/SqlError").SqlError, SqlClient.SqlClient>;
@@ -0,0 +1,106 @@
1
+ import { Clock, Effect } from "effect";
2
+ import { SqlClient } from "effect/sql";
3
+ import { FLEET_PUBLICATION, FLEET_SLOT } from "./maintainer.js";
4
+ const refuse = (message) => Effect.die(new Error(`Fleet views cannot start: ${message}`));
5
+ const currentSchema = Effect.gen(function* () {
6
+ const sql = yield* SqlClient.SqlClient;
7
+ return (yield* sql `SELECT current_schema() AS schema`)[0].schema;
8
+ });
9
+ /** Resolves each view's source and derived table schemas on this database. */
10
+ export const resolveViews = Effect.fnUntraced(function* (views) {
11
+ const schema = yield* currentSchema;
12
+ return views.map((view) => ({
13
+ view,
14
+ sourceSchema: view.source.schema ?? schema,
15
+ derivedSchema: view.source.schema ?? schema,
16
+ }));
17
+ });
18
+ /**
19
+ * Refuses to start fleet views on a database that cannot maintain them, each
20
+ * time naming the fix: `wal_level` below logical, a login without
21
+ * `REPLICATION`, a source outside the publication or without full replica
22
+ * identity, a missing or lost slot, a source whose actor type is not placed
23
+ * by tenant, a source without an index leading with
24
+ * `(routing_key, tenant_id, …group columns)`, a missing derived table, and a
25
+ * derived table the tenant role owns, which would let a turn bypass its
26
+ * policy. Then records each view, marking one whose definition changed stale.
27
+ */
28
+ export const checkFleet = Effect.fnUntraced(function* (views, tenantRole) {
29
+ const sql = yield* SqlClient.SqlClient;
30
+ const names = views.map(({ name }) => name);
31
+ if (new Set(names).size !== names.length)
32
+ return yield* refuse(`a view name is registered twice (${names.join(", ")})`);
33
+ const [level] = yield* sql `SELECT current_setting('wal_level') AS wal_level`;
34
+ if (level?.wal_level !== "logical")
35
+ return yield* refuse(`wal_level is ${level?.wal_level}; set wal_level = logical (ALTER SYSTEM SET wal_level = logical) and restart Postgres`);
36
+ const [login] = yield* sql `
37
+ SELECT rolname AS name, rolreplication OR rolsuper AS replication FROM pg_roles
38
+ WHERE rolname = session_user`;
39
+ if (login?.replication !== true)
40
+ return yield* refuse(`login ${login?.name} lacks REPLICATION, which the slot functions need; run ALTER ROLE ${login?.name} REPLICATION`);
41
+ const resolved = yield* resolveViews(views);
42
+ for (const { view, sourceSchema, derivedSchema } of resolved) {
43
+ const source = `${sourceSchema}.${view.source.table}`;
44
+ if (view.source.owner === undefined)
45
+ return yield* refuse(`${view.name} reads ${source}, which no Actor.make lists in tables`);
46
+ if (view.source.placement !== "tenant")
47
+ return yield* refuse(`${view.name} reads ${source} of actor ${view.source.owner}, which is not placed by tenant; a fleet view needs placement: "tenant"`);
48
+ const [table] = yield* sql `
49
+ SELECT c.relreplident AS identity,
50
+ EXISTS (SELECT 1 FROM pg_publication_tables p WHERE p.pubname = ${FLEET_PUBLICATION}
51
+ AND p.schemaname = n.nspname AND p.tablename = c.relname) AS published
52
+ FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace
53
+ WHERE n.nspname = ${sourceSchema} AND c.relname = ${view.source.table}`;
54
+ if (table === undefined)
55
+ return yield* refuse(`${view.name} reads ${source}, which does not exist; apply its drizzle-kit migration`);
56
+ if (!table.published)
57
+ return yield* refuse(`${source} is not in publication ${FLEET_PUBLICATION}; run durable fleet setup`);
58
+ if (table.identity !== "f")
59
+ return yield* refuse(`${source} does not have full replica identity; run durable fleet setup (ALTER TABLE ${source} REPLICA IDENTITY FULL)`);
60
+ const leading = [view.routingColumn, view.tenantColumn, ...view.groupColumns];
61
+ const indexes = yield* sql `
62
+ SELECT array(
63
+ SELECT a.attname FROM unnest(i.indkey::int2[]) WITH ORDINALITY k(attnum, position)
64
+ JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = k.attnum
65
+ ORDER BY k.position) AS columns
66
+ FROM pg_index i JOIN pg_class c ON c.oid = i.indrelid
67
+ JOIN pg_namespace n ON n.oid = c.relnamespace
68
+ WHERE n.nspname = ${sourceSchema} AND c.relname = ${view.source.table}
69
+ AND i.indisvalid AND i.indpred IS NULL`;
70
+ if (!indexes.some(({ columns }) => leading.every((column, index) => columns[index] === column)))
71
+ return yield* refuse(`${view.name} recomputes a group with one indexed read of ${source}; create its index: CREATE INDEX ${view.source.table}_${view.tableName.split(".").at(-1)} ON ${source} (${leading.join(", ")})`);
72
+ const derived = view.tableName.split(".").at(-1);
73
+ const [owner] = yield* sql `
74
+ SELECT ${tenantRole === undefined ? sql `false` : sql `pg_has_role(${tenantRole}, c.relowner, 'MEMBER')`}
75
+ AS owned_by_tenant,
76
+ ${tenantRole === undefined ? sql `true` : sql `has_table_privilege(${tenantRole}, c.oid, 'SELECT')`}
77
+ AS readable
78
+ FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace
79
+ WHERE n.nspname = ${derivedSchema} AND c.relname = ${derived}`;
80
+ if (owner === undefined)
81
+ return yield* refuse(`the derived table ${derivedSchema}.${derived} of ${view.name} does not exist; add ${view.name}.table to the drizzle-kit schema and apply its migration`);
82
+ if (!owner.readable)
83
+ return yield* refuse(`the tenant role ${tenantRole} cannot read ${derivedSchema}.${derived}, which subscriptions read as that role; GRANT SELECT ON ${derivedSchema}.${derived} TO ${tenantRole}`);
84
+ if (owner.owned_by_tenant)
85
+ return yield* refuse(`the tenant role ${tenantRole} owns ${derivedSchema}.${derived}, so its policy would not bind it; give the table to another role`);
86
+ }
87
+ const [slot] = yield* sql `
88
+ SELECT wal_status FROM pg_replication_slots
89
+ WHERE slot_name = ${FLEET_SLOT} AND database = current_database() AND slot_type = 'logical'`;
90
+ if (slot === undefined)
91
+ return yield* refuse(`replication slot ${FLEET_SLOT} does not exist; run durable fleet setup`);
92
+ if (slot.wal_status === "lost")
93
+ return yield* refuse(`replication slot ${FLEET_SLOT} is lost; run durable fleet setup to recreate it, and every view rebuilds`);
94
+ const at = yield* Clock.currentTimeMillis;
95
+ for (const { view, sourceSchema } of resolved) {
96
+ yield* sql `INSERT INTO actor_fleet_views (view_name, source_schema, source_table, definition_hash,
97
+ status, applied_lsn, updated_at_ms, last_error)
98
+ VALUES (${view.name}, ${sourceSchema}, ${view.source.table}, ${view.definitionHash},
99
+ 'building', NULL, ${at}, NULL)
100
+ ON CONFLICT (view_name) DO UPDATE SET source_schema = EXCLUDED.source_schema,
101
+ source_table = EXCLUDED.source_table, definition_hash = EXCLUDED.definition_hash,
102
+ status = 'stale', last_error = NULL, updated_at_ms = EXCLUDED.updated_at_ms
103
+ WHERE actor_fleet_views.definition_hash <> EXCLUDED.definition_hash`;
104
+ }
105
+ return resolved;
106
+ });