@rikalabs/akter 0.1.0-alpha.0 → 0.1.0-alpha.3

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 (308) hide show
  1. package/CHANGELOG.md +46 -3
  2. package/README.md +2 -2
  3. package/dist/actor/definition.d.ts +13 -9
  4. package/dist/actor/descriptor.d.ts +2 -2
  5. package/dist/actor/descriptor.js +4 -4
  6. package/dist/client/calls.js +1 -1
  7. package/dist/client/index.d.ts +1 -1
  8. package/dist/client/index.js +1 -1
  9. package/dist/errors/actor.d.ts +12 -42
  10. package/dist/errors/actor.js +13 -42
  11. package/dist/index.d.ts +1 -1
  12. package/dist/index.js +1 -1
  13. package/dist/members/payload.d.ts +1 -1
  14. package/dist/protocol/inspection.d.ts +221 -1
  15. package/dist/protocol/inspection.js +151 -2
  16. package/dist/protocol/wire.d.ts +6 -49
  17. package/dist/protocol/wire.js +1 -10
  18. package/dist/runtime/actors.d.ts +3 -0
  19. package/dist/runtime/adoption/backfill.js +1 -1
  20. package/dist/runtime/adoption/enforce.js +2 -2
  21. package/dist/runtime/adoption/observe.js +1 -1
  22. package/dist/runtime/adoption/plan.d.ts +1 -1
  23. package/dist/runtime/adoption/startup.js +1 -1
  24. package/dist/runtime/adoption/status.d.ts +1 -1
  25. package/dist/runtime/app.d.ts +65 -0
  26. package/dist/runtime/app.js +38 -0
  27. package/dist/runtime/connections/holder.d.ts +11 -1
  28. package/dist/runtime/connections/holder.js +8 -4
  29. package/dist/runtime/connections/streams.d.ts +4 -4
  30. package/dist/runtime/content/store.js +15 -11
  31. package/dist/runtime/database/bounded.d.ts +4 -18
  32. package/dist/runtime/database/bounded.js +36 -22
  33. package/dist/runtime/database/coordination.d.ts +12 -3
  34. package/dist/runtime/database/coordination.js +29 -36
  35. package/dist/runtime/database/migrations.d.ts +61 -29
  36. package/dist/runtime/database/migrations.js +375 -139
  37. package/dist/runtime/database/replica.d.ts +4 -1
  38. package/dist/runtime/database/replica.js +4 -1
  39. package/dist/runtime/database/schema.d.ts +13 -0
  40. package/dist/runtime/database/schema.js +13 -0
  41. package/dist/runtime/database/shards.d.ts +31 -13
  42. package/dist/runtime/database/shards.js +38 -26
  43. package/dist/runtime/entity/register.d.ts +8 -1
  44. package/dist/runtime/entity/register.js +58 -7
  45. package/dist/runtime/fleet/checks.js +4 -4
  46. package/dist/runtime/fleet/maintainer.d.ts +1 -1
  47. package/dist/runtime/fleet/maintainer.js +1 -1
  48. package/dist/runtime/index.d.ts +2 -0
  49. package/dist/runtime/index.js +1 -0
  50. package/dist/runtime/inspector/layer.d.ts +20 -0
  51. package/dist/runtime/inspector/layer.js +224 -5
  52. package/dist/runtime/inspector/queries.d.ts +54 -8
  53. package/dist/runtime/inspector/queries.js +84 -15
  54. package/dist/runtime/layer.d.ts +48 -39
  55. package/dist/runtime/layer.js +124 -56
  56. package/dist/runtime/operators/audit.d.ts +3 -0
  57. package/dist/runtime/operators/audit.js +6 -2
  58. package/dist/runtime/operators/repair.js +30 -10
  59. package/dist/runtime/operators/seed.js +4 -2
  60. package/dist/runtime/payloads/versions.d.ts +4 -4
  61. package/dist/runtime/payloads/versions.js +24 -15
  62. package/dist/runtime/queries.js +4 -2
  63. package/dist/runtime/registration.d.ts +5 -2
  64. package/dist/runtime/registration.js +3 -3
  65. package/dist/runtime/runner.d.ts +12 -0
  66. package/dist/runtime/runner.js +12 -0
  67. package/dist/runtime/storage/codec.d.ts +19 -7
  68. package/dist/runtime/storage/codec.js +23 -7
  69. package/dist/runtime/storage/placements.d.ts +6 -1
  70. package/dist/runtime/storage/placements.js +98 -6
  71. package/dist/runtime/storage/retention.d.ts +6 -0
  72. package/dist/runtime/storage/retention.js +25 -13
  73. package/dist/runtime/subscriptions/relay.js +47 -44
  74. package/dist/runtime/subscriptions/storage.d.ts +3 -2
  75. package/dist/runtime/subscriptions/storage.js +9 -6
  76. package/dist/runtime/telemetry/live.d.ts +255 -0
  77. package/dist/runtime/telemetry/live.js +540 -0
  78. package/dist/runtime/telemetry/metrics.d.ts +2 -0
  79. package/dist/runtime/telemetry/metrics.js +4 -1
  80. package/dist/runtime/telemetry/sampler.js +33 -13
  81. package/dist/runtime/telemetry/spans.d.ts +1 -1
  82. package/dist/runtime/telemetry/spans.js +1 -1
  83. package/dist/runtime/topology/locks.d.ts +6 -3
  84. package/dist/runtime/topology/locks.js +27 -4
  85. package/dist/runtime/turn/execute.d.ts +2 -0
  86. package/dist/runtime/turn/execute.js +5 -2
  87. package/dist/runtime/turn/pipeline.d.ts +5 -12
  88. package/dist/runtime/turn/pipeline.js +11 -11
  89. package/dist/runtime/turn/relay.d.ts +13 -3
  90. package/dist/runtime/turn/relay.js +27 -14
  91. package/dist/runtime/turn/rows.js +4 -4
  92. package/dist/runtime/workflows/compatibility.d.ts +1 -1
  93. package/dist/runtime/workflows/compatibility.js +85 -31
  94. package/dist/runtime/workflows/engine.js +20 -17
  95. package/dist/serve/layer.js +3 -2
  96. package/dist/tables/owned.d.ts +1 -1
  97. package/dist/tables/owned.js +1 -1
  98. package/dist/testing/actor-test.d.ts +2 -24
  99. package/dist/testing/actor-test.js +1 -27
  100. package/dist/testing/index.d.ts +0 -12
  101. package/dist/testing/index.js +0 -6
  102. package/package.json +1 -1
  103. package/dist/runtime/database/neki/migrations.d.ts +0 -31
  104. package/dist/runtime/database/neki/migrations.js +0 -276
  105. package/dist/runtime/database/neki/session.d.ts +0 -23
  106. package/dist/runtime/database/neki/session.js +0 -31
  107. package/dist/testing/cluster.d.ts +0 -93
  108. package/dist/testing/cluster.js +0 -296
  109. package/dist/testing/conformance/access.d.ts +0 -5
  110. package/dist/testing/conformance/access.js +0 -531
  111. package/dist/testing/conformance/admission.d.ts +0 -11
  112. package/dist/testing/conformance/admission.js +0 -182
  113. package/dist/testing/conformance/adoption.d.ts +0 -2
  114. package/dist/testing/conformance/adoption.js +0 -1019
  115. package/dist/testing/conformance/assertions.d.ts +0 -202
  116. package/dist/testing/conformance/assertions.js +0 -849
  117. package/dist/testing/conformance/batches.d.ts +0 -41
  118. package/dist/testing/conformance/batches.js +0 -388
  119. package/dist/testing/conformance/blobs.d.ts +0 -14
  120. package/dist/testing/conformance/blobs.js +0 -405
  121. package/dist/testing/conformance/capacity.d.ts +0 -8
  122. package/dist/testing/conformance/capacity.js +0 -433
  123. package/dist/testing/conformance/client.d.ts +0 -5
  124. package/dist/testing/conformance/client.js +0 -719
  125. package/dist/testing/conformance/cold-serve.d.ts +0 -16
  126. package/dist/testing/conformance/cold-serve.js +0 -254
  127. package/dist/testing/conformance/connections/actors.d.ts +0 -1143
  128. package/dist/testing/conformance/connections/actors.js +0 -180
  129. package/dist/testing/conformance/connections/harness.d.ts +0 -1754
  130. package/dist/testing/conformance/connections/harness.js +0 -142
  131. package/dist/testing/conformance/connections/holders.d.ts +0 -4
  132. package/dist/testing/conformance/connections/holders.js +0 -165
  133. package/dist/testing/conformance/connections/lifecycle.d.ts +0 -4
  134. package/dist/testing/conformance/connections/lifecycle.js +0 -113
  135. package/dist/testing/conformance/connections/limits.d.ts +0 -4
  136. package/dist/testing/conformance/connections/limits.js +0 -127
  137. package/dist/testing/conformance/connections/reauthorization.d.ts +0 -4
  138. package/dist/testing/conformance/connections/reauthorization.js +0 -170
  139. package/dist/testing/conformance/connections/resync.d.ts +0 -4
  140. package/dist/testing/conformance/connections/resync.js +0 -360
  141. package/dist/testing/conformance/connections/takeover.d.ts +0 -4
  142. package/dist/testing/conformance/connections/takeover.js +0 -287
  143. package/dist/testing/conformance/connections.d.ts +0 -4
  144. package/dist/testing/conformance/connections.js +0 -15
  145. package/dist/testing/conformance/content-blobs.d.ts +0 -16
  146. package/dist/testing/conformance/content-blobs.js +0 -534
  147. package/dist/testing/conformance/counter.d.ts +0 -16
  148. package/dist/testing/conformance/counter.js +0 -813
  149. package/dist/testing/conformance/cron.d.ts +0 -5
  150. package/dist/testing/conformance/cron.js +0 -665
  151. package/dist/testing/conformance/drain.d.ts +0 -26
  152. package/dist/testing/conformance/drain.js +0 -540
  153. package/dist/testing/conformance/effect-control.d.ts +0 -38
  154. package/dist/testing/conformance/effect-control.js +0 -1059
  155. package/dist/testing/conformance/effects.d.ts +0 -23
  156. package/dist/testing/conformance/effects.js +0 -432
  157. package/dist/testing/conformance/events.d.ts +0 -28
  158. package/dist/testing/conformance/events.js +0 -335
  159. package/dist/testing/conformance/export.d.ts +0 -2
  160. package/dist/testing/conformance/export.js +0 -368
  161. package/dist/testing/conformance/fleet.d.ts +0 -444
  162. package/dist/testing/conformance/fleet.js +0 -1009
  163. package/dist/testing/conformance/groups.d.ts +0 -7
  164. package/dist/testing/conformance/groups.js +0 -353
  165. package/dist/testing/conformance/heap.d.ts +0 -3
  166. package/dist/testing/conformance/heap.js +0 -149
  167. package/dist/testing/conformance/http.d.ts +0 -2809
  168. package/dist/testing/conformance/http.js +0 -1234
  169. package/dist/testing/conformance/inspection-views.d.ts +0 -8
  170. package/dist/testing/conformance/inspection-views.js +0 -272
  171. package/dist/testing/conformance/inspector.d.ts +0 -7
  172. package/dist/testing/conformance/inspector.js +0 -650
  173. package/dist/testing/conformance/mint.d.ts +0 -58
  174. package/dist/testing/conformance/mint.js +0 -692
  175. package/dist/testing/conformance/multi-runner.d.ts +0 -8
  176. package/dist/testing/conformance/multi-runner.js +0 -403
  177. package/dist/testing/conformance/neki/plan.d.ts +0 -19
  178. package/dist/testing/conformance/neki/plan.js +0 -30
  179. package/dist/testing/conformance/observability.d.ts +0 -3
  180. package/dist/testing/conformance/observability.js +0 -343
  181. package/dist/testing/conformance/offline.d.ts +0 -4
  182. package/dist/testing/conformance/offline.js +0 -474
  183. package/dist/testing/conformance/operator-harness.d.ts +0 -57
  184. package/dist/testing/conformance/operator-harness.js +0 -78
  185. package/dist/testing/conformance/operator.d.ts +0 -3
  186. package/dist/testing/conformance/operator.js +0 -379
  187. package/dist/testing/conformance/outbox-cross-shard.d.ts +0 -14
  188. package/dist/testing/conformance/outbox-cross-shard.js +0 -160
  189. package/dist/testing/conformance/outbox.d.ts +0 -36
  190. package/dist/testing/conformance/outbox.js +0 -437
  191. package/dist/testing/conformance/payload-migrations.d.ts +0 -3
  192. package/dist/testing/conformance/payload-migrations.js +0 -612
  193. package/dist/testing/conformance/pipeline.d.ts +0 -3
  194. package/dist/testing/conformance/pipeline.js +0 -1040
  195. package/dist/testing/conformance/placement.d.ts +0 -22
  196. package/dist/testing/conformance/placement.js +0 -539
  197. package/dist/testing/conformance/platform.d.ts +0 -40
  198. package/dist/testing/conformance/platform.js +0 -101
  199. package/dist/testing/conformance/progress.d.ts +0 -39
  200. package/dist/testing/conformance/progress.js +0 -666
  201. package/dist/testing/conformance/properties.d.ts +0 -6
  202. package/dist/testing/conformance/properties.js +0 -295
  203. package/dist/testing/conformance/protocols.d.ts +0 -4
  204. package/dist/testing/conformance/protocols.js +0 -618
  205. package/dist/testing/conformance/provider/advertise.d.ts +0 -21
  206. package/dist/testing/conformance/provider/advertise.js +0 -44
  207. package/dist/testing/conformance/read-your-writes.d.ts +0 -20
  208. package/dist/testing/conformance/read-your-writes.js +0 -192
  209. package/dist/testing/conformance/reducers.d.ts +0 -8
  210. package/dist/testing/conformance/reducers.js +0 -258
  211. package/dist/testing/conformance/relay.d.ts +0 -42
  212. package/dist/testing/conformance/relay.js +0 -1115
  213. package/dist/testing/conformance/restore.d.ts +0 -43
  214. package/dist/testing/conformance/restore.js +0 -341
  215. package/dist/testing/conformance/retention.d.ts +0 -14
  216. package/dist/testing/conformance/retention.js +0 -463
  217. package/dist/testing/conformance/rls.d.ts +0 -24
  218. package/dist/testing/conformance/rls.js +0 -576
  219. package/dist/testing/conformance/simulation.d.ts +0 -31
  220. package/dist/testing/conformance/simulation.js +0 -167
  221. package/dist/testing/conformance/single-shard.d.ts +0 -2
  222. package/dist/testing/conformance/single-shard.js +0 -125
  223. package/dist/testing/conformance/singleton.d.ts +0 -3
  224. package/dist/testing/conformance/singleton.js +0 -293
  225. package/dist/testing/conformance/statements.d.ts +0 -60
  226. package/dist/testing/conformance/statements.js +0 -108
  227. package/dist/testing/conformance/streams.d.ts +0 -7
  228. package/dist/testing/conformance/streams.js +0 -280
  229. package/dist/testing/conformance/subscriptions/access.d.ts +0 -4
  230. package/dist/testing/conformance/subscriptions/access.js +0 -98
  231. package/dist/testing/conformance/subscriptions/actors.d.ts +0 -4910
  232. package/dist/testing/conformance/subscriptions/actors.js +0 -372
  233. package/dist/testing/conformance/subscriptions/cluster.d.ts +0 -4
  234. package/dist/testing/conformance/subscriptions/cluster.js +0 -89
  235. package/dist/testing/conformance/subscriptions/delivery.d.ts +0 -4
  236. package/dist/testing/conformance/subscriptions/delivery.js +0 -253
  237. package/dist/testing/conformance/subscriptions/deploys.d.ts +0 -4
  238. package/dist/testing/conformance/subscriptions/deploys.js +0 -162
  239. package/dist/testing/conformance/subscriptions/epochs.d.ts +0 -4
  240. package/dist/testing/conformance/subscriptions/epochs.js +0 -169
  241. package/dist/testing/conformance/subscriptions/failures.d.ts +0 -4
  242. package/dist/testing/conformance/subscriptions/failures.js +0 -108
  243. package/dist/testing/conformance/subscriptions/feeds.d.ts +0 -4
  244. package/dist/testing/conformance/subscriptions/feeds.js +0 -218
  245. package/dist/testing/conformance/subscriptions/harness.d.ts +0 -124
  246. package/dist/testing/conformance/subscriptions/harness.js +0 -143
  247. package/dist/testing/conformance/subscriptions/operator.d.ts +0 -4
  248. package/dist/testing/conformance/subscriptions/operator.js +0 -128
  249. package/dist/testing/conformance/subscriptions/retention.d.ts +0 -4
  250. package/dist/testing/conformance/subscriptions/retention.js +0 -288
  251. package/dist/testing/conformance/subscriptions/routing.d.ts +0 -4
  252. package/dist/testing/conformance/subscriptions/routing.js +0 -179
  253. package/dist/testing/conformance/subscriptions.d.ts +0 -4
  254. package/dist/testing/conformance/subscriptions.js +0 -19
  255. package/dist/testing/conformance/tables.d.ts +0 -125
  256. package/dist/testing/conformance/tables.js +0 -664
  257. package/dist/testing/conformance/transports/actors.d.ts +0 -1907
  258. package/dist/testing/conformance/transports/actors.js +0 -163
  259. package/dist/testing/conformance/transports/client.d.ts +0 -3
  260. package/dist/testing/conformance/transports/client.js +0 -237
  261. package/dist/testing/conformance/transports/feeds.d.ts +0 -3
  262. package/dist/testing/conformance/transports/feeds.js +0 -232
  263. package/dist/testing/conformance/transports/harness.d.ts +0 -93
  264. package/dist/testing/conformance/transports/harness.js +0 -84
  265. package/dist/testing/conformance/transports/streams.d.ts +0 -3
  266. package/dist/testing/conformance/transports/streams.js +0 -96
  267. package/dist/testing/conformance/transports/websocket.d.ts +0 -3
  268. package/dist/testing/conformance/transports/websocket.js +0 -384
  269. package/dist/testing/conformance/transports/wire.d.ts +0 -141
  270. package/dist/testing/conformance/transports/wire.js +0 -204
  271. package/dist/testing/conformance/transports.d.ts +0 -3
  272. package/dist/testing/conformance/transports.js +0 -11
  273. package/dist/testing/conformance/watch.d.ts +0 -59
  274. package/dist/testing/conformance/watch.js +0 -879
  275. package/dist/testing/conformance/workflow-engine.d.ts +0 -97
  276. package/dist/testing/conformance/workflow-engine.js +0 -253
  277. package/dist/testing/conformance/workflow-versions.d.ts +0 -3
  278. package/dist/testing/conformance/workflow-versions.js +0 -545
  279. package/dist/testing/conformance/workflows/access.d.ts +0 -4
  280. package/dist/testing/conformance/workflows/access.js +0 -147
  281. package/dist/testing/conformance/workflows/actors.d.ts +0 -2317
  282. package/dist/testing/conformance/workflows/actors.js +0 -305
  283. package/dist/testing/conformance/workflows/basics.d.ts +0 -4
  284. package/dist/testing/conformance/workflows/basics.js +0 -144
  285. package/dist/testing/conformance/workflows/engine.d.ts +0 -4
  286. package/dist/testing/conformance/workflows/engine.js +0 -80
  287. package/dist/testing/conformance/workflows/guards.d.ts +0 -4
  288. package/dist/testing/conformance/workflows/guards.js +0 -172
  289. package/dist/testing/conformance/workflows/harness.d.ts +0 -14
  290. package/dist/testing/conformance/workflows/harness.js +0 -44
  291. package/dist/testing/conformance/workflows/recovery.d.ts +0 -4
  292. package/dist/testing/conformance/workflows/recovery.js +0 -181
  293. package/dist/testing/conformance/workflows/starts.d.ts +0 -4
  294. package/dist/testing/conformance/workflows/starts.js +0 -57
  295. package/dist/testing/conformance/workflows/suspension.d.ts +0 -4
  296. package/dist/testing/conformance/workflows/suspension.js +0 -106
  297. package/dist/testing/conformance/workflows/waits.d.ts +0 -4
  298. package/dist/testing/conformance/workflows/waits.js +0 -284
  299. package/dist/testing/conformance/workflows.d.ts +0 -4
  300. package/dist/testing/conformance/workflows.js +0 -19
  301. package/dist/testing/conformance.d.ts +0 -330
  302. package/dist/testing/conformance.js +0 -364
  303. package/dist/testing/foundation.d.ts +0 -41
  304. package/dist/testing/foundation.js +0 -517
  305. package/dist/testing/simulate-cluster.d.ts +0 -112
  306. package/dist/testing/simulate-cluster.js +0 -257
  307. package/dist/testing/simulate.d.ts +0 -90
  308. package/dist/testing/simulate.js +0 -127
