@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,241 @@
1
+ import { Effect, Schema } from "effect";
2
+ import { SqlClient } from "effect/sql";
3
+ import { installObserveTriggers } from "./observe.js";
4
+ import { quotedTable } from "./plan.js";
5
+ import { AdoptionRefused, adoptionTargets, qualifiedName } from "./target.js";
6
+ /** The default window a table must have been observed and quiet for before it is enforced. */
7
+ export const DEFAULT_QUIET_MS = 7 * 86_400_000;
8
+ const WRITE_PRIVILEGES = ["INSERT", "UPDATE", "DELETE", "TRUNCATE"];
9
+ const Revoked = Schema.Array(Schema.Struct({ grantee: Schema.String, privilege: Schema.String }));
10
+ const RevokedJson = Schema.fromJsonString(Revoked);
11
+ const decodeRevoked = Schema.decodeUnknownEffect(Revoked);
12
+ const encodeRevoked = Schema.encodeEffect(RevokedJson);
13
+ const identifier = (name) => `"${name.replaceAll('"', '""')}"`;
14
+ const literal = (value) => `'${value.replaceAll("'", "''")}'`;
15
+ /** The grantees holding a write privilege on `target`, with the privilege, as the catalog records them. */
16
+ export const writeGrants = Effect.fnUntraced(function* (target) {
17
+ const sql = yield* SqlClient.SqlClient;
18
+ return yield* sql `
19
+ SELECT CASE WHEN a.grantee = 0 THEN 'PUBLIC' ELSE pg_get_userbyid(a.grantee) END AS grantee,
20
+ a.privilege_type AS privilege
21
+ FROM pg_class c
22
+ JOIN pg_namespace n ON n.oid = c.relnamespace
23
+ CROSS JOIN LATERAL aclexplode(coalesce(c.relacl, acldefault('r', c.relowner))) AS a
24
+ WHERE n.nspname = ${target.schema} AND c.relname = ${target.table}
25
+ AND a.privilege_type IN ${sql.in(WRITE_PRIVILEGES)}
26
+ ORDER BY 1, 2`;
27
+ });
28
+ /** The trigger arguments the guard is installed with, in the order `actor_adoption_guard()` reads them. */
29
+ export const guardArguments = ({ target, writerRole, allowedRoles, }) => [writerRole, allowedRoles.join(","), target.tenantColumn, target.actorColumn, target.actor];
30
+ const roleNamed = (name, flag) => {
31
+ if (name === "" || name.includes(",") || name.includes("'"))
32
+ return AdoptionRefused.make({ message: `${flag} names a role without commas or quotes` });
33
+ return undefined;
34
+ };
35
+ /**
36
+ * The reasons `target` cannot be enforced yet, each naming the fix. Reads
37
+ * only: a table is enforced when this is empty.
38
+ */
39
+ const enforcementRefusals = Effect.fnUntraced(function* (target, options) {
40
+ const sql = yield* SqlClient.SqlClient;
41
+ const name = qualifiedName(target);
42
+ const table = quotedTable(target);
43
+ const refusals = [];
44
+ const allowed = [...options.allowedRoles];
45
+ const [adoption] = yield* sql `
46
+ SELECT changed_at_ms::text FROM actor_adoptions
47
+ WHERE table_schema = ${target.schema} AND table_name = ${target.table}`;
48
+ const observedFor = options.nowMs - Number(adoption.changed_at_ms);
49
+ if (observedFor < options.quietMs)
50
+ refusals.push(`${name} has been observed for ${Math.floor(observedFor / 1000)} s, less than the ${Math.floor(options.quietMs / 1000)} s quiet window (--quiet), so its silence proves nothing yet`);
51
+ const [counts] = yield* sql.unsafe(`SELECT count(*) FILTER (WHERE routing_key IS NULL)::text AS unfilled,
52
+ count(*) FILTER (WHERE ${identifier(target.tenantColumn)} IS NULL OR ${identifier(target.actorColumn)} IS NULL
53
+ OR ${identifier(target.tenantColumn)}::text = '' OR ${identifier(target.actorColumn)}::text = '')::text AS unowned
54
+ FROM ${table}`);
55
+ if (Number(counts.unfilled) > 0)
56
+ refusals.push(`${counts.unfilled} rows of ${name} have no routing_key; run durable adopt backfill ${target.table}`);
57
+ if (Number(counts.unowned) > 0)
58
+ refusals.push(`${counts.unowned} rows of ${name} have a NULL or empty ${target.tenantColumn} or ${target.actorColumn}, so no actor owns them`);
59
+ const recent = yield* sql `
60
+ SELECT session_user_name, application_name, operation, count(*)::text AS statements
61
+ FROM actor_adoption_writes
62
+ WHERE table_schema = ${target.schema} AND table_name = ${target.table}
63
+ AND observed_at_ms >= ${options.nowMs - options.quietMs}
64
+ AND NOT in_turn AND NOT allowed AND session_user_name NOT IN ${sql.in(["", ...allowed])}
65
+ GROUP BY session_user_name, application_name, operation
66
+ ORDER BY 1, 2, 3`;
67
+ for (const writer of recent)
68
+ refusals.push(`${writer.session_user_name} (${writer.application_name === "" ? "no application_name" : writer.application_name}) wrote ${name} with ${writer.statements} ${writer.operation} statements inside the quiet window; stop it, or route it through --allow`);
69
+ const both = yield* sql `
70
+ SELECT session_user_name FROM actor_adoption_writes
71
+ WHERE table_schema = ${target.schema} AND table_name = ${target.table}
72
+ GROUP BY session_user_name HAVING bool_or(in_turn) AND bool_or(NOT in_turn)`;
73
+ for (const shared of both)
74
+ refusals.push(`${shared.session_user_name} wrote ${name} both inside and outside runtime turns; a login that can act as the runtime can take the writer role, so give the application and the runtime separate logins`);
75
+ const [role] = yield* sql `
76
+ SELECT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = ${options.writerRole}) AS exists`;
77
+ if (role.exists !== true)
78
+ refusals.push(`role ${options.writerRole} does not exist; create it and grant it the table`);
79
+ const [owner] = yield* sql `
80
+ SELECT r.rolname AS owner, r.rolname = ${options.writerRole} AS is_writer
81
+ FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace JOIN pg_roles r ON r.oid = c.relowner
82
+ WHERE n.nspname = ${target.schema} AND c.relname = ${target.table}`;
83
+ if (owner.is_writer)
84
+ refusals.push(`${name} is owned by the writer role ${options.writerRole}; an owner can disable its triggers, so give the table to a role no login is a member of`);
85
+ const actingAsOwner = yield* sql `
86
+ SELECT l.rolname AS name FROM pg_roles l
87
+ WHERE l.rolcanlogin AND NOT l.rolsuper AND l.rolname <> session_user
88
+ AND pg_has_role(l.oid, (SELECT c.relowner FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace
89
+ WHERE n.nspname = ${target.schema} AND c.relname = ${target.table}), 'USAGE')
90
+ ORDER BY 1`;
91
+ for (const login of actingAsOwner)
92
+ refusals.push(`login ${login.name} can act as ${name}'s owner ${owner.owner}, so it could disable the guard; give the table to a NOLOGIN role no login is a member of (ALTER TABLE ${table} OWNER TO …)`);
93
+ const runtimeLogins = yield* sql `
94
+ SELECT DISTINCT session_user_name FROM actor_adoption_writes
95
+ WHERE table_schema = ${target.schema} AND table_name = ${target.table} AND in_turn`;
96
+ const members = yield* sql `
97
+ SELECT l.rolname AS name FROM pg_roles l
98
+ WHERE l.rolcanlogin AND NOT l.rolsuper AND l.rolname <> session_user AND l.rolname <> ${options.writerRole}
99
+ AND EXISTS (SELECT 1 FROM pg_roles w WHERE w.rolname = ${options.writerRole}
100
+ AND pg_has_role(l.oid, w.oid, 'MEMBER'))
101
+ ORDER BY 1`;
102
+ for (const member of members)
103
+ if (!runtimeLogins.some((login) => login.session_user_name === member.name))
104
+ refusals.push(`login ${member.name} is a member of ${options.writerRole} but no runtime turn was recorded from it, so it could write the table as the runtime; revoke its membership, or let the runtime write the table once while observing`);
105
+ const cascades = yield* sql.unsafe(`SELECT con.conname AS name, con.confrelid::regclass::text AS parent,
106
+ CASE con.confdeltype WHEN 'c' THEN 'ON DELETE CASCADE' ELSE 'ON DELETE SET NULL' END AS action
107
+ FROM pg_constraint con
108
+ WHERE con.contype = 'f' AND con.conrelid = ${`${literal(quotedTable(target))}::regclass`}
109
+ AND con.confdeltype IN ('c', 'n')
110
+ ORDER BY 1`);
111
+ for (const cascade of cascades)
112
+ refusals.push(`foreign key ${cascade.name} of ${name} references ${cascade.parent} with ${cascade.action}; deleting a parent row would change this table as its owner and be rejected by the guard, so resolve it first`);
113
+ return refusals;
114
+ });
115
+ /**
116
+ * Enforces each named adopted table of `actors`, in one transaction under a
117
+ * `lock_timeout`. Nothing changes unless every check passes: the table has
118
+ * been observed for the whole quiet window, no legacy write outside `allow`
119
+ * roles fell inside it, no login wrote both in and out of turns, every row
120
+ * has its `routing_key` and owner columns, the owner is a role no login can
121
+ * act as, no other login can take the writer role, and no cascade reaches the
122
+ * table. It then revokes write privileges from every role but the writer and
123
+ * the allowed ones, adds the constraint that keeps `routing_key` and the
124
+ * mapped columns filled, and installs the guard triggers, always enabled.
125
+ */
126
+ export const enforceAdoption = Effect.fnUntraced(function* (actors, options) {
127
+ const sql = yield* SqlClient.SqlClient;
128
+ const allowedRoles = options.allowedRoles ?? [];
129
+ for (const [role, flag] of [
130
+ [options.writerRole, "--writer-role"],
131
+ ...allowedRoles.map((allowed) => [allowed, "--allow"]),
132
+ ]) {
133
+ const bad = roleNamed(role, flag);
134
+ if (bad !== undefined)
135
+ return yield* bad;
136
+ }
137
+ if (allowedRoles.includes(options.writerRole))
138
+ return yield* AdoptionRefused.make({
139
+ message: "--allow cannot name the writer role, which already passes",
140
+ });
141
+ const results = [];
142
+ for (const target of yield* adoptionTargets(actors, options.only)) {
143
+ const name = qualifiedName(target);
144
+ if (target.access === "read")
145
+ return yield* AdoptionRefused.make({
146
+ message: `${name} is adopted for reading only and has no writers to enforce against`,
147
+ });
148
+ results.push(yield* Effect.gen(function* () {
149
+ yield* sql `SELECT set_config('lock_timeout', ${`${options.lockTimeoutMs ?? 5000}ms`}, true)`;
150
+ const [adoption] = yield* sql `
151
+ SELECT actor_type, mode FROM actor_adoptions
152
+ WHERE table_schema = ${target.schema} AND table_name = ${target.table} FOR UPDATE`;
153
+ if (adoption === undefined)
154
+ return yield* AdoptionRefused.make({
155
+ message: `${name} is not observed; run durable adopt observe ${target.table} first`,
156
+ });
157
+ if (adoption.mode === "enforce")
158
+ return yield* AdoptionRefused.make({ message: `${name} is already enforced` });
159
+ const refusals = yield* enforcementRefusals(target, {
160
+ writerRole: options.writerRole,
161
+ allowedRoles,
162
+ quietMs: options.quietMs ?? DEFAULT_QUIET_MS,
163
+ nowMs: options.nowMs,
164
+ });
165
+ if (refusals.length > 0)
166
+ return yield* AdoptionRefused.make({
167
+ message: `${name} cannot be enforced:\n${refusals.map((refusal) => ` - ${refusal}`).join("\n")}`,
168
+ });
169
+ const table = quotedTable(target);
170
+ const tenant = identifier(target.tenantColumn);
171
+ const actor = identifier(target.actorColumn);
172
+ yield* sql.unsafe(`ALTER TABLE ${table} ADD CONSTRAINT actor_adoption_owner CHECK (routing_key IS NOT NULL
173
+ AND ${tenant} IS NOT NULL AND ${actor} IS NOT NULL
174
+ AND ${tenant}::text <> '' AND ${actor}::text <> '') NOT VALID`);
175
+ yield* sql.unsafe(`ALTER TABLE ${table} VALIDATE CONSTRAINT actor_adoption_owner`);
176
+ const revoked = (yield* writeGrants(target)).filter((grant) => grant.grantee !== options.writerRole && !allowedRoles.includes(grant.grantee));
177
+ for (const grant of revoked)
178
+ yield* sql.unsafe(`REVOKE ${grant.privilege} ON ${table} FROM ${grant.grantee === "PUBLIC" ? "PUBLIC" : identifier(grant.grantee)}`);
179
+ const args = guardArguments({ target, writerRole: options.writerRole, allowedRoles })
180
+ .map(literal)
181
+ .join(", ");
182
+ const schema = (yield* sql `SELECT quote_ident(current_schema()) AS name`)[0].name;
183
+ yield* sql.unsafe(`CREATE TRIGGER actor_adoption_guard BEFORE INSERT OR UPDATE OR DELETE ON ${table}
184
+ FOR EACH ROW EXECUTE FUNCTION ${schema}.actor_adoption_guard(${args})`);
185
+ yield* sql.unsafe(`ALTER TABLE ${table} ENABLE ALWAYS TRIGGER actor_adoption_guard`);
186
+ yield* sql.unsafe(`CREATE TRIGGER actor_adoption_guard_truncate BEFORE TRUNCATE ON ${table}
187
+ FOR EACH STATEMENT EXECUTE FUNCTION ${schema}.actor_adoption_guard(${args})`);
188
+ yield* sql.unsafe(`ALTER TABLE ${table} ENABLE ALWAYS TRIGGER actor_adoption_guard_truncate`);
189
+ yield* installObserveTriggers(target, [options.writerRole, ...allowedRoles]);
190
+ const recorded = yield* encodeRevoked(revoked).pipe(Effect.orDie);
191
+ yield* sql `UPDATE actor_adoptions SET mode = 'enforce', writer_role = ${options.writerRole},
192
+ allowed_roles = coalesce(string_to_array(nullif(${allowedRoles.join(",")}, ''), ','), '{}'), revoked = ${recorded}::jsonb,
193
+ changed_at_ms = floor(extract(epoch FROM clock_timestamp()) * 1000), changed_by = session_user
194
+ WHERE table_schema = ${target.schema} AND table_name = ${target.table}`;
195
+ return {
196
+ table: name,
197
+ writerRole: options.writerRole,
198
+ allowedRoles,
199
+ revoked: revoked.length,
200
+ };
201
+ }).pipe(sql.withTransaction));
202
+ }
203
+ return results;
204
+ });
205
+ /**
206
+ * Returns `only` from enforced to observed: drops the guard and the
207
+ * constraint that legacy writers, which supply no `routing_key`, would
208
+ * violate, gives back the privileges `enforce` recorded, and reinstalls the
209
+ * plain observing triggers. It never removes `routing_key` or the record.
210
+ */
211
+ export const releaseAdoption = Effect.fnUntraced(function* (actors, options) {
212
+ const sql = yield* SqlClient.SqlClient;
213
+ const released = [];
214
+ for (const target of yield* adoptionTargets(actors, options.only)) {
215
+ const name = qualifiedName(target);
216
+ yield* Effect.gen(function* () {
217
+ yield* sql `SELECT set_config('lock_timeout', ${`${options.lockTimeoutMs ?? 5000}ms`}, true)`;
218
+ const [adoption] = yield* sql `
219
+ SELECT mode, revoked FROM actor_adoptions
220
+ WHERE table_schema = ${target.schema} AND table_name = ${target.table} FOR UPDATE`;
221
+ if (adoption?.mode !== "enforce")
222
+ return yield* AdoptionRefused.make({ message: `${name} is not enforced` });
223
+ const table = quotedTable(target);
224
+ const grants = yield* decodeRevoked(adoption.revoked).pipe(Effect.orDie);
225
+ yield* sql.unsafe(`DROP TRIGGER IF EXISTS actor_adoption_guard ON ${table}`);
226
+ yield* sql.unsafe(`DROP TRIGGER IF EXISTS actor_adoption_guard_truncate ON ${table}`);
227
+ yield* sql.unsafe(`ALTER TABLE ${table} DROP CONSTRAINT IF EXISTS actor_adoption_owner`);
228
+ for (const grant of grants)
229
+ yield* sql.unsafe(`GRANT ${grant.privilege} ON ${table} TO ${grant.grantee === "PUBLIC" ? "PUBLIC" : identifier(grant.grantee)}`);
230
+ yield* installObserveTriggers(target);
231
+ yield* sql `UPDATE actor_adoptions SET mode = 'observe', writer_role = NULL,
232
+ allowed_roles = '{}', revoked = '[]',
233
+ changed_at_ms = floor(extract(epoch FROM clock_timestamp()) * 1000), changed_by = session_user
234
+ WHERE table_schema = ${target.schema} AND table_name = ${target.table}`;
235
+ }).pipe(sql.withTransaction);
236
+ released.push(name);
237
+ }
238
+ return released;
239
+ });
240
+ /** One line per enforced table. */
241
+ export const formatEnforce = (result) => `${result.table} is enforced: writer ${result.writerRole}, ${result.revoked} privileges revoked${result.allowedRoles.length === 0 ? "" : `, allowed roles ${result.allowedRoles.join(", ")}`}`;
@@ -0,0 +1,43 @@
1
+ import { Effect } from "effect";
2
+ import { SqlClient } from "effect/sql";
3
+ import { AdoptionRefused, type AdoptionTarget } from "./target.ts";
4
+ /** One legacy or runtime writer the observing trigger recorded, grouped as `observe --report` prints it. */
5
+ export interface ObservedWriter {
6
+ readonly table: string;
7
+ readonly sessionUser: string;
8
+ readonly applicationName: string;
9
+ readonly operation: string;
10
+ /** True for statements a runtime turn made; the setting that marks them is forgeable, so it classifies and never authorizes. */
11
+ readonly inTurn: boolean;
12
+ readonly allowed: boolean;
13
+ readonly statements: number;
14
+ readonly rows: number;
15
+ readonly firstSeenMs: number;
16
+ readonly lastSeenMs: number;
17
+ }
18
+ /**
19
+ * Installs the four observing triggers on `target`, replacing any this module
20
+ * installed before. `arguments` is empty while observing, and names the writer
21
+ * and allowed roles once the table is enforced, so the trigger stays quiet for
22
+ * the runtime and marks allowed roles.
23
+ */
24
+ export declare const installObserveTriggers: (target: AdoptionTarget, roles?: readonly string[] | undefined) => Effect.Effect<void, import("effect/sql/SqlError").SqlError, SqlClient.SqlClient>;
25
+ /**
26
+ * Moves each writable adopted table of `actors` into the observing state:
27
+ * adds the nullable `routing_key`, records the adoption, and installs the
28
+ * statement triggers that record every later write. Observing changes no
29
+ * outcome, and repeating it is safe. A table already enforced is refused.
30
+ */
31
+ export declare const observeAdoption: (actors: readonly WeakKey[], only?: string | undefined, lockTimeoutMs?: any) => Effect.Effect<string[], AdoptionRefused | import("effect/sql/SqlError").SqlError, SqlClient.SqlClient>;
32
+ /**
33
+ * The writers recorded for the adopted tables of `actors` since `sinceMs`,
34
+ * grouped by table, login, application, and operation, with the runtime's own
35
+ * turns kept apart. `clear` deletes exactly the rows it reports.
36
+ */
37
+ export declare const adoptionWriters: (actors: readonly WeakKey[], options: {
38
+ readonly only?: string | undefined;
39
+ readonly sinceMs?: number | undefined;
40
+ readonly clear?: boolean | undefined;
41
+ }) => Effect.Effect<ObservedWriter[], AdoptionRefused | import("effect/sql/SqlError").SqlError, SqlClient.SqlClient>;
42
+ /** One line of `observe --report`: who wrote, how often, and whether the runtime's own turns did. */
43
+ export declare const formatObservedWriter: (writer: ObservedWriter) => string;
@@ -0,0 +1,139 @@
1
+ import { DateTime, Effect } from "effect";
2
+ import { SqlClient } from "effect/sql";
3
+ import { mappingProblems, quotedTable } from "./plan.js";
4
+ import { AdoptionRefused, adoptionTargets, qualifiedName } from "./target.js";
5
+ const observeFunction = Effect.gen(function* () {
6
+ const sql = yield* SqlClient.SqlClient;
7
+ return (yield* sql `SELECT quote_ident(current_schema()) AS name`)[0].name;
8
+ });
9
+ /**
10
+ * Installs the four observing triggers on `target`, replacing any this module
11
+ * installed before. `arguments` is empty while observing, and names the writer
12
+ * and allowed roles once the table is enforced, so the trigger stays quiet for
13
+ * the runtime and marks allowed roles.
14
+ */
15
+ export const installObserveTriggers = Effect.fnUntraced(function* (target, roles = []) {
16
+ const sql = yield* SqlClient.SqlClient;
17
+ const schema = yield* observeFunction;
18
+ const table = quotedTable(target);
19
+ const literals = roles.map((role) => `'${role.replaceAll("'", "''")}'`).join(", ");
20
+ for (const event of ["insert", "update", "delete", "truncate"])
21
+ yield* sql.unsafe(`DROP TRIGGER IF EXISTS actor_adoption_observe_${event} ON ${table}`);
22
+ const trigger = `${schema}.actor_adoption_observe(${literals})`;
23
+ yield* sql.unsafe(`CREATE TRIGGER actor_adoption_observe_insert AFTER INSERT ON ${table}
24
+ REFERENCING NEW TABLE AS new_rows FOR EACH STATEMENT EXECUTE FUNCTION ${trigger}`);
25
+ yield* sql.unsafe(`CREATE TRIGGER actor_adoption_observe_update AFTER UPDATE ON ${table}
26
+ REFERENCING OLD TABLE AS old_rows NEW TABLE AS new_rows
27
+ FOR EACH STATEMENT EXECUTE FUNCTION ${trigger}`);
28
+ yield* sql.unsafe(`CREATE TRIGGER actor_adoption_observe_delete AFTER DELETE ON ${table}
29
+ REFERENCING OLD TABLE AS old_rows FOR EACH STATEMENT EXECUTE FUNCTION ${trigger}`);
30
+ yield* sql.unsafe(`CREATE TRIGGER actor_adoption_observe_truncate AFTER TRUNCATE ON ${table}
31
+ FOR EACH STATEMENT EXECUTE FUNCTION ${trigger}`);
32
+ });
33
+ /** Refuses a `--table` filter that names a table adopted for reading only, which has no observing state. */
34
+ const writable = (targets, only) => {
35
+ const found = targets.filter((target) => target.access === "write");
36
+ if (found.length === 0 && only !== undefined)
37
+ return Effect.fail(AdoptionRefused.make({
38
+ message: `${only} is adopted for reading only: nothing writes it, so it has no observing state`,
39
+ }));
40
+ return Effect.succeed(found);
41
+ };
42
+ /**
43
+ * Moves each writable adopted table of `actors` into the observing state:
44
+ * adds the nullable `routing_key`, records the adoption, and installs the
45
+ * statement triggers that record every later write. Observing changes no
46
+ * outcome, and repeating it is safe. A table already enforced is refused.
47
+ */
48
+ export const observeAdoption = Effect.fnUntraced(function* (actors, only, lockTimeoutMs = 5000) {
49
+ const sql = yield* SqlClient.SqlClient;
50
+ const done = [];
51
+ for (const target of yield* adoptionTargets(actors, only).pipe(Effect.flatMap((targets) => writable(targets, only)))) {
52
+ const name = qualifiedName(target);
53
+ const problems = yield* mappingProblems(target);
54
+ if (problems.length > 0)
55
+ return yield* AdoptionRefused.make({
56
+ message: `${name} cannot be adopted: ${problems.join("; ")}`,
57
+ });
58
+ yield* Effect.gen(function* () {
59
+ yield* sql `SELECT set_config('lock_timeout', ${`${lockTimeoutMs}ms`}, true)`;
60
+ const [existing] = yield* sql `
61
+ SELECT actor_type, mode FROM actor_adoptions
62
+ WHERE table_schema = ${target.schema} AND table_name = ${target.table} FOR UPDATE`;
63
+ if (existing !== undefined && existing.actor_type !== target.actor)
64
+ return yield* AdoptionRefused.make({
65
+ message: `${name} is adopted by actor ${existing.actor_type}, not ${target.actor}`,
66
+ });
67
+ if (existing?.mode === "enforce")
68
+ return yield* AdoptionRefused.make({
69
+ message: `${name} is enforced; run durable adopt release ${target.table} --to observe first`,
70
+ });
71
+ const [column] = yield* sql `
72
+ SELECT t.typname AS type FROM pg_attribute a
73
+ JOIN pg_class c ON c.oid = a.attrelid JOIN pg_namespace n ON n.oid = c.relnamespace
74
+ JOIN pg_type t ON t.oid = a.atttypid
75
+ WHERE n.nspname = ${target.schema} AND c.relname = ${target.table}
76
+ AND a.attname = 'routing_key' AND NOT a.attisdropped`;
77
+ if (column !== undefined && column.type !== "int8")
78
+ return yield* AdoptionRefused.make({
79
+ message: `${name} already has a routing_key column of type ${column.type}; it must be bigint`,
80
+ });
81
+ yield* sql.unsafe(`ALTER TABLE ${quotedTable(target)} ADD COLUMN IF NOT EXISTS routing_key bigint`);
82
+ yield* sql `INSERT INTO actor_adoptions (table_schema, table_name, actor_type, tenant_column,
83
+ actor_column, mode, changed_at_ms, changed_by)
84
+ VALUES (${target.schema}, ${target.table}, ${target.actor}, ${target.tenantColumn},
85
+ ${target.actorColumn}, 'observe', floor(extract(epoch FROM clock_timestamp()) * 1000),
86
+ session_user)
87
+ ON CONFLICT (table_schema, table_name) DO UPDATE SET
88
+ changed_at_ms = CASE WHEN actor_adoptions.tenant_column = EXCLUDED.tenant_column
89
+ AND actor_adoptions.actor_column = EXCLUDED.actor_column
90
+ THEN actor_adoptions.changed_at_ms ELSE EXCLUDED.changed_at_ms END,
91
+ tenant_column = EXCLUDED.tenant_column, actor_column = EXCLUDED.actor_column,
92
+ changed_by = EXCLUDED.changed_by`;
93
+ yield* installObserveTriggers(target);
94
+ }).pipe(sql.withTransaction);
95
+ done.push(name);
96
+ }
97
+ return done;
98
+ });
99
+ /**
100
+ * The writers recorded for the adopted tables of `actors` since `sinceMs`,
101
+ * grouped by table, login, application, and operation, with the runtime's own
102
+ * turns kept apart. `clear` deletes exactly the rows it reports.
103
+ */
104
+ export const adoptionWriters = Effect.fnUntraced(function* (actors, options) {
105
+ const sql = yield* SqlClient.SqlClient;
106
+ const found = [];
107
+ for (const target of yield* adoptionTargets(actors, options.only).pipe(Effect.flatMap((targets) => writable(targets, options.only)))) {
108
+ const since = options.sinceMs ?? 0;
109
+ const rows = yield* sql `
110
+ SELECT session_user_name, application_name, operation, in_turn, allowed,
111
+ count(*)::text AS statements, sum(rows)::text AS rows,
112
+ min(observed_at_ms)::text AS first_seen, max(observed_at_ms)::text AS last_seen
113
+ FROM actor_adoption_writes
114
+ WHERE table_schema = ${target.schema} AND table_name = ${target.table}
115
+ AND observed_at_ms >= ${since}
116
+ GROUP BY session_user_name, application_name, operation, in_turn, allowed
117
+ ORDER BY in_turn, session_user_name, application_name, operation`;
118
+ for (const row of rows)
119
+ found.push({
120
+ table: qualifiedName(target),
121
+ sessionUser: row.session_user_name,
122
+ applicationName: row.application_name,
123
+ operation: row.operation,
124
+ inTurn: row.in_turn,
125
+ allowed: row.allowed,
126
+ statements: Number(row.statements),
127
+ rows: Number(row.rows),
128
+ firstSeenMs: Number(row.first_seen),
129
+ lastSeenMs: Number(row.last_seen),
130
+ });
131
+ if (options.clear === true)
132
+ yield* sql `DELETE FROM actor_adoption_writes
133
+ WHERE table_schema = ${target.schema} AND table_name = ${target.table}
134
+ AND observed_at_ms >= ${since}`;
135
+ }
136
+ return found;
137
+ });
138
+ /** One line of `observe --report`: who wrote, how often, and whether the runtime's own turns did. */
139
+ export const formatObservedWriter = (writer) => `${writer.table} ${writer.inTurn ? "turn " : writer.allowed ? "allow" : "legacy"} ${writer.sessionUser} ${writer.applicationName === "" ? "(no application_name)" : writer.applicationName} ${writer.operation} ${writer.statements} statements, ${writer.rows} rows first ${DateTime.formatIso(DateTime.makeUnsafe(writer.firstSeenMs))} last ${DateTime.formatIso(DateTime.makeUnsafe(writer.lastSeenMs))}`;
@@ -0,0 +1,45 @@
1
+ import { Effect } from "effect";
2
+ import { SqlClient } from "effect/sql";
3
+ import { type AdoptionTarget } from "./target.ts";
4
+ /** What `durable adopt plan` reports for one table; it changes nothing. */
5
+ export interface AdoptionPlan {
6
+ readonly table: string;
7
+ readonly actor: string;
8
+ readonly access: "write" | "read";
9
+ /** Reasons the table cannot be adopted as declared; observe and enforce refuse while any remain. */
10
+ readonly problems: ReadonlyArray<string>;
11
+ /** Conditions the operator should know about that do not stop adoption. */
12
+ readonly warnings: ReadonlyArray<string>;
13
+ readonly foreignKeys: ReadonlyArray<string>;
14
+ readonly triggers: ReadonlyArray<string>;
15
+ readonly rules: ReadonlyArray<string>;
16
+ readonly views: ReadonlyArray<string>;
17
+ readonly owner: string;
18
+ /** Roles holding a write privilege, which `enforce` revokes except for the writer and `--allow` roles. */
19
+ readonly writers: ReadonlyArray<string>;
20
+ /** The statement that adds the index every scoped statement needs, or undefined when one exists. */
21
+ readonly indexSql: string | undefined;
22
+ /** The SQL each later step would run. */
23
+ readonly steps: ReadonlyArray<string>;
24
+ }
25
+ /** `"schema"."table"`, quoted for the SQL the CLI prints and runs. */
26
+ export declare const quotedTable: (target: Pick<AdoptionTarget, "schema" | "table">) => string;
27
+ /** The index columns a scoped statement leads with: `routing_key` first when the runtime writes the table. */
28
+ export declare const ownerIndexColumns: (target: Pick<AdoptionTarget, "access" | "tenantColumn" | "actorColumn">) => string[];
29
+ /** The statement that adds an index leading with the mapped columns. */
30
+ export declare const ownerIndexSql: (target: Pick<AdoptionTarget, "schema" | "table" | "access" | "tenantColumn" | "actorColumn">) => string;
31
+ /**
32
+ * The problems that stop a table from being adopted as declared: it must
33
+ * exist, its mapped columns must exist, and they must be text, varchar, or uuid
34
+ * with a deterministic collation. Shared by `plan` and `observe`.
35
+ */
36
+ export declare const mappingProblems: (target: AdoptionTarget) => Effect.Effect<string[], import("effect/sql/SqlError").SqlError, SqlClient.SqlClient>;
37
+ /** True when an index leading with the mapped columns exists, so scoped statements do not scan the table. */
38
+ export declare const ownerIndexExists: (target: Pick<AdoptionTarget, "access" | "actorColumn" | "schema" | "table" | "tenantColumn">) => Effect.Effect<boolean, import("effect/sql/SqlError").SqlError, SqlClient.SqlClient>;
39
+ /**
40
+ * Reads the catalog for every adopted table of `actors` and reports what
41
+ * adoption would meet, and the SQL each step would run. Changes nothing.
42
+ */
43
+ export declare const planAdoption: (actors: readonly WeakKey[], only?: string | undefined) => Effect.Effect<AdoptionPlan[], import("./target.ts").AdoptionRefused | import("effect/sql/SqlError").SqlError, SqlClient.SqlClient>;
44
+ /** What `plan` prints: one block per table. */
45
+ export declare const formatAdoptionPlan: (plan: AdoptionPlan) => string;