@smthrs/journal 0.0.0-stage → 1.0.0-rc.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 (257) hide show
  1. package/CHANGELOG.md +149 -0
  2. package/LICENSE +21 -0
  3. package/README.md +206 -2
  4. package/dist/cjs/CallFact.d.ts +129 -0
  5. package/dist/cjs/CallFact.d.ts.map +1 -0
  6. package/dist/cjs/CallFact.js +106 -0
  7. package/dist/cjs/CallFact.js.map +7 -0
  8. package/dist/cjs/Consensus.d.ts +440 -0
  9. package/dist/cjs/Consensus.d.ts.map +1 -0
  10. package/dist/cjs/Consensus.js +251 -0
  11. package/dist/cjs/Consensus.js.map +7 -0
  12. package/dist/cjs/EngineEvent.d.ts +890 -0
  13. package/dist/cjs/EngineEvent.d.ts.map +1 -0
  14. package/dist/cjs/EngineEvent.js +383 -0
  15. package/dist/cjs/EngineEvent.js.map +7 -0
  16. package/dist/cjs/ExecutionFact.d.ts +216 -0
  17. package/dist/cjs/ExecutionFact.d.ts.map +1 -0
  18. package/dist/cjs/ExecutionFact.js +303 -0
  19. package/dist/cjs/ExecutionFact.js.map +7 -0
  20. package/dist/cjs/Journal.d.ts +617 -0
  21. package/dist/cjs/Journal.d.ts.map +1 -0
  22. package/dist/cjs/Journal.js +190 -0
  23. package/dist/cjs/Journal.js.map +7 -0
  24. package/dist/cjs/JournalEvent.d.ts +421 -0
  25. package/dist/cjs/JournalEvent.d.ts.map +1 -0
  26. package/dist/cjs/JournalEvent.js +281 -0
  27. package/dist/cjs/JournalEvent.js.map +7 -0
  28. package/dist/cjs/JournalGeneration.d.ts +34 -0
  29. package/dist/cjs/JournalGeneration.d.ts.map +1 -0
  30. package/dist/cjs/JournalGeneration.js +72 -0
  31. package/dist/cjs/JournalGeneration.js.map +7 -0
  32. package/dist/cjs/JournalMetrics.d.ts +72 -0
  33. package/dist/cjs/JournalMetrics.d.ts.map +1 -0
  34. package/dist/cjs/JournalMetrics.js +55 -0
  35. package/dist/cjs/JournalMetrics.js.map +7 -0
  36. package/dist/cjs/Migrations.d.ts +42 -0
  37. package/dist/cjs/Migrations.d.ts.map +1 -0
  38. package/dist/cjs/Migrations.js +58 -0
  39. package/dist/cjs/Migrations.js.map +7 -0
  40. package/dist/cjs/OwnerId.d.ts +40 -0
  41. package/dist/cjs/OwnerId.d.ts.map +1 -0
  42. package/dist/cjs/OwnerId.js +40 -0
  43. package/dist/cjs/OwnerId.js.map +7 -0
  44. package/dist/cjs/Projection.d.ts +29 -0
  45. package/dist/cjs/Projection.d.ts.map +1 -0
  46. package/dist/cjs/Projection.js +25 -0
  47. package/dist/cjs/Projection.js.map +7 -0
  48. package/dist/cjs/RedactedLogger.d.ts +121 -0
  49. package/dist/cjs/RedactedLogger.d.ts.map +1 -0
  50. package/dist/cjs/RedactedLogger.js +235 -0
  51. package/dist/cjs/RedactedLogger.js.map +7 -0
  52. package/dist/cjs/Redaction.d.ts +350 -0
  53. package/dist/cjs/Redaction.d.ts.map +1 -0
  54. package/dist/cjs/Redaction.js +928 -0
  55. package/dist/cjs/Redaction.js.map +7 -0
  56. package/dist/cjs/SqlConsensus.d.ts +44 -0
  57. package/dist/cjs/SqlConsensus.d.ts.map +1 -0
  58. package/dist/cjs/SqlConsensus.js +243 -0
  59. package/dist/cjs/SqlConsensus.js.map +7 -0
  60. package/dist/cjs/SqlJournal.d.ts +173 -0
  61. package/dist/cjs/SqlJournal.d.ts.map +1 -0
  62. package/dist/cjs/SqlJournal.js +1568 -0
  63. package/dist/cjs/SqlJournal.js.map +7 -0
  64. package/dist/cjs/StepFact.d.ts +66 -0
  65. package/dist/cjs/StepFact.d.ts.map +1 -0
  66. package/dist/cjs/StepFact.js +68 -0
  67. package/dist/cjs/StepFact.js.map +7 -0
  68. package/dist/cjs/index.d.ts +95 -0
  69. package/dist/cjs/index.d.ts.map +1 -0
  70. package/dist/cjs/index.js +63 -0
  71. package/dist/cjs/index.js.map +7 -0
  72. package/dist/cjs/internal/JournalInternalFault.d.ts +37 -0
  73. package/dist/cjs/internal/JournalInternalFault.d.ts.map +1 -0
  74. package/dist/cjs/internal/JournalInternalFault.js +43 -0
  75. package/dist/cjs/internal/JournalInternalFault.js.map +7 -0
  76. package/dist/cjs/migrations/0001_initial.d.ts +15 -0
  77. package/dist/cjs/migrations/0001_initial.d.ts.map +1 -0
  78. package/dist/cjs/migrations/0001_initial.js +54 -0
  79. package/dist/cjs/migrations/0001_initial.js.map +7 -0
  80. package/dist/cjs/migrations/0002_checkpoints.d.ts +27 -0
  81. package/dist/cjs/migrations/0002_checkpoints.d.ts.map +1 -0
  82. package/dist/cjs/migrations/0002_checkpoints.js +48 -0
  83. package/dist/cjs/migrations/0002_checkpoints.js.map +7 -0
  84. package/dist/cjs/migrations/0003_startup_index.d.ts +15 -0
  85. package/dist/cjs/migrations/0003_startup_index.d.ts.map +1 -0
  86. package/dist/cjs/migrations/0003_startup_index.js +40 -0
  87. package/dist/cjs/migrations/0003_startup_index.js.map +7 -0
  88. package/dist/cjs/migrations/0004_dedup.d.ts +15 -0
  89. package/dist/cjs/migrations/0004_dedup.d.ts.map +1 -0
  90. package/dist/cjs/migrations/0004_dedup.js +57 -0
  91. package/dist/cjs/migrations/0004_dedup.js.map +7 -0
  92. package/dist/cjs/migrations/0005_run_event_type.d.ts +15 -0
  93. package/dist/cjs/migrations/0005_run_event_type.d.ts.map +1 -0
  94. package/dist/cjs/migrations/0005_run_event_type.js +40 -0
  95. package/dist/cjs/migrations/0005_run_event_type.js.map +7 -0
  96. package/dist/cjs/migrations/0006_consensus.d.ts +22 -0
  97. package/dist/cjs/migrations/0006_consensus.d.ts.map +1 -0
  98. package/dist/cjs/migrations/0006_consensus.js +84 -0
  99. package/dist/cjs/migrations/0006_consensus.js.map +7 -0
  100. package/dist/cjs/package.json +1 -0
  101. package/dist/cjs/test/Notifying.d.ts +65 -0
  102. package/dist/cjs/test/Notifying.d.ts.map +1 -0
  103. package/dist/cjs/test/Notifying.js +62 -0
  104. package/dist/cjs/test/Notifying.js.map +7 -0
  105. package/dist/cjs/test/TestJournal.d.ts +43 -0
  106. package/dist/cjs/test/TestJournal.d.ts.map +1 -0
  107. package/dist/cjs/test/TestJournal.js +43 -0
  108. package/dist/cjs/test/TestJournal.js.map +7 -0
  109. package/dist/esm/CallFact.d.ts +129 -0
  110. package/dist/esm/CallFact.d.ts.map +1 -0
  111. package/dist/esm/CallFact.js +96 -0
  112. package/dist/esm/CallFact.js.map +1 -0
  113. package/dist/esm/Consensus.d.ts +440 -0
  114. package/dist/esm/Consensus.d.ts.map +1 -0
  115. package/dist/esm/Consensus.js +454 -0
  116. package/dist/esm/Consensus.js.map +1 -0
  117. package/dist/esm/EngineEvent.d.ts +890 -0
  118. package/dist/esm/EngineEvent.d.ts.map +1 -0
  119. package/dist/esm/EngineEvent.js +614 -0
  120. package/dist/esm/EngineEvent.js.map +1 -0
  121. package/dist/esm/ExecutionFact.d.ts +216 -0
  122. package/dist/esm/ExecutionFact.d.ts.map +1 -0
  123. package/dist/esm/ExecutionFact.js +374 -0
  124. package/dist/esm/ExecutionFact.js.map +1 -0
  125. package/dist/esm/Journal.d.ts +617 -0
  126. package/dist/esm/Journal.d.ts.map +1 -0
  127. package/dist/esm/Journal.js +323 -0
  128. package/dist/esm/Journal.js.map +1 -0
  129. package/dist/esm/JournalEvent.d.ts +421 -0
  130. package/dist/esm/JournalEvent.d.ts.map +1 -0
  131. package/dist/esm/JournalEvent.js +517 -0
  132. package/dist/esm/JournalEvent.js.map +1 -0
  133. package/dist/esm/JournalGeneration.d.ts +34 -0
  134. package/dist/esm/JournalGeneration.d.ts.map +1 -0
  135. package/dist/esm/JournalGeneration.js +65 -0
  136. package/dist/esm/JournalGeneration.js.map +1 -0
  137. package/dist/esm/JournalMetrics.d.ts +72 -0
  138. package/dist/esm/JournalMetrics.d.ts.map +1 -0
  139. package/dist/esm/JournalMetrics.js +79 -0
  140. package/dist/esm/JournalMetrics.js.map +1 -0
  141. package/dist/esm/Migrations.d.ts +42 -0
  142. package/dist/esm/Migrations.d.ts.map +1 -0
  143. package/dist/esm/Migrations.js +59 -0
  144. package/dist/esm/Migrations.js.map +1 -0
  145. package/dist/esm/OwnerId.d.ts +40 -0
  146. package/dist/esm/OwnerId.d.ts.map +1 -0
  147. package/dist/esm/OwnerId.js +33 -0
  148. package/dist/esm/OwnerId.js.map +1 -0
  149. package/dist/esm/Projection.d.ts +29 -0
  150. package/dist/esm/Projection.d.ts.map +1 -0
  151. package/dist/esm/Projection.js +13 -0
  152. package/dist/esm/Projection.js.map +1 -0
  153. package/dist/esm/RedactedLogger.d.ts +121 -0
  154. package/dist/esm/RedactedLogger.d.ts.map +1 -0
  155. package/dist/esm/RedactedLogger.js +445 -0
  156. package/dist/esm/RedactedLogger.js.map +1 -0
  157. package/dist/esm/Redaction.d.ts +350 -0
  158. package/dist/esm/Redaction.d.ts.map +1 -0
  159. package/dist/esm/Redaction.js +1584 -0
  160. package/dist/esm/Redaction.js.map +1 -0
  161. package/dist/esm/SqlConsensus.d.ts +44 -0
  162. package/dist/esm/SqlConsensus.d.ts.map +1 -0
  163. package/dist/esm/SqlConsensus.js +252 -0
  164. package/dist/esm/SqlConsensus.js.map +1 -0
  165. package/dist/esm/SqlJournal.d.ts +173 -0
  166. package/dist/esm/SqlJournal.d.ts.map +1 -0
  167. package/dist/esm/SqlJournal.js +1858 -0
  168. package/dist/esm/SqlJournal.js.map +1 -0
  169. package/dist/esm/StepFact.d.ts +66 -0
  170. package/dist/esm/StepFact.d.ts.map +1 -0
  171. package/dist/esm/StepFact.js +50 -0
  172. package/dist/esm/StepFact.js.map +1 -0
  173. package/dist/esm/index.d.ts +95 -0
  174. package/dist/esm/index.d.ts.map +1 -0
  175. package/dist/esm/index.js +95 -0
  176. package/dist/esm/index.js.map +1 -0
  177. package/dist/esm/internal/JournalInternalFault.d.ts +37 -0
  178. package/dist/esm/internal/JournalInternalFault.d.ts.map +1 -0
  179. package/dist/esm/internal/JournalInternalFault.js +28 -0
  180. package/dist/esm/internal/JournalInternalFault.js.map +1 -0
  181. package/dist/esm/migrations/0001_initial.d.ts +15 -0
  182. package/dist/esm/migrations/0001_initial.d.ts.map +1 -0
  183. package/dist/esm/migrations/0001_initial.js +32 -0
  184. package/dist/esm/migrations/0001_initial.js.map +1 -0
  185. package/dist/esm/migrations/0002_checkpoints.d.ts +27 -0
  186. package/dist/esm/migrations/0002_checkpoints.d.ts.map +1 -0
  187. package/dist/esm/migrations/0002_checkpoints.js +38 -0
  188. package/dist/esm/migrations/0002_checkpoints.js.map +1 -0
  189. package/dist/esm/migrations/0003_startup_index.d.ts +15 -0
  190. package/dist/esm/migrations/0003_startup_index.d.ts.map +1 -0
  191. package/dist/esm/migrations/0003_startup_index.js +18 -0
  192. package/dist/esm/migrations/0003_startup_index.js.map +1 -0
  193. package/dist/esm/migrations/0004_dedup.d.ts +15 -0
  194. package/dist/esm/migrations/0004_dedup.d.ts.map +1 -0
  195. package/dist/esm/migrations/0004_dedup.js +38 -0
  196. package/dist/esm/migrations/0004_dedup.js.map +1 -0
  197. package/dist/esm/migrations/0005_run_event_type.d.ts +15 -0
  198. package/dist/esm/migrations/0005_run_event_type.d.ts.map +1 -0
  199. package/dist/esm/migrations/0005_run_event_type.js +18 -0
  200. package/dist/esm/migrations/0005_run_event_type.js.map +1 -0
  201. package/dist/esm/migrations/0006_consensus.d.ts +22 -0
  202. package/dist/esm/migrations/0006_consensus.d.ts.map +1 -0
  203. package/dist/esm/migrations/0006_consensus.js +69 -0
  204. package/dist/esm/migrations/0006_consensus.js.map +1 -0
  205. package/dist/esm/test/Notifying.d.ts +65 -0
  206. package/dist/esm/test/Notifying.d.ts.map +1 -0
  207. package/dist/esm/test/Notifying.js +62 -0
  208. package/dist/esm/test/Notifying.js.map +1 -0
  209. package/dist/esm/test/TestJournal.d.ts +43 -0
  210. package/dist/esm/test/TestJournal.d.ts.map +1 -0
  211. package/dist/esm/test/TestJournal.js +27 -0
  212. package/dist/esm/test/TestJournal.js.map +1 -0
  213. package/docs/README.md +164 -0
  214. package/docs/api.md +639 -0
  215. package/docs/concepts/compaction.md +157 -0
  216. package/docs/concepts/idempotency.md +127 -0
  217. package/docs/concepts/owner-fence.md +124 -0
  218. package/docs/concepts/redaction.md +218 -0
  219. package/docs/concepts/state-event-authority.md +159 -0
  220. package/docs/concepts/two-channels.md +167 -0
  221. package/docs/guides/commit-state-and-entry.md +114 -0
  222. package/docs/guides/compact-a-run.md +134 -0
  223. package/docs/guides/fold-a-projection.md +106 -0
  224. package/docs/guides/read-a-run.md +139 -0
  225. package/docs/guides/redact-log-output.md +94 -0
  226. package/docs/guides/testing.md +124 -0
  227. package/docs/guides/write-lifecycle-events.md +110 -0
  228. package/docs/installation.md +133 -0
  229. package/docs/quickstart.md +143 -0
  230. package/docs/troubleshooting.md +214 -0
  231. package/package.json +263 -3
  232. package/src/CallFact.ts +117 -0
  233. package/src/Consensus.ts +683 -0
  234. package/src/EngineEvent.ts +823 -0
  235. package/src/ExecutionFact.ts +433 -0
  236. package/src/Journal.ts +688 -0
  237. package/src/JournalEvent.ts +654 -0
  238. package/src/JournalGeneration.ts +77 -0
  239. package/src/JournalMetrics.ts +89 -0
  240. package/src/Migrations.ts +62 -0
  241. package/src/OwnerId.ts +42 -0
  242. package/src/Projection.ts +31 -0
  243. package/src/RedactedLogger.ts +483 -0
  244. package/src/Redaction.ts +1784 -0
  245. package/src/SqlConsensus.ts +344 -0
  246. package/src/SqlJournal.ts +2732 -0
  247. package/src/StepFact.ts +69 -0
  248. package/src/index.ts +109 -0
  249. package/src/internal/JournalInternalFault.ts +40 -0
  250. package/src/migrations/0001_initial.ts +41 -0
  251. package/src/migrations/0002_checkpoints.ts +46 -0
  252. package/src/migrations/0003_startup_index.ts +19 -0
  253. package/src/migrations/0004_dedup.ts +43 -0
  254. package/src/migrations/0005_run_event_type.ts +19 -0
  255. package/src/migrations/0006_consensus.ts +83 -0
  256. package/src/test/Notifying.ts +101 -0
  257. package/src/test/TestJournal.ts +52 -0
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Durable generations distinguish histories that reuse journal sequences.
3
+ *
4
+ * @since 1.0.0-rc.0
5
+ */
6
+
7
+ import * as Dialect from "@smthrs/database/Dialect"
8
+ import * as Effect from "effect/Effect"
9
+ import * as SqlClient from "effect/unstable/sql/SqlClient"
10
+
11
+ /**
12
+ * Installs the generation table idempotently. Both the SQL journal and time
13
+ * travel initialize it, including databases whose migration ladder already
14
+ * passed the journal's reserved block. A read-only client installs nothing.
15
+ *
16
+ * @category migrations
17
+ * @since 1.0.0-rc.0
18
+ */
19
+ export const initialize = Effect.gen(function*() {
20
+ const sql = yield* SqlClient.SqlClient
21
+ // A read-only observer reads the schema it finds and installs nothing.
22
+ if (Dialect.isReadOnly(sql)) return
23
+ yield* sql`
24
+ CREATE TABLE IF NOT EXISTS flows_journal_generations (
25
+ run_id TEXT PRIMARY KEY NOT NULL CHECK (length(run_id) > 0),
26
+ generation ${Dialect.integer(sql)} NOT NULL CHECK (${
27
+ Dialect.isInteger(sql, sql`generation`)
28
+ } AND generation > 0 AND generation <= 9007199254740991),
29
+ after_seq ${Dialect.integer(sql)} NOT NULL CHECK (${
30
+ Dialect.isInteger(sql, sql`after_seq`)
31
+ } AND after_seq >= -1 AND after_seq <= 9007199254740991)
32
+ )
33
+ `
34
+ })
35
+
36
+ const journals = new WeakMap<SqlClient.SqlClient, Set<(runIds: ReadonlyArray<string>) => void>>()
37
+
38
+ /**
39
+ * Registers a live journal's cache invalidation until its scope closes.
40
+ * Multiple journals over the same SQL client must observe the same rewind.
41
+ *
42
+ * @category lifecycle
43
+ * @since 1.0.0-rc.0
44
+ */
45
+ export const onTruncate = (forget: (runIds: ReadonlyArray<string>) => void) =>
46
+ Effect.gen(function*() {
47
+ const sql = yield* SqlClient.SqlClient
48
+ let listeners = journals.get(sql)
49
+ if (listeners === undefined) {
50
+ listeners = new Set()
51
+ journals.set(sql, listeners)
52
+ }
53
+ const registered = listeners
54
+ yield* Effect.acquireRelease(
55
+ Effect.sync(() => registered.add(forget)),
56
+ () =>
57
+ Effect.sync(() => {
58
+ registered.delete(forget)
59
+ })
60
+ )
61
+ })
62
+
63
+ /**
64
+ * Forgets cached identities and allocation floors after a committed truncation.
65
+ * The rewinder must quiesce producers and flush pending admissions first.
66
+ * Database rows remain authoritative; this operation changes no durable data.
67
+ *
68
+ * @category lifecycle
69
+ * @since 1.0.0-rc.0
70
+ */
71
+ export const forget = (runIds: ReadonlyArray<string>) =>
72
+ Effect.gen(function*() {
73
+ const sql = yield* SqlClient.SqlClient
74
+ yield* Effect.sync(() => {
75
+ for (const invalidate of journals.get(sql) ?? []) invalidate(runIds)
76
+ })
77
+ })
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Standard metric definitions for the journal write path.
3
+ *
4
+ * This module only defines the metric handles, following the shape of Effect's
5
+ * `ClusterMetrics`. `SqlJournal` updates them as emission receipts are
6
+ * produced, so the counters measure admissions on the hot path rather than
7
+ * rows read back. No exporter ships in this package; provide one, for
8
+ * example `@smthrs/observability`, and these counters appear in it.
9
+ *
10
+ * @since 0.1.0
11
+ */
12
+
13
+ import * as Metric from "effect/Metric"
14
+
15
+ /**
16
+ * Counter over journal emissions, dimensioned by `channel` (`durable` or
17
+ * `lossy`) and `receipt` (`accepted`, `duplicate`, or `dropped`).
18
+ *
19
+ * **Details**
20
+ *
21
+ * A `durable` emission counts when its receipt is produced, which is after the
22
+ * write transaction returned; under `Journal.transact` that is still inside
23
+ * the caller's transaction, so a receipt that later rolls back with the
24
+ * enclosing transaction has already counted. The counter is throughput
25
+ * evidence, not commit evidence: the journal rows themselves are the latter.
26
+ *
27
+ * @category metrics
28
+ * @since 0.1.0
29
+ */
30
+ export const writes = Metric.counter("flows_journal_writes", {
31
+ description: "Journal emissions by channel and receipt"
32
+ })
33
+
34
+ /**
35
+ * `writes` views for the durable channel, keyed by the receipt tag
36
+ * `Journal.emitDurable` resolves to.
37
+ *
38
+ * @category metrics
39
+ * @since 0.1.0
40
+ */
41
+ export const durable: {
42
+ readonly [Tag in "Accepted" | "Duplicate"]: Metric.Metric<number, Metric.CounterState<number>>
43
+ } = {
44
+ Accepted: Metric.withAttributes(writes, { channel: "durable", receipt: "accepted" }),
45
+ Duplicate: Metric.withAttributes(writes, { channel: "durable", receipt: "duplicate" })
46
+ }
47
+
48
+ /**
49
+ * `writes` views for the lossy channel, keyed by the receipt tag
50
+ * `Journal.emitLossy` resolves to.
51
+ *
52
+ * @category metrics
53
+ * @since 0.1.0
54
+ */
55
+ export const lossy: {
56
+ readonly [Tag in "Accepted" | "Duplicate" | "Dropped"]: Metric.Metric<number, Metric.CounterState<number>>
57
+ } = {
58
+ Accepted: Metric.withAttributes(writes, { channel: "lossy", receipt: "accepted" }),
59
+ Duplicate: Metric.withAttributes(writes, { channel: "lossy", receipt: "duplicate" }),
60
+ Dropped: Metric.withAttributes(writes, { channel: "lossy", receipt: "dropped" })
61
+ }
62
+
63
+ /**
64
+ * Counter over lossy entries the writer admitted and then failed to commit,
65
+ * dimensioned by `channel` (always `lossy`) and the `code` of the
66
+ * `JournalError` that lost them.
67
+ *
68
+ * **Details**
69
+ *
70
+ * A lossy producer rarely calls `flush`, so the failure `flush` reports is not
71
+ * where an operator learns about a lost batch. This counter moves by the number
72
+ * of entries lost the moment the writer gives them up, whether or not anyone
73
+ * is waiting on them.
74
+ *
75
+ * @category metrics
76
+ * @since 1.0.0-rc.1
77
+ */
78
+ export const lostEntries = Metric.counter("flows_journal_lost", {
79
+ description: "Admitted lossy journal entries the writer failed to commit"
80
+ })
81
+
82
+ /**
83
+ * The {@link lostEntries} view for one `JournalError` code.
84
+ *
85
+ * @category metrics
86
+ * @since 1.0.0-rc.1
87
+ */
88
+ export const lost = (code: string): Metric.Metric<number, Metric.CounterState<number>> =>
89
+ Metric.withAttributes(lostEntries, { channel: "lossy", code })
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Journal schema migrations.
3
+ *
4
+ * The journal owns four tables: `flows_journal_events` and its event-type
5
+ * index in `0001_initial`, `flows_journal_checkpoints` in
6
+ * `0002_checkpoints`, the bounded startup ordering index in
7
+ * `0003_startup_index`, compacted producer identities in `0004_dedup`, the
8
+ * per-run exact event-type cursor index in `0005_run_event_type`, and the
9
+ * `SqlConsensus` lease table `flows_consensus_leases` in `0006_consensus`. Run
10
+ * and attempt state migrate from `@smthrs/run-store`, the step cache from
11
+ * `@smthrs/step-cache`, and the durable deferred/clock tables from
12
+ * `@smthrs/engine-store`; an application composes those sets with this one
13
+ * through `@smthrs/database`'s `Migrations.layer`.
14
+ *
15
+ * @since 0.1.0
16
+ */
17
+
18
+ import * as DatabaseMigrations from "@smthrs/database/Migrations"
19
+ import * as Layer from "effect/Layer"
20
+ import { initial } from "./migrations/0001_initial.ts"
21
+ import { checkpoints } from "./migrations/0002_checkpoints.ts"
22
+ import { startupIndex } from "./migrations/0003_startup_index.ts"
23
+ import { dedup } from "./migrations/0004_dedup.ts"
24
+ import { runEventType } from "./migrations/0005_run_event_type.ts"
25
+ import { consensus } from "./migrations/0006_consensus.ts"
26
+
27
+ /**
28
+ * The journal's namespaced migration set, for composition with the other
29
+ * storage packages.
30
+ *
31
+ * @category migrations
32
+ * @since 0.1.0
33
+ */
34
+ export const set: DatabaseMigrations.MigrationSet = {
35
+ namespace: "journal",
36
+ idOffset: 0,
37
+ migrations: {
38
+ "0001_initial": initial,
39
+ "0002_checkpoints": checkpoints,
40
+ "0003_startup_index": startupIndex,
41
+ "0004_dedup": dedup,
42
+ "0005_run_event_type": runEventType,
43
+ "0006_consensus": consensus
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Creates the journal's authoritative durable schema.
49
+ *
50
+ * @category migrations
51
+ * @since 0.1.0
52
+ */
53
+ export const run = DatabaseMigrations.run([set])
54
+
55
+ /**
56
+ * Layer that runs journal migrations before exposing the database to journal
57
+ * services.
58
+ *
59
+ * @category layers
60
+ * @since 0.1.0
61
+ */
62
+ export const layer = Layer.effectDiscard(run)
package/src/OwnerId.ts ADDED
@@ -0,0 +1,42 @@
1
+ /**
2
+ * The fencing token the journal accepts on durable appends.
3
+ *
4
+ * `OwnerId` lives here rather than with the ownership *arbitration* in
5
+ * `@smthrs/run-store` because the journal is what it fences: `emitDurable`
6
+ * takes an owner and refuses the append when the persisted fence has moved on.
7
+ * The journal therefore defines the token, and the run store (which stores it
8
+ * on runs and arbitrates who holds it) imports it.
9
+ *
10
+ * @since 0.1.0
11
+ */
12
+
13
+ import * as Schema from "effect/Schema"
14
+
15
+ /**
16
+ * A process identity scoped to a host and a unique ownership nonce.
17
+ *
18
+ * `pid` is a real operating-system process id, so the schema states that: a
19
+ * non-negative integer. A fractional, `NaN`, or negative `pid` is a caller
20
+ * bug, and the fenced methods reject it as `invalid_event` rather than
21
+ * degrading it into `fence_lost`, which would read as "someone else owns this
22
+ * run" and send the caller looking for a race that never happened.
23
+ *
24
+ * `hostId` and `nonce` stay plain strings. An empty one is a legal value that
25
+ * simply matches no persisted owner, which is exactly `fence_lost`.
26
+ *
27
+ * @since 0.1.0
28
+ * @category models
29
+ */
30
+ export const OwnerId = Schema.Struct({
31
+ hostId: Schema.String,
32
+ pid: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),
33
+ nonce: Schema.String
34
+ })
35
+
36
+ /**
37
+ * A process identity scoped to a host and a unique ownership nonce.
38
+ *
39
+ * @since 0.1.0
40
+ * @category models
41
+ */
42
+ export type OwnerId = typeof OwnerId.Type
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Reproducible journal projections.
3
+ *
4
+ * @since 0.1.0
5
+ */
6
+
7
+ import type * as Effect from "effect/Effect"
8
+ import type { Entry } from "./JournalEvent.ts"
9
+
10
+ /**
11
+ * An effectful fold over committed journal entries.
12
+ *
13
+ * Projections have no independent durable state. Replaying the same entries
14
+ * through the same reducer must reproduce the same result.
15
+ *
16
+ * @category models
17
+ * @since 0.1.0
18
+ */
19
+ export interface Projection<S, E = never, R = never> {
20
+ readonly name: string
21
+ readonly initial: S
22
+ readonly reduce: (state: S, entry: Entry) => Effect.Effect<S, E, R>
23
+ }
24
+
25
+ /**
26
+ * Constructs a reproducible journal projection.
27
+ *
28
+ * @category constructors
29
+ * @since 0.1.0
30
+ */
31
+ export const make = <S, E = never, R = never>(projection: Projection<S, E, R>): Projection<S, E, R> => projection