@@ -1,463 +0,0 @@
1
- import { Cause, Clock, Effect, Exit, Fiber, Layer, Option, Schema } from "effect";
2
- import { SqlClient } from "effect/sql";
3
- import { Actor, Intent, RetentionGap, UnknownCursor } from "../../index.js";
4
- import { ActorError, CommandExpired, Timeout } from "../../errors/actor.js";
5
- import { databaseTime } from "../../runtime/turn/admission.js";
6
- import { ActorTest } from "../actor-test.js";
7
- import { CLAIM_LEASE } from "./outbox.js";
8
- export const retentionFixture = () => ({ adds: 0, receives: 0 });
9
- const Noted = Actor.event("Noted", { body: Schema.String });
10
- const files = Actor.blob("files");
11
- const Note = Actor.command("Note", { payload: Schema.String, success: Schema.String });
12
- const NoteMany = Actor.command("NoteMany", {
13
- payload: Schema.Struct({ count: Schema.Int, bytes: Schema.Int }),
14
- });
15
- const Add = Actor.command("Add", { payload: Schema.Int, success: Schema.Int });
16
- const Forward = Actor.command("Forward", { payload: Schema.String });
17
- const Receive = Actor.command("Receive", { payload: Schema.String });
18
- const Put = Actor.command("Put", {
19
- payload: Schema.Struct({ name: Schema.String, bytes: Schema.Int }),
20
- });
21
- const Grow = Actor.command("Grow", {
22
- payload: Schema.Struct({ name: Schema.String, bytes: Schema.Int }),
23
- });
24
- const Drop = Actor.command("Drop", { payload: Schema.String });
25
- /** Replaces an entry and swallows the defect, so the turn commits whatever the write left. */
26
- const PutCaught = Actor.command("PutCaught", {
27
- payload: Schema.Struct({ name: Schema.String, bytes: Schema.Int }),
28
- success: Schema.Boolean,
29
- });
30
- const Entry = Schema.Struct({ cursor: Schema.String, body: Schema.String });
31
- const History = Actor.query("History", {
32
- payload: Schema.Struct({
33
- after: Schema.optional(Schema.String),
34
- limit: Schema.optional(Schema.Finite),
35
- }),
36
- success: Schema.Array(Entry),
37
- error: Schema.Union([UnknownCursor, RetentionGap]),
38
- });
39
- const Size = Actor.query("Size", { payload: Schema.String, success: Schema.Int });
40
- const Total = Actor.query("Total", { success: Schema.Int });
41
- const Journal = Actor.make("Journal", {
42
- key: Schema.String,
43
- state: Actor.state({ total: Schema.Int.pipe(Schema.withDecodingDefault(Effect.succeed(0))) }),
44
- events: [Noted],
45
- blobs: [files],
46
- api: { Note, NoteMany, Add, Forward, Put, Grow, PutCaught, Drop, History, Size, Total },
47
- internal: { Receive },
48
- policy: {
49
- keepReceipts: "2 days",
50
- keepEvents: "1 day",
51
- maxBlobBytes: 1024,
52
- maxBlobEntries: 3,
53
- executionTimeout: "2 seconds",
54
- },
55
- });
56
- /** The same events under a longer horizon, so one sweep applies each type's own policy. */
57
- const Tally = Actor.command("Tally", { payload: Schema.Int, success: Schema.Int });
58
- /** Keeps receipts for less than the retry window, so only the delivery-timeout grace holds them. */
59
- const Brief = Actor.make("Brief", {
60
- key: Schema.String,
61
- state: Actor.state({ total: Schema.Int.pipe(Schema.withDecodingDefault(Effect.succeed(0))) }),
62
- api: { Tally },
63
- policy: { keepReceipts: "1 second" },
64
- });
65
- const Chronicle = Actor.make("Chronicle", {
66
- key: Schema.String,
67
- events: [Noted],
68
- api: { Note },
69
- policy: { keepEvents: "90 days" },
70
- });
71
- export const retentionLayer = (fixture) => Layer.mergeAll(Journal.toLayer(Effect.succeed({
72
- Forward: Effect.fnUntraced(function* (to) {
73
- yield* Journal.Turn;
74
- yield* (yield* Journal.intents(to)).Receive("forwarded").pipe(Intent.after("1 minute"));
75
- }),
76
- Note: Effect.fnUntraced(function* (body) {
77
- const turn = yield* Journal.Turn;
78
- yield* turn.emit(Noted.make({ body }));
79
- return turn.commandId;
80
- }),
81
- NoteMany: Effect.fnUntraced(function* ({ count, bytes }) {
82
- const turn = yield* Journal.Turn;
83
- for (let index = 0; index < count; index++)
84
- yield* turn.emit(Noted.make({ body: "x".repeat(bytes) }));
85
- }),
86
- Add: Effect.fnUntraced(function* (amount) {
87
- const turn = yield* Journal.Turn;
88
- fixture.adds += 1;
89
- yield* turn.state.set({ total: turn.state.total + amount });
90
- return turn.state.total;
91
- }),
92
- Receive: Effect.fnUntraced(function* () {
93
- const turn = yield* Journal.Turn;
94
- fixture.receives += 1;
95
- yield* turn.state.set({ total: turn.state.total + 1 });
96
- }),
97
- Put: Effect.fnUntraced(function* ({ name, bytes }) {
98
- yield* (yield* Journal.Turn).blob(files).set(name, new Uint8Array(bytes));
99
- }),
100
- Grow: Effect.fnUntraced(function* ({ name, bytes }) {
101
- yield* (yield* Journal.Turn).blob(files).append(name, new Uint8Array(bytes));
102
- }),
103
- Drop: Effect.fnUntraced(function* (name) {
104
- yield* (yield* Journal.Turn).blob(files).delete(name);
105
- }),
106
- PutCaught: Effect.fnUntraced(function* ({ name, bytes }) {
107
- return yield* (yield* Journal.Turn)
108
- .blob(files)
109
- .set(name, new Uint8Array(bytes))
110
- .pipe(Effect.as(true), Effect.catchDefect(() => Effect.succeed(false)));
111
- }),
112
- })), Journal.toQueryLayer(Effect.succeed({
113
- History: Effect.fnUntraced(function* ({ after, limit }) {
114
- const read = yield* Journal.Read;
115
- const entries = yield* read.events(Noted, { after, limit });
116
- return entries.map(({ cursor, event }) => ({ cursor, body: event.body }));
117
- }),
118
- Size: Effect.fnUntraced(function* (name) {
119
- const bytes = yield* (yield* Journal.Read).blob(files).get(name);
120
- return Option.match(bytes, { onNone: () => -1, onSome: (value) => value.byteLength });
121
- }),
122
- Total: Effect.fnUntraced(function* () {
123
- return (yield* Journal.Read).state.total;
124
- }),
125
- })), Brief.toLayer(Effect.succeed({
126
- Tally: Effect.fnUntraced(function* (amount) {
127
- const turn = yield* Brief.Turn;
128
- yield* turn.state.set({ total: turn.state.total + amount });
129
- return turn.state.total;
130
- }),
131
- })), Chronicle.toLayer(Effect.succeed({
132
- Note: Effect.fnUntraced(function* (body) {
133
- const turn = yield* Chronicle.Turn;
134
- yield* turn.emit(Noted.make({ body }));
135
- return turn.commandId;
136
- }),
137
- })));
138
- const defect = (exit) => Exit.isFailure(exit) ? Cause.pretty(exit.cause) : "succeeded";
139
- const cursors = (entries) => entries.map(({ cursor }) => cursor);
140
- /**
141
- * Runs `effect` in a runtime of its own on a fresh database, for a case whose
142
- * pause points must not catch a turn the shared runtime's relay delivers. The
143
- * shared runtime stops meanwhile: two in-process runtimes at once can starve
144
- * Cluster's runner health checks.
145
- */
146
- const isolated = (environment, effect) => Effect.runPromise(Effect.gen(function* () {
147
- yield* Effect.acquireRelease(environment.stop, () => environment.restart);
148
- const database = yield* environment.freshDatabase;
149
- const runtime = yield* Effect.acquireRelease(Effect.sync(() => environment.build({ database })), (built) => Effect.promise(() => built.dispose()));
150
- return yield* Effect.promise(() => runtime.runPromise(Effect.scoped(effect)));
151
- }).pipe(Effect.scoped));
152
- const eventSequence = Effect.fnUntraced(function* (id) {
153
- const sql = yield* SqlClient.SqlClient;
154
- const test = yield* ActorTest;
155
- const [row] = yield* sql `
156
- SELECT event_sequence::text AS sequence FROM actor_generations
157
- WHERE tenant_id = ${test.tenant} AND actor_type = 'Journal' AND actor_id = ${id}`;
158
- return row?.sequence;
159
- }, Effect.orDie);
160
- /** Retention cases: pruning of receipts and events keeps expired ids rejected, outbox dedup intact, and sequences continuous. */
161
- export const retentionConformance = [
162
- {
163
- name: "prunes receipts past keepReceipts and still rejects the expired id after pruning and restart",
164
- run: ({ expect, environment, fixture }) => environment.run(Effect.gen(function* () {
165
- const test = yield* ActorTest;
166
- const journal = yield* Journal.get("receipts");
167
- const before = fixture.adds;
168
- const add = journal.Add(3);
169
- expect(yield* add).toBe(3);
170
- expect(yield* journal.Add(4)).toBe(7);
171
- yield* test.advance("1 day");
172
- yield* test.cleanup;
173
- expect(yield* test.inspect(journal.ref)).toMatchObject({ receipts: 2 });
174
- expect((yield* add.pipe(Effect.flip)).reason).toBeInstanceOf(CommandExpired);
175
- yield* test.advance("2 days");
176
- yield* test.cleanup;
177
- expect(yield* test.inspect(journal.ref)).toMatchObject({
178
- receipts: 0,
179
- state: { total: 7 },
180
- });
181
- expect((yield* add.pipe(Effect.flip)).reason).toBeInstanceOf(CommandExpired);
182
- expect(fixture.adds - before).toBe(2);
183
- expect(yield* journal.Total()).toBe(7);
184
- })),
185
- },
186
- {
187
- name: "rejects a pruned expired id after restart without running its handler",
188
- run: ({ expect, environment, fixture }) => Effect.runPromise(Effect.gen(function* () {
189
- yield* environment.stop;
190
- const first = environment.build();
191
- const saved = yield* Effect.promise(() => first
192
- .runPromise(Effect.scoped(Effect.gen(function* () {
193
- const test = yield* ActorTest;
194
- const journal = yield* Journal.get("restart");
195
- const now = yield* databaseTime;
196
- const id = `v1.${now - 59_000}.${now + 1_000}.6f6f1e0a-3a42-4c1e-9d6b-2b1c1f1a9e01`;
197
- expect(yield* journal.Add(5).pipe(Actor.commandId(id))).toBe(5);
198
- yield* test.advance("3 days");
199
- yield* test.cleanup;
200
- expect(yield* test.inspect(journal.ref)).toMatchObject({ receipts: 0 });
201
- return { id, tenant: test.tenant };
202
- })))
203
- .finally(() => first.dispose()));
204
- const adds = fixture.adds;
205
- const second = environment.build();
206
- yield* Effect.promise(() => second
207
- .runPromise(Effect.scoped(Effect.gen(function* () {
208
- const journal = yield* Journal.get("restart").pipe(Actor.tenant(saved.tenant));
209
- yield* Effect.sleep("1100 millis");
210
- const failure = yield* journal
211
- .Add(5)
212
- .pipe(Actor.commandId(saved.id), Effect.flip);
213
- expect(failure.reason).toBeInstanceOf(CommandExpired);
214
- expect(yield* journal.Total()).toBe(5);
215
- })))
216
- .finally(() => second.dispose()));
217
- expect(fixture.adds).toBe(adds);
218
- }).pipe(Effect.ensuring(environment.restart))),
219
- },
220
- {
221
- name: "prunes receipts past keepReceipts without breaking outbox dedup",
222
- run: ({ expect, environment, fixture }) => environment.run(Effect.gen(function* () {
223
- const test = yield* ActorTest;
224
- const sender = yield* Journal.get("sender");
225
- const receiver = yield* Journal.get("receiver");
226
- const bystander = yield* Journal.get("bystander");
227
- const before = fixture.receives;
228
- yield* sender.Forward("receiver");
229
- const sql = yield* SqlClient.SqlClient;
230
- yield* bystander.Add(1);
231
- yield* sql `UPDATE actor_receipts SET command_id = o.intent_id FROM actor_outbox o
232
- WHERE o.tenant_id = ${test.tenant} AND o.actor_id = 'sender'
233
- AND actor_receipts.tenant_id = ${test.tenant} AND actor_receipts.actor_id = 'bystander'`;
234
- yield* test.crashNext("beforeOutboxDelete");
235
- yield* test.crashNext("beforeOutboxDelete");
236
- yield* test.advance("10 days");
237
- expect(yield* test.receiptsFor(receiver.ref, "Receive")).toBe(1);
238
- expect(yield* test.inspect(sender.ref)).toMatchObject({ outbox: 1 });
239
- yield* test.cleanup;
240
- expect(yield* test.receiptsFor(receiver.ref, "Receive")).toBe(1);
241
- expect(yield* test.receiptsFor(bystander.ref, "Add")).toBe(0);
242
- yield* test.advance(CLAIM_LEASE);
243
- yield* test.cleanup;
244
- expect(yield* test.inspect(sender.ref)).toMatchObject({ outbox: 1 });
245
- yield* test.advance(CLAIM_LEASE);
246
- expect(fixture.receives - before).toBe(1);
247
- expect(yield* receiver.Total()).toBe(1);
248
- expect(yield* test.inspect(sender.ref)).toMatchObject({ outbox: 0 });
249
- yield* test.cleanup;
250
- expect(yield* test.receiptsFor(receiver.ref, "Receive")).toBe(0);
251
- })),
252
- },
253
- {
254
- name: "completes a command admitted before expiry when keepReceipts is shorter than the retry window",
255
- run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
256
- const test = yield* ActorTest;
257
- const brief = yield* Brief.get("short-horizon");
258
- const pause = yield* test.pauseNext("beforeHandler");
259
- yield* test.crashNext("beforeCommit");
260
- const now = yield* databaseTime;
261
- const id = `v1.${now - 59_500}.${now + 500}.2d1f6a3e-7b9c-4e21-8f0a-5c6d7e8f9a01`;
262
- const waiter = yield* brief
263
- .Tally(9)
264
- .pipe(Actor.commandId(id), Effect.flip, Effect.forkChild);
265
- yield* pause.reached;
266
- yield* Effect.sleep("550 millis");
267
- yield* pause.release;
268
- expect((yield* Fiber.join(waiter)).reason).toBeInstanceOf(CommandExpired);
269
- expect(yield* test.inspect(brief.ref)).toMatchObject({ state: { total: 9 }, receipts: 1 });
270
- yield* test.cleanup;
271
- expect(yield* test.inspect(brief.ref)).toMatchObject({ receipts: 1 });
272
- })),
273
- },
274
- {
275
- name: "prunes only an actor's oldest events, never resets the sequence, and reports the gap",
276
- run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
277
- const test = yield* ActorTest;
278
- const journal = yield* Journal.get("events");
279
- const chronicle = yield* Chronicle.get("events");
280
- yield* journal.Note("a");
281
- yield* journal.Note("b");
282
- yield* chronicle.Note("kept");
283
- yield* test.advance("2 days");
284
- yield* journal.Note("c");
285
- yield* test.cleanup;
286
- expect(yield* test.inspect(journal.ref)).toMatchObject({ events: 1 });
287
- expect(yield* test.inspect(chronicle.ref)).toMatchObject({ events: 1 });
288
- expect(yield* eventSequence("events")).toBe("3");
289
- expect(yield* journal.History({}).pipe(Effect.flip)).toEqual(RetentionGap.make({ cursor: "0" }));
290
- expect(yield* journal.History({ after: "1" }).pipe(Effect.flip)).toEqual(RetentionGap.make({ cursor: "1" }));
291
- expect(yield* journal.History({ after: "2" })).toEqual([{ cursor: "3", body: "c" }]);
292
- yield* journal.Note("d");
293
- expect(cursors(yield* journal.History({ after: "2" }))).toEqual(["3", "4"]);
294
- expect(yield* eventSequence("events")).toBe("4");
295
- })),
296
- },
297
- {
298
- name: "prunes events as a prefix even when a later event carries an older timestamp",
299
- run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
300
- const test = yield* ActorTest;
301
- const sql = yield* SqlClient.SqlClient;
302
- const journal = yield* Journal.get("skewed");
303
- for (const body of ["a", "b", "c", "d"])
304
- yield* journal.Note(body);
305
- yield* sql `UPDATE actor_events SET emitted_at_ms = emitted_at_ms - 172800000
306
- WHERE tenant_id = ${test.tenant} AND actor_type = 'Journal' AND actor_id = 'skewed' AND sequence = 3`;
307
- yield* test.cleanup;
308
- expect(yield* test.inspect(journal.ref)).toMatchObject({ events: 1 });
309
- expect(yield* journal.History({ after: "3" })).toEqual([{ cursor: "4", body: "d" }]);
310
- expect(yield* journal.History({ after: "2" }).pipe(Effect.flip)).toEqual(RetentionGap.make({ cursor: "2" }));
311
- })),
312
- },
313
- {
314
- name: "sweeps in batches that each leave a whole prefix",
315
- run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
316
- const test = yield* ActorTest;
317
- const journal = yield* Journal.get("batched");
318
- yield* journal.NoteMany({ count: 2_500, bytes: 1 });
319
- yield* test.advance("2 days");
320
- yield* journal.Note("fresh");
321
- yield* test.cleanup;
322
- expect(yield* test.inspect(journal.ref)).toMatchObject({ events: 1 });
323
- expect(yield* journal.History({ after: "2500" })).toEqual([
324
- { cursor: "2501", body: "fresh" },
325
- ]);
326
- expect(yield* eventSequence("batched")).toBe("2501");
327
- })),
328
- },
329
- {
330
- name: "pages event replay by limit and continues after the last cursor",
331
- run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
332
- const journal = yield* Journal.get("paged");
333
- yield* journal.NoteMany({ count: 1_205, bytes: 1 });
334
- const first = yield* journal.History({});
335
- expect(first.length).toBe(1_000);
336
- expect(first.at(-1).cursor).toBe("1000");
337
- expect((yield* journal.History({ after: "1000" })).length).toBe(205);
338
- const small = yield* journal.History({ after: "10", limit: 3 });
339
- expect(cursors(small)).toEqual(["11", "12", "13"]);
340
- expect(cursors(yield* journal.History({ after: "1203", limit: 3 }))).toEqual([
341
- "1204",
342
- "1205",
343
- ]);
344
- expect(yield* journal.History({ after: "1205", limit: 3 })).toEqual([]);
345
- for (const limit of [0, 10_001, 1.5])
346
- expect(defect(yield* journal.History({ limit }).pipe(Effect.exit))).toContain("read.events limit must be an integer from 1 to 10000");
347
- })),
348
- },
349
- {
350
- name: "fails a turn whose emits exceed the per-turn byte budget and commits none of them",
351
- run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
352
- const test = yield* ActorTest;
353
- const journal = yield* Journal.get("budget");
354
- yield* journal.NoteMany({ count: 2, bytes: 500_000 });
355
- expect(yield* test.inspect(journal.ref)).toMatchObject({ events: 2, receipts: 1 });
356
- expect(defect(yield* journal.NoteMany({ count: 3, bytes: 500_000 }).pipe(Effect.exit))).toContain("Events emitted in one turn exceed 1048576 bytes");
357
- expect(yield* test.inspect(journal.ref)).toMatchObject({ events: 2, receipts: 1 });
358
- expect(yield* eventSequence("budget")).toBe("2");
359
- })),
360
- },
361
- {
362
- name: "refuses blob writes past policy.maxBlobBytes and leaves the entry whole",
363
- run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
364
- const test = yield* ActorTest;
365
- const journal = yield* Journal.get("quota");
366
- yield* journal.Put({ name: "a", bytes: 600 });
367
- yield* journal.Grow({ name: "b", bytes: 200 });
368
- yield* journal.Grow({ name: "b", bytes: 200 });
369
- expect(defect(yield* journal.Grow({ name: "b", bytes: 25 }).pipe(Effect.exit))).toContain("One actor's blobs hold at most 1024 bytes (policy.maxBlobBytes)");
370
- expect(defect(yield* journal.Put({ name: "c", bytes: 25 }).pipe(Effect.exit))).toContain("policy.maxBlobBytes");
371
- yield* journal.Put({ name: "a", bytes: 624 });
372
- expect(yield* journal.Size("a")).toBe(624);
373
- expect(yield* journal.PutCaught({ name: "b", bytes: 500 })).toBe(false);
374
- expect(yield* journal.Size("b")).toBe(400);
375
- expect(yield* journal.PutCaught({ name: "b", bytes: 100 })).toBe(true);
376
- expect(yield* journal.Size("b")).toBe(100);
377
- expect(yield* test.inspect(journal.ref)).toMatchObject({ blobs: { files: 2 } });
378
- })),
379
- },
380
- {
381
- name: "refuses a new blob entry past policy.maxBlobEntries and frees one on delete",
382
- run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
383
- const test = yield* ActorTest;
384
- const journal = yield* Journal.get("entries");
385
- yield* journal.Put({ name: "a", bytes: 0 });
386
- yield* journal.Put({ name: "b", bytes: 0 });
387
- yield* journal.Grow({ name: "c", bytes: 0 });
388
- expect(defect(yield* journal.Put({ name: "d", bytes: 0 }).pipe(Effect.exit))).toContain("One actor's blobs hold at most 3 entries (policy.maxBlobEntries)");
389
- expect(defect(yield* journal.Grow({ name: "d", bytes: 1 }).pipe(Effect.exit))).toContain("policy.maxBlobEntries");
390
- expect(yield* journal.PutCaught({ name: "d", bytes: 1 })).toBe(false);
391
- expect(yield* journal.Size("d")).toBe(-1);
392
- yield* journal.Put({ name: "a", bytes: 10 });
393
- yield* journal.Grow({ name: "b", bytes: 5 });
394
- yield* journal.Grow({ name: "b", bytes: 5 });
395
- expect([yield* journal.Size("a"), yield* journal.Size("b")]).toEqual([10, 10]);
396
- expect(yield* test.inspect(journal.ref)).toMatchObject({ blobs: { files: 3 } });
397
- yield* journal.Drop("b");
398
- yield* journal.Drop("missing");
399
- expect(yield* journal.Size("b")).toBe(-1);
400
- yield* journal.Put({ name: "d", bytes: 4 });
401
- expect(yield* journal.Size("d")).toBe(4);
402
- expect(yield* test.inspect(journal.ref)).toMatchObject({ blobs: { files: 3 } });
403
- })),
404
- },
405
- {
406
- name: "rejects a retry admitted before expiry when cleanup pruned the receipt before its turn",
407
- requiresFreshDatabase: true,
408
- requiresIndependentConnections: true,
409
- timeoutMs: 20_000,
410
- run: ({ expect, environment, fixture }) => isolated(environment, Effect.gen(function* () {
411
- const test = yield* ActorTest;
412
- const journal = yield* Journal.get("race");
413
- const before = fixture.adds;
414
- const now = yield* databaseTime;
415
- const id = `v1.${now - 58_500}.${now + 1_500}.0c2f3a55-5b8e-4d53-9a51-1f7b3d9f0c11`;
416
- const committing = yield* test.pauseNext("beforeCommit");
417
- const first = yield* journal.Add(1).pipe(Actor.commandId(id), Effect.forkChild);
418
- yield* committing.reached;
419
- const delivering = yield* test.pauseNext("beforeDelivery");
420
- const retry = yield* journal
421
- .Add(1)
422
- .pipe(Actor.commandId(id), Effect.flip, Effect.forkChild);
423
- yield* delivering.reached;
424
- yield* committing.release;
425
- expect(yield* Fiber.join(first)).toBe(1);
426
- yield* test.advance("3 days");
427
- yield* test.cleanup;
428
- expect(yield* test.inspect(journal.ref)).toMatchObject({ receipts: 0 });
429
- yield* delivering.release;
430
- const failure = yield* Fiber.join(retry);
431
- expect(Schema.is(ActorError)(failure) && failure.reason).toBeInstanceOf(CommandExpired);
432
- expect(fixture.adds - before).toBe(1);
433
- expect(yield* journal.Total()).toBe(1);
434
- })),
435
- },
436
- {
437
- name: "cancels a query read past commandTimeout on the server",
438
- requiresIndependentConnections: true,
439
- timeoutMs: 20_000,
440
- run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
441
- const journal = yield* Journal.get("slow-read");
442
- yield* journal.Add(1);
443
- const connect = environment.connect;
444
- const locker = yield* connect;
445
- yield* locker.query("BEGIN");
446
- yield* locker.query("LOCK TABLE actor_state IN ACCESS EXCLUSIVE MODE");
447
- const started = yield* Clock.currentTimeMillis;
448
- const failure = yield* journal.Total().pipe(Effect.flip);
449
- expect(failure.reason).toBeInstanceOf(Timeout);
450
- expect((yield* Clock.currentTimeMillis) - started < 10_000).toBe(true);
451
- const waiting = yield* locker.query(`SELECT count(*)::int AS waiting FROM pg_stat_activity
452
- WHERE datname = current_database() AND wait_event_type = 'Lock' AND pid <> pg_backend_pid()`);
453
- expect(waiting).toEqual([{ waiting: 0 }]);
454
- yield* locker.query("ROLLBACK");
455
- expect(yield* journal.Total()).toBe(1);
456
- })),
457
- },
458
- ];
459
- /** Retention actors. */
460
- export const retentionSuite = {
461
- fixture: retentionFixture,
462
- layer: retentionLayer,
463
- };
@@ -1,24 +0,0 @@
1
- import { PGlite } from "@electric-sql/pglite";
2
- import { Crypto, Effect, Redacted, Scope } from "effect";
3
- import type { ConformanceCase, ConformanceEnvironment } from "../conformance.ts";
4
- /**
5
- * The operator script of the row-level security guide: a tenant role the
6
- * runtime takes for tenant-scoped transactions, and a separate view-owner role
7
- * the policies bind, which the tenant role can't act as.
8
- */
9
- export declare const grants: ({ role, viewOwner, }: {
10
- readonly role: string;
11
- readonly viewOwner: string;
12
- }) => string[];
13
- type Target = Redacted.Redacted<string> | {
14
- readonly liveClient: PGlite;
15
- };
16
- /** A fresh database for `environment`, migrated with the owned tables and a new tenant role, as row-level security cases need. */
17
- export declare const preparedForRowLevelSecurity: (environment: ConformanceEnvironment) => Effect.Effect<{
18
- target: Target;
19
- role: string;
20
- viewOwner: string;
21
- }, never, Crypto.Crypto | Scope.Scope>;
22
- /** Row-level-security cases: every framework and owned table carries the tenant policy, and runners serving two tenants each see only their own rows. */
23
- export declare const rlsConformance: ReadonlyArray<ConformanceCase>;
24
- export {};