@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
package/CHANGELOG.md ADDED
@@ -0,0 +1,149 @@
1
+ # @smthrs/journal
2
+
3
+ ## [Unreleased]
4
+
5
+ ### Fixed
6
+
7
+ - A lossy batch the writer fails to commit is logged and counted on the new
8
+ `flows_journal_lost` counter (`JournalMetrics.lostEntries`, `lost(code)`),
9
+ so telemetry lost with no `flush` caller is no longer silent. A final flush
10
+ that fails while the journal closes is logged instead of ignored.
11
+ - Migration `0003_startup_index` lives in `src/migrations/` beside the other
12
+ migrations instead of `src/internal/`.
13
+
14
+ - The migration modules `0001_initial` and `0002_checkpoints` export their
15
+ Effect as a named binding (`initial`, `checkpoints`) instead of a default
16
+ export, and `Migrations` imports them by name. The CommonJS build converts
17
+ each source file with esbuild in Node interop mode, where a default import
18
+ of a sibling module resolves to that module's whole exports object rather
19
+ than the Effect, so `Migrations.set.migrations["0001_initial"].pipe` was
20
+ undefined under `require` while the ESM build kept working.
21
+
22
+ ## [1.0.0-rc.0] - 2026-08-31
23
+
24
+ ### Breaking Changes
25
+
26
+ - The stores and `SqlJournal` now require Effect's `SqlClient` service plus
27
+ `DurableWriter` (the renamed `Database` service) instead of the bundled
28
+ `Database` service.
29
+ - `emitDurable`, `checkpoint`, and `compact` require a well-formed `OwnerId`.
30
+ An omitted, null, or malformed owner fails `invalid_event` instead of
31
+ silently selecting the unfenced write path. `emitDurableUnfenced` is the one
32
+ sanctioned ownerless admission.
33
+ - `JournalEvent.RunId`, `JournalEvent.SourceId`, and `Input.eventType` reject
34
+ the empty string and ill-formed UTF-16 at decode. SQLite binds a lone
35
+ surrogate as U+FFFD, so two distinct identifiers collapsed to one persisted
36
+ key and destroyed run isolation.
37
+ - `JournalEvent.RunId`, `JournalEvent.SourceId`, and `Input.eventType` are
38
+ limited to 1,024 UTF-16 code units. `Seq` and `SourceSeq` exclude
39
+ `Number.MAX_SAFE_INTEGER`, whose successor is not a distinct integer the
40
+ journal can allocate.
41
+ - `EntriesOptions.limit` and the `entries` service reject pages above 10,000
42
+ entries, which would otherwise be decoded into memory in full.
43
+ - `OwnerId.pid` is a non-negative integer. A fractional, `NaN`, or negative
44
+ pid used to degrade into `fence_lost`, which reads as "someone else owns
45
+ this run" and sends the caller hunting a race that never happened.
46
+ - Durable read failures report the new `read_failed` code instead of `unknown`,
47
+ which is now reserved for a genuinely unclassified journal defect.
48
+ - `payload` and `meta` are encoded with sorted object keys, so producer
49
+ idempotency compares JSON values rather than one serialization of them. The
50
+ sort runs over the ENCODED JSON, so the persisted bytes keep every
51
+ `JSON.stringify` semantic.
52
+ - `JournalEvent.Entry.eventType` uses the same bounded identifier as
53
+ `Input.eventType`. It was a bare `Schema.String`, so a consumer decoding a
54
+ committed row accepted event types no emit could have produced.
55
+ - Every identifier rejects NUL. SQLite's `length()` stops at the first one, so
56
+ the column's own non-empty check failed and the caller was told `sink_failed`
57
+ about an identifier it had just supplied.
58
+ - `entries`, `stream`, `checkpoint`, `latestCheckpoint`, and `compact` decode
59
+ the schemas this package publishes instead of hand-checking a subset of them.
60
+ A lone-surrogate run id was refused at `emit` and answered with an empty page
61
+ at `entries`.
62
+
63
+ ### Added
64
+
65
+ - `emitDurableUnfenced`, `checkpoint`, `latestCheckpoint`, `compact`, the
66
+ `Checkpoint` and `Compacted` model, and `SqlJournal.CompactionPolicy` for
67
+ automatic threshold-driven checkpoint-and-compact.
68
+ - `SqlJournalOptions.sourceEventCache` bounds the in-process
69
+ producer-idempotency index, and `SqlJournalOptions.redact` chooses the
70
+ redactor applied at the single encode chokepoint.
71
+ - `TestJournalOptions` forwards `sourceEventCache`, `redact`, and `compaction`,
72
+ so the sanctioned test bundle can exercise every layer option.
73
+ - `SqlJournalOptions.maxEntryBytes` bounds one entry's encoded bytes. It is
74
+ unset by default: `capacity` bounds entry COUNT, so without it a handful of
75
+ multi-megabyte payloads is the memory bill.
76
+ - Package-owned documentation under `docs/`, generated into
77
+ `docs/pages/api/journal.md` by `scripts/docs.mjs` and drift-checked by the
78
+ `//packages/journal:docsPages` target.
79
+
80
+ ### Fixed
81
+
82
+ - `Redaction.defaultRules` covers GitHub tokens, AWS access keys, Slack tokens,
83
+ Google API keys, URL passwords, quoted `KEY="value"` assignments, and
84
+ embedded JSON credential members. The bearer rule consumes the full RFC 6750
85
+ token alphabet instead of stopping at the first `+`, `/`, or `~`.
86
+ - `Redaction.redact` mirrors `JSON.stringify`'s `toJSON` step, so a `Date`
87
+ persists as its ISO string instead of `{}`. The canonical encoder now runs
88
+ after encoding rather than over the raw redactor output, so the same `Date`
89
+ survives `Redaction.makeNoop()` too, and a redactor returning a cycle fails
90
+ `invalid_event` instead of killing the emit with a defect.
91
+ - `Redaction.isSensitiveKey` recognises `credential`, `credentials`, `dsn`, the
92
+ connection-string family, a plural form of every name it knew, and a trailing
93
+ `key` word. The permanent journal redacted strictly less than the one-shot
94
+ `smithers bug` report, which inverted the risk.
95
+ - The redacting console redacts the label `count`, `countReset`, `time`, and
96
+ `timeEnd` print. All four were bound straight to the delegate as if they
97
+ carried no output, and `timeLog` already redacted its label, so a timer could
98
+ never be found again under the name it was registered with.
99
+ - The compaction policy's per-run counter is serialized. Two settlements that
100
+ overlapped both issued the seeding COUNT and the later reply overwrote the
101
+ newer count with a stale one, so ten committed events produced no compaction
102
+ at all.
103
+ - A `Rule` with `replace` omitted now replaces the whole match, as its JSDoc
104
+ always said. It used to emit `"123-45-678=[REDACTED]"` for a match containing
105
+ no `=`, leaking every character but the last.
106
+ - A non-global `Rule.pattern` redacts every match instead of only the first.
107
+ - `Redaction.redactJsonString` fails closed. It used to return the original
108
+ secret JSON when re-encoding the redacted value failed.
109
+ - A payload with a throwing getter, a hostile `Proxy`, or extreme nesting fails
110
+ the emit with a typed `invalid_event` instead of an unrecoverable defect that
111
+ tore down the enclosing `transact` transaction.
112
+ - `Journal.stream` emits its first entry after one page instead of
113
+ materializing a run's whole history first.
114
+ - A lossy entry admitted before a compaction can no longer land below the
115
+ committed compaction floor, where it was persisted and unreadable forever.
116
+ - Automatic compaction runs off the layer-wide allocation permit, so a slow
117
+ `CompactionPolicy.capture` no longer stalls emits on unrelated runs, and
118
+ `capture` is bounded by a timeout.
119
+ - `checkpoint`'s receipt is decoded from the bytes it persisted, so it agrees
120
+ with `latestCheckpoint` and no longer aliases the caller's mutable state.
121
+ - One conflicted lossy entry no longer destroys its whole persisted batch.
122
+ - Entries published to `changes` are frozen, so one subscriber cannot mutate
123
+ another subscriber's view.
124
+ - Module headers and the README cite pages that exist. `docs/specs/` was never
125
+ imported into this repository.
126
+ - The internal `@slop` review markers no longer ship in the published
127
+ declarations. Every export they marked now carries the prose that retires
128
+ them, so a consumer's editor hover shows the contract rather than a note to
129
+ ourselves.
130
+
131
+ ## [0.1.0] - 2026-08-05
132
+
133
+ This release predates the storage split. The run, attempt, and cache stores and
134
+ the deferred/clock migration named below moved to `@smthrs/run-store`,
135
+ `@smthrs/step-cache`, and `@smthrs/engine-store`; this package's `0002`
136
+ migration creates `flows_journal_checkpoints`.
137
+
138
+ ### Fixed
139
+
140
+ - Kept journal admission, JSON validation, persistence normalization, and
141
+ ownership heartbeat loss in typed Effect failure/interruption channels.
142
+ - Replaced structural `_tag` probing with Schema and Effect SQL error guards.
143
+
144
+ ### Added
145
+
146
+ - Added the non-blocking journal, fenced run and attempt stores, run
147
+ coordinator, migrations, and content-addressed cache.
148
+ - Added migration 0002 for durable deferred completions and absolute clock
149
+ deadlines.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 William Cory and the Smithers Flows contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,207 @@
1
- # Temporary Holding Version
1
+ # @smthrs/journal
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Release candidate scope, host requirements and compatibility review are defined in the [library support policy](https://github.com/smithersai/smithers/blob/main/RELEASE_SUPPORT.md).
4
+
5
+ This package declares `effect` as an exact
6
+ `4.0.0-rc.115` peer dependency. Keep the application on that version so
7
+ all Smithers packages share one Effect runtime.
8
+
9
+ **Documentation:** https://journal.smithers.sh
10
+
11
+ An append-only event history for [Effect](https://effect.website) applications.
12
+ `@smthrs/journal` records what a long-running piece of work did, in order, in
13
+ SQLite. Rows are appended and never updated, so the history reads the same on
14
+ the tenth pass as on the first, and a process that dies halfway through leaves
15
+ behind everything it had already committed.
16
+
17
+ It is a set of Effect services: every write returns a typed receipt or a typed
18
+ failure, and the database arrives as a layer you compose. It belongs to the
19
+ Smithers durable flow engine, but it runs on its own, and no other Smithers
20
+ package is required.
21
+
22
+ ## Install
23
+
24
+ Not on npm yet; see [Installation](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/flow/docs/installation.md#use-the-libraries).
25
+
26
+ `effect` is a peer dependency at exactly `4.0.0-rc.115`. Two copies of `effect`
27
+ in one program are two sets of service tags, so a journal layer built against
28
+ one copy cannot be provided to a program holding the other.
29
+
30
+ Node.js 26.4.0 or later is required for the Node SQLite driver. The package
31
+ ships as both ESM and CommonJS with TypeScript declarations.
32
+
33
+ ## Write one run and read it back
34
+
35
+ ```ts
36
+ import * as DurableWriter from "@smthrs/database/DurableWriter"
37
+ import * as NodeDatabase from "@smthrs/database/node/NodeDatabase"
38
+ import { Journal, JournalEvent, Migrations, SqlJournal } from "@smthrs/journal"
39
+ import * as Effect from "effect/Effect"
40
+ import * as Layer from "effect/Layer"
41
+
42
+ const database = Layer.provideMerge(
43
+ DurableWriter.layer(),
44
+ NodeDatabase.layer({ filename: "history.db" })
45
+ )
46
+
47
+ const journalLayer = SqlJournal.layer({ capacity: 1024, overflow: "reject" }).pipe(
48
+ Layer.provide(Layer.provideMerge(Migrations.layer, database))
49
+ )
50
+
51
+ const runId = "run-1" as JournalEvent.RunId
52
+ const sourceId = "engine" as JournalEvent.SourceId
53
+
54
+ const program = Effect.gen(function*() {
55
+ const journal = yield* Journal.Journal
56
+
57
+ const created = yield* journal.emitDurableUnfenced({
58
+ runId,
59
+ sourceId,
60
+ eventType: "run.created",
61
+ payload: { flow: "build", token: "ghp_0123456789abcdefghijklmnopqrstuvwxyz" }
62
+ })
63
+ console.log("durable:", created._tag, "seq", created.seq)
64
+
65
+ yield* journal.emitLossy({
66
+ runId,
67
+ sourceId,
68
+ eventType: "step.progress",
69
+ payload: { step: "compile", percent: 40 }
70
+ })
71
+ yield* journal.flush
72
+
73
+ const page = yield* journal.entries({ runId, limit: 100 })
74
+ for (const entry of page.entries) {
75
+ console.log(entry.seq, entry.eventType, JSON.stringify(entry.payload))
76
+ }
77
+ })
78
+
79
+ await Effect.runPromise(program.pipe(Effect.provide(journalLayer), Effect.orDie))
80
+ ```
81
+
82
+ ```text
83
+ durable: Accepted seq 0
84
+ 0 run.created {"flow":"build","token":"[REDACTED]"}
85
+ 1 step.progress {"percent":40,"step":"compile"}
86
+ ```
87
+
88
+ The token came back as `[REDACTED]` because it was scrubbed before the row was
89
+ encoded, so the credential is not in `history.db` and never was. `SqlJournal.layer`
90
+ needs both database services: `SqlClient` to read through and `DurableWriter`
91
+ to write through.
92
+
93
+ ## What the journal guarantees
94
+
95
+ - **Two channels, one order.** `emitDurable` and `emitDurableUnfenced` are on
96
+ disk before the call returns. `emitLossy` goes through a bounded queue that
97
+ drops under pressure rather than stalling the writer. Both land in one
98
+ per-run `seq`, so the cheap channel cannot reorder the expensive one.
99
+ - **Every write gets an answer.** An emission returns `Accepted`, `Duplicate`,
100
+ or `Dropped`, and every failure is a `JournalError` carrying one of fourteen
101
+ stable codes, from `invalid_event` and `fence_lost` through `queue_overflow`
102
+ and `sink_failed`.
103
+ - **A retry is not a second event.** Producer identity is
104
+ `(runId, sourceId, sourceSeq)`, unique in the database, so a producer that
105
+ replays after a crash gets `Duplicate` back rather than doubling its history.
106
+ - **Credentials never reach the file.** Payloads are scrubbed on the write
107
+ path, before encoding, because a row is permanent and gets replayed verbatim
108
+ to every later reader.
109
+ - **A stale process cannot append.** `emitDurable` takes an `OwnerId` and
110
+ commits only while the injected `Consensus` strategy still records that
111
+ owner as holding the run. A process that was replaced fails `fence_lost`
112
+ instead of writing into a history it no longer owns.
113
+ - **State and its entry commit together.** `transact` runs your own writes and
114
+ the entries describing them in one transaction and defers publication until
115
+ it commits, so the two can never disagree. Committing locally is not remote
116
+ atomicity: external effects still need idempotency keys, fencing tokens, or
117
+ compensation.
118
+ - **A long run stops growing.** A checkpoint pins replay state to a sequence,
119
+ and `compact` deletes the entries below it.
120
+
121
+ `Seq` is canonical per-run replay order; `SourceSeq` identifies producer
122
+ retries. Rejected and dropped admissions may consume either sequence, so gaps
123
+ are valid.
124
+
125
+ Post-commit compaction preserves the durable writer caller's Effect
126
+ interruption policy. Ordinary callers can interrupt a slow capture; a write
127
+ inside an uninterruptible cancellation finalizer keeps that policy, so
128
+ journaling cannot abandon the cleanup that follows the commit.
129
+
130
+ ## Public API
131
+
132
+ The root exports each module as a namespace, and each is also importable from
133
+ the matching `@smthrs/journal/*` subpath. The
134
+ [API reference](https://journal.smithers.sh/reference/api/) lists every export
135
+ with its one-line summary.
136
+
137
+ | Namespace | What it holds |
138
+ | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
139
+ | `Journal` | The service and its operations, the `Checkpoint` and `Compacted` models, typed errors, receipts, read options, constructors, and the no-op layer. |
140
+ | `JournalEvent` | Branded `RunId`, `Seq`, `SourceId`, and `SourceSeq`; the `Input` and committed `Entry` schemas; deterministic `makeEventId`. |
141
+ | `SqlJournal` | `SqlJournalOptions`, `CompactionPolicy`, the database-backed `layer(options)` fenced by `SqlConsensus`, and `layerWith(options)` over an injected strategy. |
142
+ | `OwnerId` | The fencing token `emitDurable` accepts, carrying `hostId`, `pid`, and `nonce`. |
143
+ | `Consensus` | The injectable ownership strategy: `claim`, `activate`, `heartbeat`, `reconfirm`, `release`, `steal`, `recover`, and the commit-time `guard`; typed outcomes; `LivenessEvidence`; the lease constants; `layerLocal`, `layerNoop`, `make`, `makeLocal`, `makeNoop`. |
144
+ | `SqlConsensus` | The default database-backed strategy over `flows_consensus_leases`: `make` and `layer`. |
145
+ | `Redaction` | The payload redaction applied to entries before they are written, its rule set, and `makeNoop`. |
146
+ | `Projection` | The reproducible `Projection` model and its identity constructor. |
147
+ | `JournalMetrics` | The `flows_journal_writes` counter and the per-channel views `SqlJournal` updates on every emission receipt. |
148
+ | `Migrations` | `set`, `run`, and `layer` for this package's tables: `flows_journal_events` with its indexes, `flows_journal_checkpoints`, `flows_journal_dedup`, and the `flows_consensus_leases` lease table. |
149
+
150
+ Two test entry points sit outside the root:
151
+ `@smthrs/journal/test/TestJournal` provides the production journal over an
152
+ in-memory database (Node only), and `@smthrs/journal/test/Notifying` wraps a
153
+ service so a hook fires around every operation, which is how you inject a crash
154
+ at an exact transition.
155
+
156
+ ## What a fenced write needs
157
+
158
+ `emitDurable`, `checkpoint`, and `compact` gate their write on the
159
+ `Consensus` strategy the journal was built with: the write joins the
160
+ strategy's `guard` inside its own transaction and commits only while the
161
+ strategy still records the supplied owner as holding the run. `SqlJournal.layer`
162
+ fences through `SqlConsensus`, whose lease lives in `flows_consensus_leases`, a
163
+ table this package's own migrations create; `SqlJournal.layerWith` takes any
164
+ strategy, such as `Consensus.layerLocal` for a single process or the browser.
165
+ An owner takes the run through the strategy's `claim` and `activate`, which
166
+ [`@smthrs/run-store`](https://run-store.smithers.sh) drives for a durable run.
167
+
168
+ `emitDurableUnfenced` is the sanctioned path for a genuinely ownerless
169
+ admission, such as an import or a repair tool. Reaching for it to dodge
170
+ `fence_lost` writes exactly the zombie entry the fence exists to reject.
171
+
172
+ ## Where the journal sits
173
+
174
+ The journal holds the history and nothing else. Run and attempt state live in
175
+ [`@smthrs/run-store`](https://run-store.smithers.sh), sealed step results in
176
+ [`@smthrs/step-cache`](https://step-cache.smithers.sh), and the durable
177
+ deferred and clock tables in
178
+ [`@smthrs/engine-store`](https://engine-store.smithers.sh). Those stores hold
179
+ the executable state, which is not derived from journal entries; `transact` is
180
+ what keeps the two halves consistent, because every one of them writes through
181
+ the same `DurableWriter`.
182
+
183
+ SQLite and PostgreSQL share this journal and migration ladder; see
184
+ [database configuration](../database/docs/concepts/sqlite-only.md).
185
+
186
+ Rewinding SQL histories expose `Journal.Service.generation(runId)`, which reads
187
+ `{ generation, afterSeq }` from `flows_journal_generations` (initially zero and
188
+ `-1`). The SQL layer installs this table idempotently on existing databases.
189
+ Time travel increments the generation in the archive transaction. Append-only
190
+ adapters may omit the operation; truncating adapters must implement it. The
191
+ `JournalGeneration.initialize` subpath shares the table installation with time
192
+ travel without adding a migration below an already applied migration block.
193
+
194
+ ## Documentation
195
+
196
+ - [State and event authority](./docs/concepts/state-event-authority.md)
197
+ - [Installation](https://journal.smithers.sh/installation/)
198
+ - [Quickstart](https://journal.smithers.sh/quickstart/)
199
+ - [The two channels](https://journal.smithers.sh/concepts/two-channels/)
200
+ - [The owner fence](https://journal.smithers.sh/concepts/owner-fence/)
201
+ - [Checkpoints and compaction](https://journal.smithers.sh/concepts/compaction/)
202
+ - [API reference](https://journal.smithers.sh/reference/api/)
203
+ - [Troubleshooting](https://journal.smithers.sh/troubleshooting/)
204
+
205
+ ## License
206
+
207
+ MIT
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Versioned facts for an authorized native cell invocation and its delivered result.
3
+ * @since 1.0.0
4
+ */
5
+ import * as Context from "effect/Context";
6
+ import * as Schema from "effect/Schema";
7
+ /** Stable harness coordinates, independent of physical attempt or publication order.
8
+ * @category schemas
9
+ * @since 1.0.0
10
+ */
11
+ export declare const Identity: Schema.Struct<{
12
+ /** Public logical run identity, not an authentication session credential. */
13
+ readonly runId: Schema.String;
14
+ readonly frame: Schema.Int;
15
+ readonly cell: Schema.String;
16
+ readonly ordinal: Schema.Int;
17
+ readonly declaration: Schema.String;
18
+ readonly layers: Schema.$Array<Schema.String>;
19
+ }>;
20
+ /** A call annotation contains data only and never changes an action key.
21
+ * @category schemas
22
+ * @since 1.0.0
23
+ */
24
+ export declare const Call: Schema.Struct<{
25
+ readonly callId: Schema.String;
26
+ readonly identity: Schema.Struct<{
27
+ /** Public logical run identity, not an authentication session credential. */
28
+ readonly runId: Schema.String;
29
+ readonly frame: Schema.Int;
30
+ readonly cell: Schema.String;
31
+ readonly ordinal: Schema.Int;
32
+ readonly declaration: Schema.String;
33
+ readonly layers: Schema.$Array<Schema.String>;
34
+ }>;
35
+ readonly flowName: Schema.String;
36
+ readonly input: Schema.Codec<Schema.Json, Schema.Json, never, never>;
37
+ /**
38
+ * The resolved declaration's display projection, as its owner encoded it.
39
+ *
40
+ * JSON rather than a struct because the vocabulary belongs to
41
+ * `@smthrs/registry` (`Descriptor.FlowActivity`, `Descriptor.CallPresentation`),
42
+ * which sits above this package: `@smthrs/harness` `Cell.displayDescriptor`
43
+ * encodes it from a typed call and the reading card validates each field
44
+ * before it is displayed, so the journal carries it and claims nothing about
45
+ * it. Absent means the declaration claimed nothing.
46
+ */
47
+ readonly descriptor: Schema.optional<Schema.Codec<Schema.Json, Schema.Json, never, never>>;
48
+ }>;
49
+ /** Decoded authorized call coordinates.
50
+ * @category models
51
+ * @since 1.0.0
52
+ */
53
+ export type Call = typeof Call.Type;
54
+ declare const Annotation_base: Context.ServiceClass<Annotation, "@smthrs/journal/CallFact/Annotation", {
55
+ readonly phase: "invoked" | "settled";
56
+ readonly call: Call;
57
+ }>;
58
+ /** Native action annotation; only the existing controller record settles a call.
59
+ * @category services
60
+ * @since 1.0.0
61
+ */
62
+ export declare class Annotation extends Annotation_base {
63
+ }
64
+ /** Public result vocabulary. Executable outcomes remain in the protected attempt row.
65
+ * @category schemas
66
+ * @since 1.0.0
67
+ */
68
+ export declare const Result: Schema.Union<readonly [Schema.Struct<{
69
+ readonly outcome: Schema.Literal<"success">;
70
+ readonly value: Schema.Codec<Schema.Json, Schema.Json, never, never>;
71
+ readonly message: Schema.optional<Schema.String>;
72
+ readonly code: Schema.optionalKey<Schema.Never>;
73
+ }>, Schema.Struct<{
74
+ readonly outcome: Schema.Literal<"failure">;
75
+ readonly value: Schema.Codec<Schema.Json, Schema.Json, never, never>;
76
+ readonly message: Schema.optional<Schema.String>;
77
+ readonly code: Schema.optional<Schema.String>;
78
+ }>]>;
79
+ /** Bounded, redacted event projection; a truncation marker is still JSON.
80
+ * @category schemas
81
+ * @since 1.0.0
82
+ */
83
+ export declare const Fact: Schema.Union<readonly [Schema.Struct<{
84
+ readonly phase: Schema.Literal<"invoked">;
85
+ readonly input: Schema.Codec<Schema.Json, Schema.Json, never, never>;
86
+ readonly descriptor: Schema.optional<Schema.Codec<Schema.Json, Schema.Json, never, never>>;
87
+ readonly version: Schema.Literal<1>;
88
+ readonly callId: Schema.String;
89
+ readonly identity: Schema.Struct<{
90
+ /** Public logical run identity, not an authentication session credential. */
91
+ readonly runId: Schema.String;
92
+ readonly frame: Schema.Int;
93
+ readonly cell: Schema.String;
94
+ readonly ordinal: Schema.Int;
95
+ readonly declaration: Schema.String;
96
+ readonly layers: Schema.$Array<Schema.String>;
97
+ }>;
98
+ readonly flowName: Schema.String;
99
+ }>, Schema.Struct<{
100
+ readonly phase: Schema.Literal<"settled">;
101
+ readonly outcome: Schema.Literals<readonly ["success", "failure"]>;
102
+ readonly value: Schema.Codec<Schema.Json, Schema.Json, never, never>;
103
+ readonly message: Schema.optional<Schema.Codec<Schema.Json, Schema.Json, never, never>>;
104
+ readonly code: Schema.optional<Schema.String>;
105
+ readonly version: Schema.Literal<1>;
106
+ readonly callId: Schema.String;
107
+ readonly identity: Schema.Struct<{
108
+ /** Public logical run identity, not an authentication session credential. */
109
+ readonly runId: Schema.String;
110
+ readonly frame: Schema.Int;
111
+ readonly cell: Schema.String;
112
+ readonly ordinal: Schema.Int;
113
+ readonly declaration: Schema.String;
114
+ readonly layers: Schema.$Array<Schema.String>;
115
+ }>;
116
+ readonly flowName: Schema.String;
117
+ }>]>;
118
+ /** Decoded public native call fact.
119
+ * @category models
120
+ * @since 1.0.0
121
+ */
122
+ export type Fact = typeof Fact.Type;
123
+ /** The immutable native journal is the durable outbox consumed by the native bridge.
124
+ * @category events
125
+ * @since 1.0.0
126
+ */
127
+ export declare const eventType = "flows.harness.call-fact.v1";
128
+ export {};
129
+ //# sourceMappingURL=CallFact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CallFact.d.ts","sourceRoot":"","sources":["../../src/CallFact.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAA;AACzC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC;;;GAGG;AACH,eAAO,MAAM,QAAQ;IACnB,6EAA6E;;;;;;;EAO7E,CAAA;AAEF;;;GAGG;AACH,eAAO,MAAM,IAAI;;;QAbf,6EAA6E;;;;;;;;;;IAkB7E;;;;;;;;;OASG;;EAEH,CAAA;AAEF;;;GAGG;AACH,MAAM,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,CAAA;;oBAOjB,SAAS,GAAG,SAAS;mBACtB,IAAI;;AANrB;;;GAGG;AACH,qBAAa,UAAW,SAAQ,eAGW;CAAG;AAE9C;;;GAGG;AACH,eAAO,MAAM,MAAM;;;;;;;;;;IAajB,CAAA;AASF;;;GAGG;AACH,eAAO,MAAM,IAAI;;;;;;;QA5Ef,6EAA6E;;;;;;;;;;;;;;;;;;QAA7E,6EAA6E;;;;;;;;;IA2F7E,CAAA;AAEF;;;GAGG;AACH,MAAM,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,CAAA;AAEnC;;;GAGG;AACH,eAAO,MAAM,SAAS,+BAA+B,CAAA"}
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var CallFact_exports = {};
30
+ __export(CallFact_exports, {
31
+ Annotation: () => Annotation,
32
+ Call: () => Call,
33
+ Fact: () => Fact,
34
+ Identity: () => Identity,
35
+ Result: () => Result,
36
+ eventType: () => eventType
37
+ });
38
+ module.exports = __toCommonJS(CallFact_exports);
39
+ var Context = __toESM(require("effect/Context"), 1);
40
+ var Schema = __toESM(require("effect/Schema"), 1);
41
+ const Identity = Schema.Struct({
42
+ /** Public logical run identity, not an authentication session credential. */
43
+ runId: Schema.String,
44
+ frame: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),
45
+ cell: Schema.String,
46
+ ordinal: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),
47
+ declaration: Schema.String,
48
+ layers: Schema.Array(Schema.String)
49
+ });
50
+ const Call = Schema.Struct({
51
+ callId: Schema.String.check(Schema.isPattern(/^cell-call-v1:[0-9a-f]{64}$/)),
52
+ identity: Identity,
53
+ flowName: Schema.String,
54
+ input: Schema.Json,
55
+ /**
56
+ * The resolved declaration's display projection, as its owner encoded it.
57
+ *
58
+ * JSON rather than a struct because the vocabulary belongs to
59
+ * `@smthrs/registry` (`Descriptor.FlowActivity`, `Descriptor.CallPresentation`),
60
+ * which sits above this package: `@smthrs/harness` `Cell.displayDescriptor`
61
+ * encodes it from a typed call and the reading card validates each field
62
+ * before it is displayed, so the journal carries it and claims nothing about
63
+ * it. Absent means the declaration claimed nothing.
64
+ */
65
+ descriptor: Schema.optional(Schema.Json)
66
+ });
67
+ class Annotation extends Context.Service()("@smthrs/journal/CallFact/Annotation") {
68
+ }
69
+ const Result = Schema.Union([
70
+ Schema.Struct({
71
+ outcome: Schema.Literal("success"),
72
+ value: Schema.Json,
73
+ message: Schema.optional(Schema.String),
74
+ code: Schema.optionalKey(Schema.Never)
75
+ }),
76
+ Schema.Struct({
77
+ outcome: Schema.Literal("failure"),
78
+ value: Schema.Json,
79
+ message: Schema.optional(Schema.String),
80
+ code: Schema.optional(Schema.String)
81
+ })
82
+ ]);
83
+ const coordinates = {
84
+ version: Schema.Literal(1),
85
+ callId: Call.fields.callId,
86
+ identity: Identity,
87
+ flowName: Schema.String
88
+ };
89
+ const Fact = Schema.Union([
90
+ Schema.Struct({
91
+ ...coordinates,
92
+ phase: Schema.Literal("invoked"),
93
+ input: Schema.Json,
94
+ descriptor: Schema.optional(Schema.Json)
95
+ }),
96
+ Schema.Struct({
97
+ ...coordinates,
98
+ phase: Schema.Literal("settled"),
99
+ outcome: Schema.Literals(["success", "failure"]),
100
+ value: Schema.Json,
101
+ message: Schema.optional(Schema.Json),
102
+ code: Schema.optional(Schema.String)
103
+ })
104
+ ]);
105
+ const eventType = "flows.harness.call-fact.v1";
106
+ //# sourceMappingURL=CallFact.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/CallFact.ts"],
4
+ "sourcesContent": ["/**\n * Versioned facts for an authorized native cell invocation and its delivered result.\n * @since 1.0.0\n */\n\nimport * as Context from \"effect/Context\"\nimport * as Schema from \"effect/Schema\"\n\n/** Stable harness coordinates, independent of physical attempt or publication order.\n * @category schemas\n * @since 1.0.0\n */\nexport const Identity = Schema.Struct({\n /** Public logical run identity, not an authentication session credential. */\n runId: Schema.String,\n frame: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n cell: Schema.String,\n ordinal: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n declaration: Schema.String,\n layers: Schema.Array(Schema.String)\n})\n\n/** A call annotation contains data only and never changes an action key.\n * @category schemas\n * @since 1.0.0\n */\nexport const Call = Schema.Struct({\n callId: Schema.String.check(Schema.isPattern(/^cell-call-v1:[0-9a-f]{64}$/)),\n identity: Identity,\n flowName: Schema.String,\n input: Schema.Json,\n /**\n * The resolved declaration's display projection, as its owner encoded it.\n *\n * JSON rather than a struct because the vocabulary belongs to\n * `@smthrs/registry` (`Descriptor.FlowActivity`, `Descriptor.CallPresentation`),\n * which sits above this package: `@smthrs/harness` `Cell.displayDescriptor`\n * encodes it from a typed call and the reading card validates each field\n * before it is displayed, so the journal carries it and claims nothing about\n * it. Absent means the declaration claimed nothing.\n */\n descriptor: Schema.optional(Schema.Json)\n})\n\n/** Decoded authorized call coordinates.\n * @category models\n * @since 1.0.0\n */\nexport type Call = typeof Call.Type\n\n/** Native action annotation; only the existing controller record settles a call.\n * @category services\n * @since 1.0.0\n */\nexport class Annotation extends Context.Service<Annotation, {\n readonly phase: \"invoked\" | \"settled\"\n readonly call: Call\n}>()(\"@smthrs/journal/CallFact/Annotation\") {}\n\n/** Public result vocabulary. Executable outcomes remain in the protected attempt row.\n * @category schemas\n * @since 1.0.0\n */\nexport const Result = Schema.Union([\n Schema.Struct({\n outcome: Schema.Literal(\"success\"),\n value: Schema.Json,\n message: Schema.optional(Schema.String),\n code: Schema.optionalKey(Schema.Never)\n }),\n Schema.Struct({\n outcome: Schema.Literal(\"failure\"),\n value: Schema.Json,\n message: Schema.optional(Schema.String),\n code: Schema.optional(Schema.String)\n })\n])\n\nconst coordinates = {\n version: Schema.Literal(1),\n callId: Call.fields.callId,\n identity: Identity,\n flowName: Schema.String\n}\n\n/** Bounded, redacted event projection; a truncation marker is still JSON.\n * @category schemas\n * @since 1.0.0\n */\nexport const Fact = Schema.Union([\n Schema.Struct({\n ...coordinates,\n phase: Schema.Literal(\"invoked\"),\n input: Schema.Json,\n descriptor: Schema.optional(Schema.Json)\n }),\n Schema.Struct({\n ...coordinates,\n phase: Schema.Literal(\"settled\"),\n outcome: Schema.Literals([\"success\", \"failure\"]),\n value: Schema.Json,\n message: Schema.optional(Schema.Json),\n code: Schema.optional(Schema.String)\n })\n])\n\n/** Decoded public native call fact.\n * @category models\n * @since 1.0.0\n */\nexport type Fact = typeof Fact.Type\n\n/** The immutable native journal is the durable outbox consumed by the native bridge.\n * @category events\n * @since 1.0.0\n */\nexport const eventType = \"flows.harness.call-fact.v1\"\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,cAAyB;AACzB,aAAwB;AAMjB,MAAM,WAAW,OAAO,OAAO;AAAA;AAAA,EAEpC,OAAO,OAAO;AAAA,EACd,OAAO,OAAO,IAAI,MAAM,OAAO,uBAAuB,CAAC,CAAC;AAAA,EACxD,MAAM,OAAO;AAAA,EACb,SAAS,OAAO,IAAI,MAAM,OAAO,uBAAuB,CAAC,CAAC;AAAA,EAC1D,aAAa,OAAO;AAAA,EACpB,QAAQ,OAAO,MAAM,OAAO,MAAM;AACpC,CAAC;AAMM,MAAM,OAAO,OAAO,OAAO;AAAA,EAChC,QAAQ,OAAO,OAAO,MAAM,OAAO,UAAU,6BAA6B,CAAC;AAAA,EAC3E,UAAU;AAAA,EACV,UAAU,OAAO;AAAA,EACjB,OAAO,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWd,YAAY,OAAO,SAAS,OAAO,IAAI;AACzC,CAAC;AAYM,MAAM,mBAAmB,QAAQ,QAGrC,EAAE,qCAAqC,EAAE;AAAC;AAMtC,MAAM,SAAS,OAAO,MAAM;AAAA,EACjC,OAAO,OAAO;AAAA,IACZ,SAAS,OAAO,QAAQ,SAAS;AAAA,IACjC,OAAO,OAAO;AAAA,IACd,SAAS,OAAO,SAAS,OAAO,MAAM;AAAA,IACtC,MAAM,OAAO,YAAY,OAAO,KAAK;AAAA,EACvC,CAAC;AAAA,EACD,OAAO,OAAO;AAAA,IACZ,SAAS,OAAO,QAAQ,SAAS;AAAA,IACjC,OAAO,OAAO;AAAA,IACd,SAAS,OAAO,SAAS,OAAO,MAAM;AAAA,IACtC,MAAM,OAAO,SAAS,OAAO,MAAM;AAAA,EACrC,CAAC;AACH,CAAC;AAED,MAAM,cAAc;AAAA,EAClB,SAAS,OAAO,QAAQ,CAAC;AAAA,EACzB,QAAQ,KAAK,OAAO;AAAA,EACpB,UAAU;AAAA,EACV,UAAU,OAAO;AACnB;AAMO,MAAM,OAAO,OAAO,MAAM;AAAA,EAC/B,OAAO,OAAO;AAAA,IACZ,GAAG;AAAA,IACH,OAAO,OAAO,QAAQ,SAAS;AAAA,IAC/B,OAAO,OAAO;AAAA,IACd,YAAY,OAAO,SAAS,OAAO,IAAI;AAAA,EACzC,CAAC;AAAA,EACD,OAAO,OAAO;AAAA,IACZ,GAAG;AAAA,IACH,OAAO,OAAO,QAAQ,SAAS;AAAA,IAC/B,SAAS,OAAO,SAAS,CAAC,WAAW,SAAS,CAAC;AAAA,IAC/C,OAAO,OAAO;AAAA,IACd,SAAS,OAAO,SAAS,OAAO,IAAI;AAAA,IACpC,MAAM,OAAO,SAAS,OAAO,MAAM;AAAA,EACrC,CAAC;AACH,CAAC;AAYM,MAAM,YAAY;",
6
+ "names": []
7
+ }