@smthrs/journal 0.0.0-stage → 1.0.0-rc.4
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.
- package/CHANGELOG.md +149 -0
- package/LICENSE +21 -0
- package/README.md +206 -2
- package/dist/cjs/CallFact.d.ts +129 -0
- package/dist/cjs/CallFact.d.ts.map +1 -0
- package/dist/cjs/CallFact.js +106 -0
- package/dist/cjs/CallFact.js.map +7 -0
- package/dist/cjs/Consensus.d.ts +440 -0
- package/dist/cjs/Consensus.d.ts.map +1 -0
- package/dist/cjs/Consensus.js +251 -0
- package/dist/cjs/Consensus.js.map +7 -0
- package/dist/cjs/EngineEvent.d.ts +890 -0
- package/dist/cjs/EngineEvent.d.ts.map +1 -0
- package/dist/cjs/EngineEvent.js +383 -0
- package/dist/cjs/EngineEvent.js.map +7 -0
- package/dist/cjs/ExecutionFact.d.ts +216 -0
- package/dist/cjs/ExecutionFact.d.ts.map +1 -0
- package/dist/cjs/ExecutionFact.js +303 -0
- package/dist/cjs/ExecutionFact.js.map +7 -0
- package/dist/cjs/Journal.d.ts +617 -0
- package/dist/cjs/Journal.d.ts.map +1 -0
- package/dist/cjs/Journal.js +190 -0
- package/dist/cjs/Journal.js.map +7 -0
- package/dist/cjs/JournalEvent.d.ts +421 -0
- package/dist/cjs/JournalEvent.d.ts.map +1 -0
- package/dist/cjs/JournalEvent.js +281 -0
- package/dist/cjs/JournalEvent.js.map +7 -0
- package/dist/cjs/JournalGeneration.d.ts +34 -0
- package/dist/cjs/JournalGeneration.d.ts.map +1 -0
- package/dist/cjs/JournalGeneration.js +72 -0
- package/dist/cjs/JournalGeneration.js.map +7 -0
- package/dist/cjs/JournalMetrics.d.ts +72 -0
- package/dist/cjs/JournalMetrics.d.ts.map +1 -0
- package/dist/cjs/JournalMetrics.js +55 -0
- package/dist/cjs/JournalMetrics.js.map +7 -0
- package/dist/cjs/Migrations.d.ts +42 -0
- package/dist/cjs/Migrations.d.ts.map +1 -0
- package/dist/cjs/Migrations.js +58 -0
- package/dist/cjs/Migrations.js.map +7 -0
- package/dist/cjs/OwnerId.d.ts +40 -0
- package/dist/cjs/OwnerId.d.ts.map +1 -0
- package/dist/cjs/OwnerId.js +40 -0
- package/dist/cjs/OwnerId.js.map +7 -0
- package/dist/cjs/Projection.d.ts +29 -0
- package/dist/cjs/Projection.d.ts.map +1 -0
- package/dist/cjs/Projection.js +25 -0
- package/dist/cjs/Projection.js.map +7 -0
- package/dist/cjs/RedactedLogger.d.ts +121 -0
- package/dist/cjs/RedactedLogger.d.ts.map +1 -0
- package/dist/cjs/RedactedLogger.js +235 -0
- package/dist/cjs/RedactedLogger.js.map +7 -0
- package/dist/cjs/Redaction.d.ts +350 -0
- package/dist/cjs/Redaction.d.ts.map +1 -0
- package/dist/cjs/Redaction.js +928 -0
- package/dist/cjs/Redaction.js.map +7 -0
- package/dist/cjs/SqlConsensus.d.ts +44 -0
- package/dist/cjs/SqlConsensus.d.ts.map +1 -0
- package/dist/cjs/SqlConsensus.js +243 -0
- package/dist/cjs/SqlConsensus.js.map +7 -0
- package/dist/cjs/SqlJournal.d.ts +173 -0
- package/dist/cjs/SqlJournal.d.ts.map +1 -0
- package/dist/cjs/SqlJournal.js +1568 -0
- package/dist/cjs/SqlJournal.js.map +7 -0
- package/dist/cjs/StepFact.d.ts +66 -0
- package/dist/cjs/StepFact.d.ts.map +1 -0
- package/dist/cjs/StepFact.js +68 -0
- package/dist/cjs/StepFact.js.map +7 -0
- package/dist/cjs/index.d.ts +95 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +63 -0
- package/dist/cjs/index.js.map +7 -0
- package/dist/cjs/internal/JournalInternalFault.d.ts +37 -0
- package/dist/cjs/internal/JournalInternalFault.d.ts.map +1 -0
- package/dist/cjs/internal/JournalInternalFault.js +43 -0
- package/dist/cjs/internal/JournalInternalFault.js.map +7 -0
- package/dist/cjs/migrations/0001_initial.d.ts +15 -0
- package/dist/cjs/migrations/0001_initial.d.ts.map +1 -0
- package/dist/cjs/migrations/0001_initial.js +54 -0
- package/dist/cjs/migrations/0001_initial.js.map +7 -0
- package/dist/cjs/migrations/0002_checkpoints.d.ts +27 -0
- package/dist/cjs/migrations/0002_checkpoints.d.ts.map +1 -0
- package/dist/cjs/migrations/0002_checkpoints.js +48 -0
- package/dist/cjs/migrations/0002_checkpoints.js.map +7 -0
- package/dist/cjs/migrations/0003_startup_index.d.ts +15 -0
- package/dist/cjs/migrations/0003_startup_index.d.ts.map +1 -0
- package/dist/cjs/migrations/0003_startup_index.js +40 -0
- package/dist/cjs/migrations/0003_startup_index.js.map +7 -0
- package/dist/cjs/migrations/0004_dedup.d.ts +15 -0
- package/dist/cjs/migrations/0004_dedup.d.ts.map +1 -0
- package/dist/cjs/migrations/0004_dedup.js +57 -0
- package/dist/cjs/migrations/0004_dedup.js.map +7 -0
- package/dist/cjs/migrations/0005_run_event_type.d.ts +15 -0
- package/dist/cjs/migrations/0005_run_event_type.d.ts.map +1 -0
- package/dist/cjs/migrations/0005_run_event_type.js +40 -0
- package/dist/cjs/migrations/0005_run_event_type.js.map +7 -0
- package/dist/cjs/migrations/0006_consensus.d.ts +22 -0
- package/dist/cjs/migrations/0006_consensus.d.ts.map +1 -0
- package/dist/cjs/migrations/0006_consensus.js +84 -0
- package/dist/cjs/migrations/0006_consensus.js.map +7 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/test/Notifying.d.ts +65 -0
- package/dist/cjs/test/Notifying.d.ts.map +1 -0
- package/dist/cjs/test/Notifying.js +62 -0
- package/dist/cjs/test/Notifying.js.map +7 -0
- package/dist/cjs/test/TestJournal.d.ts +43 -0
- package/dist/cjs/test/TestJournal.d.ts.map +1 -0
- package/dist/cjs/test/TestJournal.js +43 -0
- package/dist/cjs/test/TestJournal.js.map +7 -0
- package/dist/esm/CallFact.d.ts +129 -0
- package/dist/esm/CallFact.d.ts.map +1 -0
- package/dist/esm/CallFact.js +96 -0
- package/dist/esm/CallFact.js.map +1 -0
- package/dist/esm/Consensus.d.ts +440 -0
- package/dist/esm/Consensus.d.ts.map +1 -0
- package/dist/esm/Consensus.js +454 -0
- package/dist/esm/Consensus.js.map +1 -0
- package/dist/esm/EngineEvent.d.ts +890 -0
- package/dist/esm/EngineEvent.d.ts.map +1 -0
- package/dist/esm/EngineEvent.js +614 -0
- package/dist/esm/EngineEvent.js.map +1 -0
- package/dist/esm/ExecutionFact.d.ts +216 -0
- package/dist/esm/ExecutionFact.d.ts.map +1 -0
- package/dist/esm/ExecutionFact.js +374 -0
- package/dist/esm/ExecutionFact.js.map +1 -0
- package/dist/esm/Journal.d.ts +617 -0
- package/dist/esm/Journal.d.ts.map +1 -0
- package/dist/esm/Journal.js +323 -0
- package/dist/esm/Journal.js.map +1 -0
- package/dist/esm/JournalEvent.d.ts +421 -0
- package/dist/esm/JournalEvent.d.ts.map +1 -0
- package/dist/esm/JournalEvent.js +517 -0
- package/dist/esm/JournalEvent.js.map +1 -0
- package/dist/esm/JournalGeneration.d.ts +34 -0
- package/dist/esm/JournalGeneration.d.ts.map +1 -0
- package/dist/esm/JournalGeneration.js +65 -0
- package/dist/esm/JournalGeneration.js.map +1 -0
- package/dist/esm/JournalMetrics.d.ts +72 -0
- package/dist/esm/JournalMetrics.d.ts.map +1 -0
- package/dist/esm/JournalMetrics.js +79 -0
- package/dist/esm/JournalMetrics.js.map +1 -0
- package/dist/esm/Migrations.d.ts +42 -0
- package/dist/esm/Migrations.d.ts.map +1 -0
- package/dist/esm/Migrations.js +59 -0
- package/dist/esm/Migrations.js.map +1 -0
- package/dist/esm/OwnerId.d.ts +40 -0
- package/dist/esm/OwnerId.d.ts.map +1 -0
- package/dist/esm/OwnerId.js +33 -0
- package/dist/esm/OwnerId.js.map +1 -0
- package/dist/esm/Projection.d.ts +29 -0
- package/dist/esm/Projection.d.ts.map +1 -0
- package/dist/esm/Projection.js +13 -0
- package/dist/esm/Projection.js.map +1 -0
- package/dist/esm/RedactedLogger.d.ts +121 -0
- package/dist/esm/RedactedLogger.d.ts.map +1 -0
- package/dist/esm/RedactedLogger.js +445 -0
- package/dist/esm/RedactedLogger.js.map +1 -0
- package/dist/esm/Redaction.d.ts +350 -0
- package/dist/esm/Redaction.d.ts.map +1 -0
- package/dist/esm/Redaction.js +1584 -0
- package/dist/esm/Redaction.js.map +1 -0
- package/dist/esm/SqlConsensus.d.ts +44 -0
- package/dist/esm/SqlConsensus.d.ts.map +1 -0
- package/dist/esm/SqlConsensus.js +252 -0
- package/dist/esm/SqlConsensus.js.map +1 -0
- package/dist/esm/SqlJournal.d.ts +173 -0
- package/dist/esm/SqlJournal.d.ts.map +1 -0
- package/dist/esm/SqlJournal.js +1858 -0
- package/dist/esm/SqlJournal.js.map +1 -0
- package/dist/esm/StepFact.d.ts +66 -0
- package/dist/esm/StepFact.d.ts.map +1 -0
- package/dist/esm/StepFact.js +50 -0
- package/dist/esm/StepFact.js.map +1 -0
- package/dist/esm/index.d.ts +95 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +95 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/internal/JournalInternalFault.d.ts +37 -0
- package/dist/esm/internal/JournalInternalFault.d.ts.map +1 -0
- package/dist/esm/internal/JournalInternalFault.js +28 -0
- package/dist/esm/internal/JournalInternalFault.js.map +1 -0
- package/dist/esm/migrations/0001_initial.d.ts +15 -0
- package/dist/esm/migrations/0001_initial.d.ts.map +1 -0
- package/dist/esm/migrations/0001_initial.js +32 -0
- package/dist/esm/migrations/0001_initial.js.map +1 -0
- package/dist/esm/migrations/0002_checkpoints.d.ts +27 -0
- package/dist/esm/migrations/0002_checkpoints.d.ts.map +1 -0
- package/dist/esm/migrations/0002_checkpoints.js +38 -0
- package/dist/esm/migrations/0002_checkpoints.js.map +1 -0
- package/dist/esm/migrations/0003_startup_index.d.ts +15 -0
- package/dist/esm/migrations/0003_startup_index.d.ts.map +1 -0
- package/dist/esm/migrations/0003_startup_index.js +18 -0
- package/dist/esm/migrations/0003_startup_index.js.map +1 -0
- package/dist/esm/migrations/0004_dedup.d.ts +15 -0
- package/dist/esm/migrations/0004_dedup.d.ts.map +1 -0
- package/dist/esm/migrations/0004_dedup.js +38 -0
- package/dist/esm/migrations/0004_dedup.js.map +1 -0
- package/dist/esm/migrations/0005_run_event_type.d.ts +15 -0
- package/dist/esm/migrations/0005_run_event_type.d.ts.map +1 -0
- package/dist/esm/migrations/0005_run_event_type.js +18 -0
- package/dist/esm/migrations/0005_run_event_type.js.map +1 -0
- package/dist/esm/migrations/0006_consensus.d.ts +22 -0
- package/dist/esm/migrations/0006_consensus.d.ts.map +1 -0
- package/dist/esm/migrations/0006_consensus.js +69 -0
- package/dist/esm/migrations/0006_consensus.js.map +1 -0
- package/dist/esm/test/Notifying.d.ts +65 -0
- package/dist/esm/test/Notifying.d.ts.map +1 -0
- package/dist/esm/test/Notifying.js +62 -0
- package/dist/esm/test/Notifying.js.map +1 -0
- package/dist/esm/test/TestJournal.d.ts +43 -0
- package/dist/esm/test/TestJournal.d.ts.map +1 -0
- package/dist/esm/test/TestJournal.js +27 -0
- package/dist/esm/test/TestJournal.js.map +1 -0
- package/docs/README.md +164 -0
- package/docs/api.md +639 -0
- package/docs/concepts/compaction.md +157 -0
- package/docs/concepts/idempotency.md +127 -0
- package/docs/concepts/owner-fence.md +124 -0
- package/docs/concepts/redaction.md +218 -0
- package/docs/concepts/state-event-authority.md +159 -0
- package/docs/concepts/two-channels.md +167 -0
- package/docs/guides/commit-state-and-entry.md +114 -0
- package/docs/guides/compact-a-run.md +134 -0
- package/docs/guides/fold-a-projection.md +106 -0
- package/docs/guides/read-a-run.md +139 -0
- package/docs/guides/redact-log-output.md +94 -0
- package/docs/guides/testing.md +124 -0
- package/docs/guides/write-lifecycle-events.md +110 -0
- package/docs/installation.md +133 -0
- package/docs/quickstart.md +143 -0
- package/docs/troubleshooting.md +214 -0
- package/package.json +263 -3
- package/src/CallFact.ts +117 -0
- package/src/Consensus.ts +683 -0
- package/src/EngineEvent.ts +823 -0
- package/src/ExecutionFact.ts +433 -0
- package/src/Journal.ts +688 -0
- package/src/JournalEvent.ts +654 -0
- package/src/JournalGeneration.ts +77 -0
- package/src/JournalMetrics.ts +89 -0
- package/src/Migrations.ts +62 -0
- package/src/OwnerId.ts +42 -0
- package/src/Projection.ts +31 -0
- package/src/RedactedLogger.ts +483 -0
- package/src/Redaction.ts +1784 -0
- package/src/SqlConsensus.ts +344 -0
- package/src/SqlJournal.ts +2732 -0
- package/src/StepFact.ts +69 -0
- package/src/index.ts +109 -0
- package/src/internal/JournalInternalFault.ts +40 -0
- package/src/migrations/0001_initial.ts +41 -0
- package/src/migrations/0002_checkpoints.ts +46 -0
- package/src/migrations/0003_startup_index.ts +19 -0
- package/src/migrations/0004_dedup.ts +43 -0
- package/src/migrations/0005_run_event_type.ts +19 -0
- package/src/migrations/0006_consensus.ts +83 -0
- package/src/test/Notifying.ts +101 -0
- package/src/test/TestJournal.ts +52 -0
|
@@ -0,0 +1,190 @@
|
|
|
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 Journal_exports = {};
|
|
30
|
+
__export(Journal_exports, {
|
|
31
|
+
Accepted: () => Accepted,
|
|
32
|
+
Checkpoint: () => Checkpoint,
|
|
33
|
+
CheckpointOptions: () => CheckpointOptions,
|
|
34
|
+
CompactOptions: () => CompactOptions,
|
|
35
|
+
Compacted: () => Compacted,
|
|
36
|
+
Dropped: () => Dropped,
|
|
37
|
+
Duplicate: () => Duplicate,
|
|
38
|
+
DurableReceipt: () => DurableReceipt,
|
|
39
|
+
EmitReceipt: () => EmitReceipt,
|
|
40
|
+
EntriesOptions: () => EntriesOptions,
|
|
41
|
+
EntriesPage: () => EntriesPage,
|
|
42
|
+
Journal: () => Journal,
|
|
43
|
+
JournalError: () => JournalError,
|
|
44
|
+
JournalErrorCode: () => JournalErrorCode,
|
|
45
|
+
OverflowPolicy: () => OverflowPolicy,
|
|
46
|
+
StreamOptions: () => StreamOptions,
|
|
47
|
+
afterCommit: () => import_DurableWriter.afterCommit,
|
|
48
|
+
layerNoop: () => layerNoop,
|
|
49
|
+
make: () => make,
|
|
50
|
+
makeNoop: () => makeNoop,
|
|
51
|
+
maxEntriesLimit: () => maxEntriesLimit
|
|
52
|
+
});
|
|
53
|
+
module.exports = __toCommonJS(Journal_exports);
|
|
54
|
+
var Context = __toESM(require("effect/Context"), 1);
|
|
55
|
+
var Effect = __toESM(require("effect/Effect"), 1);
|
|
56
|
+
var Layer = __toESM(require("effect/Layer"), 1);
|
|
57
|
+
var PubSub = __toESM(require("effect/PubSub"), 1);
|
|
58
|
+
var Schema = __toESM(require("effect/Schema"), 1);
|
|
59
|
+
var Stream = __toESM(require("effect/Stream"), 1);
|
|
60
|
+
var import_JournalEvent = require("./JournalEvent.js");
|
|
61
|
+
var import_DurableWriter = require("@smthrs/database/DurableWriter");
|
|
62
|
+
const JournalErrorCode = Schema.Literals([
|
|
63
|
+
"invalid_event",
|
|
64
|
+
"idempotency_conflict",
|
|
65
|
+
"sequence_conflict",
|
|
66
|
+
"fence_lost",
|
|
67
|
+
"queue_overflow",
|
|
68
|
+
"journal_closed",
|
|
69
|
+
"sink_failed",
|
|
70
|
+
"read_failed",
|
|
71
|
+
"decode_failed",
|
|
72
|
+
"projection_failed",
|
|
73
|
+
"checkpoint_invalid",
|
|
74
|
+
"reader_behind",
|
|
75
|
+
"compacted",
|
|
76
|
+
"unknown"
|
|
77
|
+
]);
|
|
78
|
+
class JournalError extends Schema.TaggedError()("@smthrs/journal/JournalError", {
|
|
79
|
+
code: JournalErrorCode,
|
|
80
|
+
message: Schema.String,
|
|
81
|
+
cause: Schema.optional(Schema.Unknown),
|
|
82
|
+
checkpointSeq: Schema.optional(import_JournalEvent.Seq)
|
|
83
|
+
}) {
|
|
84
|
+
}
|
|
85
|
+
const OverflowPolicy = Schema.Literals(["reject", "drop-newest", "drop-oldest"]);
|
|
86
|
+
const Accepted = Schema.TaggedStruct("Accepted", {
|
|
87
|
+
seq: import_JournalEvent.Seq,
|
|
88
|
+
sourceSeq: import_JournalEvent.SourceSeq,
|
|
89
|
+
evicted: Schema.optionalKey(Schema.Struct({
|
|
90
|
+
policy: Schema.Literal("drop-oldest"),
|
|
91
|
+
count: Schema.Int.check(Schema.isGreaterThan(0))
|
|
92
|
+
}))
|
|
93
|
+
});
|
|
94
|
+
const Duplicate = Schema.TaggedStruct("Duplicate", {
|
|
95
|
+
seq: import_JournalEvent.Seq,
|
|
96
|
+
sourceSeq: import_JournalEvent.SourceSeq,
|
|
97
|
+
status: Schema.Literals(["pending", "committed"])
|
|
98
|
+
});
|
|
99
|
+
const Dropped = Schema.TaggedStruct("Dropped", {
|
|
100
|
+
seq: import_JournalEvent.Seq,
|
|
101
|
+
sourceSeq: import_JournalEvent.SourceSeq,
|
|
102
|
+
policy: Schema.Literal("drop-newest")
|
|
103
|
+
});
|
|
104
|
+
const EmitReceipt = Schema.Union([Accepted, Duplicate, Dropped]);
|
|
105
|
+
const DurableReceipt = Schema.Union([Accepted, Duplicate]);
|
|
106
|
+
const StreamOptions = Schema.Struct({
|
|
107
|
+
runId: import_JournalEvent.RunId,
|
|
108
|
+
afterSequence: Schema.optionalKey(import_JournalEvent.Seq)
|
|
109
|
+
});
|
|
110
|
+
const maxEntriesLimit = 1e4;
|
|
111
|
+
const EntriesOptions = Schema.Struct({
|
|
112
|
+
runId: import_JournalEvent.RunId,
|
|
113
|
+
after: Schema.optionalKey(import_JournalEvent.Seq),
|
|
114
|
+
eventTypes: Schema.optionalKey(
|
|
115
|
+
Schema.Array(import_JournalEvent.Entry.fields.eventType).check(Schema.isMinLength(1), Schema.isMaxLength(64))
|
|
116
|
+
),
|
|
117
|
+
limit: Schema.Int.check(Schema.isGreaterThan(0), Schema.isLessThanOrEqualTo(maxEntriesLimit))
|
|
118
|
+
});
|
|
119
|
+
const EntriesPage = Schema.Struct({
|
|
120
|
+
entries: Schema.Array(import_JournalEvent.Entry),
|
|
121
|
+
hasMore: Schema.Boolean
|
|
122
|
+
});
|
|
123
|
+
class Checkpoint extends Schema.Class("@smthrs/journal/Journal/Checkpoint")({
|
|
124
|
+
runId: import_JournalEvent.RunId,
|
|
125
|
+
seq: import_JournalEvent.Seq,
|
|
126
|
+
state: Schema.Unknown,
|
|
127
|
+
createdAtMs: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),
|
|
128
|
+
compactedAtMs: Schema.NullOr(Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)))
|
|
129
|
+
}) {
|
|
130
|
+
}
|
|
131
|
+
const CheckpointOptions = Schema.Struct({
|
|
132
|
+
runId: import_JournalEvent.RunId,
|
|
133
|
+
seq: import_JournalEvent.Seq,
|
|
134
|
+
state: Schema.Unknown
|
|
135
|
+
});
|
|
136
|
+
const CompactOptions = Schema.Struct({
|
|
137
|
+
runId: import_JournalEvent.RunId,
|
|
138
|
+
upTo: Schema.optionalKey(import_JournalEvent.Seq)
|
|
139
|
+
});
|
|
140
|
+
const Compacted = Schema.Struct({
|
|
141
|
+
runId: import_JournalEvent.RunId,
|
|
142
|
+
checkpointSeq: import_JournalEvent.Seq,
|
|
143
|
+
deleted: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0))
|
|
144
|
+
});
|
|
145
|
+
class Journal extends Context.Service()("@smthrs/journal/Journal") {
|
|
146
|
+
}
|
|
147
|
+
const make = (implementation) => Journal.of(implementation);
|
|
148
|
+
const unavailable = (method) => new JournalError({
|
|
149
|
+
code: "journal_closed",
|
|
150
|
+
message: `${method} is unavailable`
|
|
151
|
+
});
|
|
152
|
+
const makeNoop = (overrides = {}) => {
|
|
153
|
+
const service = {
|
|
154
|
+
emitLossy: Effect.fn("Journal.emitLossy")(() => Effect.fail(unavailable("emitLossy"))),
|
|
155
|
+
emitDurable: Effect.fn("Journal.emitDurable")(() => Effect.fail(unavailable("emitDurable"))),
|
|
156
|
+
emitDurableUnfenced: Effect.fn("Journal.emitDurableUnfenced")(
|
|
157
|
+
() => Effect.fail(unavailable("emitDurableUnfenced"))
|
|
158
|
+
),
|
|
159
|
+
/**
|
|
160
|
+
* The closed stub has no sink and therefore no transaction to open, so it
|
|
161
|
+
* runs the effect directly, the same posture as
|
|
162
|
+
* `DurableEngineState`'s in-memory twin, whose `transaction` has no crash
|
|
163
|
+
* window to close. A test double that models rollback overrides it.
|
|
164
|
+
*/
|
|
165
|
+
transact: (effect) => effect,
|
|
166
|
+
whenCommitted: (update) => Effect.as(update, true),
|
|
167
|
+
stream: (options) => Stream.unwrap(
|
|
168
|
+
Effect.fn("Journal.stream")((_options) => Effect.succeed(Stream.fail(unavailable("stream"))))(
|
|
169
|
+
options
|
|
170
|
+
)
|
|
171
|
+
),
|
|
172
|
+
entries: Effect.fn("Journal.entries")(() => Effect.fail(unavailable("entries"))),
|
|
173
|
+
changes: Effect.acquireRelease(
|
|
174
|
+
PubSub.sliding(1),
|
|
175
|
+
PubSub.shutdown
|
|
176
|
+
).pipe(Effect.flatMap(PubSub.subscribe)),
|
|
177
|
+
project: (projection, options) => Stream.unwrap(
|
|
178
|
+
Effect.fn("Journal.project")(
|
|
179
|
+
(_projection, _options) => Effect.succeed(Stream.fail(unavailable("project")))
|
|
180
|
+
)(projection, options)
|
|
181
|
+
),
|
|
182
|
+
flush: Effect.fn("Journal.flush")(() => Effect.fail(unavailable("flush")))(),
|
|
183
|
+
checkpoint: Effect.fn("Journal.checkpoint")(() => Effect.fail(unavailable("checkpoint"))),
|
|
184
|
+
latestCheckpoint: Effect.fn("Journal.latestCheckpoint")(() => Effect.fail(unavailable("latestCheckpoint"))),
|
|
185
|
+
compact: Effect.fn("Journal.compact")(() => Effect.fail(unavailable("compact")))
|
|
186
|
+
};
|
|
187
|
+
return Journal.of({ ...service, ...overrides });
|
|
188
|
+
};
|
|
189
|
+
const layerNoop = (overrides = {}) => Layer.succeed(Journal)(makeNoop(overrides));
|
|
190
|
+
//# sourceMappingURL=Journal.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/Journal.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Logical journal contract with durable lifecycle and lossy telemetry channels.\n *\n * The ownership fence and the lossless `emitDurable` / lossy `emitLossy`\n * split are described at https://journal.smithers.sh/concepts/owner-fence/\n * and https://journal.smithers.sh/concepts/two-channels/.\n *\n * @since 0.1.0\n */\n\nimport * as Context from \"effect/Context\"\nimport * as Effect from \"effect/Effect\"\nimport * as Layer from \"effect/Layer\"\nimport type * as Option from \"effect/Option\"\nimport * as PubSub from \"effect/PubSub\"\nimport * as Schema from \"effect/Schema\"\nimport type * as Scope from \"effect/Scope\"\nimport * as Stream from \"effect/Stream\"\nimport { Entry, RunId, Seq, SourceSeq } from \"./JournalEvent.ts\"\nimport type { Input } from \"./JournalEvent.ts\"\nimport type { OwnerId } from \"./OwnerId.ts\"\nimport type { Projection } from \"./Projection.ts\"\n\n/**\n * Defers a fold/cache update until the outermost durable write commits.\n * Returns false without running it when no managed commit is available.\n * Failed savepoints and retried transaction attempts never publish the update.\n *\n * @category transactions\n * @since 1.0.0\n */\nexport { afterCommit } from \"@smthrs/database/DurableWriter\"\n\n/**\n * Stable error codes returned by journal operations.\n *\n * `read_failed` identifies a database failure on a durable read path. Callers\n * can distinguish that retryable storage condition from an unclassified\n * `unknown` journal defect.\n *\n * @category models\n * @since 0.1.0\n */\nexport const JournalErrorCode = Schema.Literals([\n \"invalid_event\",\n \"idempotency_conflict\",\n \"sequence_conflict\",\n \"fence_lost\",\n \"queue_overflow\",\n \"journal_closed\",\n \"sink_failed\",\n \"read_failed\",\n \"decode_failed\",\n \"projection_failed\",\n \"checkpoint_invalid\",\n \"reader_behind\",\n \"compacted\",\n \"unknown\"\n])\n\n/**\n * Stable error codes returned by journal operations.\n *\n * @category models\n * @since 0.1.0\n */\nexport type JournalErrorCode = typeof JournalErrorCode.Type\n\n/**\n * Error raised by journal admission, persistence, replay, or projection.\n *\n * `checkpointSeq` is set on the compaction-aware codes: on `compacted` it is\n * the run's compaction floor, the checkpoint sequence a reader must resync\n * from, and on `reader_behind` it is the checkpoint a compaction refused to\n * truncate below.\n *\n * @category errors\n * @since 0.1.0\n */\nexport class JournalError extends Schema.TaggedError<JournalError>()(\"@smthrs/journal/JournalError\", {\n code: JournalErrorCode,\n message: Schema.String,\n cause: Schema.optional(Schema.Unknown),\n checkpointSeq: Schema.optional(Seq)\n}) {}\n\n/**\n * Policy applied when the non-blocking admission queue is full.\n *\n * @category models\n * @since 0.1.0\n */\nexport const OverflowPolicy = Schema.Literals([\"reject\", \"drop-newest\", \"drop-oldest\"])\n\n/**\n * Policy applied when the non-blocking admission queue is full.\n *\n * @category models\n * @since 0.1.0\n */\nexport type OverflowPolicy = typeof OverflowPolicy.Type\n\n/**\n * Receipt for a newly admitted event.\n *\n * On the lossy channel, `seq` and `sourceSeq` are allocated synchronously and\n * returned before SQL commits. This `seq` is provisional: the SQL writer\n * moves it above the committed tail if another commit overtakes its reservation.\n * Use committed entries for durable cursors. On the durable channel, the same\n * receipt shape is returned only after the entry commits. `seq` orders the run;\n * `sourceSeq` identifies producer retries and does not change at commit.\n *\n * @category models\n * @since 0.1.0\n */\nexport const Accepted = Schema.TaggedStruct(\"Accepted\", {\n seq: Seq,\n sourceSeq: SourceSeq,\n evicted: Schema.optionalKey(Schema.Struct({\n policy: Schema.Literal(\"drop-oldest\"),\n count: Schema.Int.check(Schema.isGreaterThan(0))\n }))\n})\n\n/**\n * Receipt for a newly admitted event.\n *\n * @category models\n * @since 0.1.0\n */\nexport type Accepted = typeof Accepted.Type\n\n/**\n * Receipt for an exact retry of an already pending or committed source event.\n *\n * `seq` is the original event's sequence, provisional while pending and\n * canonical after commit. A duplicate does not allocate another sequence or\n * enqueue another write. `status` distinguishes\n * an optimistic retry from one whose original event is already durable.\n *\n * @category models\n * @since 0.1.0\n */\nexport const Duplicate = Schema.TaggedStruct(\"Duplicate\", {\n seq: Seq,\n sourceSeq: SourceSeq,\n status: Schema.Literals([\"pending\", \"committed\"])\n})\n\n/**\n * Receipt for an exact producer retry.\n *\n * @category models\n * @since 0.1.0\n */\nexport type Duplicate = typeof Duplicate.Type\n\n/**\n * Receipt for an event discarded by an explicit dropping policy.\n *\n * A dropped admission still consumes its synchronously allocated `seq` and\n * `sourceSeq`, so sequence gaps are expected.\n *\n * @category models\n * @since 0.1.0\n */\nexport const Dropped = Schema.TaggedStruct(\"Dropped\", {\n seq: Seq,\n sourceSeq: SourceSeq,\n policy: Schema.Literal(\"drop-newest\")\n})\n\n/**\n * Receipt for an event discarded by policy.\n *\n * @category models\n * @since 0.1.0\n */\nexport type Dropped = typeof Dropped.Type\n\n/**\n * Receipt union for admission that may use the lossy queue.\n *\n * @category models\n * @since 0.1.0\n */\nexport const EmitReceipt = Schema.Union([Accepted, Duplicate, Dropped])\n\n/**\n * Receipt union for the lossy channel.\n *\n * @category models\n * @since 0.1.0\n */\nexport type EmitReceipt = typeof EmitReceipt.Type\n\n/**\n * Result of a synchronously durable journal admission.\n *\n * A durable admission is never dropped: it either commits, returns the\n * committed sequence of an exact producer retry, or fails.\n *\n * @category models\n * @since 0.1.0\n */\nexport const DurableReceipt = Schema.Union([Accepted, Duplicate])\n\n/**\n * Receipt union for the durable channel.\n *\n * @category models\n * @since 0.1.0\n */\nexport type DurableReceipt = typeof DurableReceipt.Type\n\n/**\n * Cursor used to replay a run and then follow its committed tail.\n *\n * @category models\n * @since 0.1.0\n */\nexport const StreamOptions = Schema.Struct({\n runId: RunId,\n afterSequence: Schema.optionalKey(Seq)\n})\n\n/**\n * Cursor used to replay a run and follow its committed tail.\n *\n * @category models\n * @since 0.1.0\n */\nexport type StreamOptions = typeof StreamOptions.Type\n\n/**\n * Largest page `entries` will read.\n *\n * A page is decoded into memory in full before the caller sees its first\n * entry, so an unbounded limit lets one call materialize a whole run. The\n * largest page any caller in this repository asks for is 512, so this\n * ceiling refuses only a limit that was going to be a memory incident.\n *\n * @since 1.0.0\n * @category constants\n */\nexport const maxEntriesLimit = 10_000\n\n/**\n * Cursor and page size for durable journal reads.\n *\n * `limit` is at most `maxEntriesLimit` (10,000 entries). Optional `eventTypes`\n * selects a nonempty list of at most 64 exact types before pagination; cursors remain canonical run\n * sequences and `hasMore` describes matching entries. Omit it for the full run.\n * Filtering does not bypass the run's compaction floor.\n *\n * @category models\n * @since 0.1.0\n */\nexport const EntriesOptions = Schema.Struct({\n runId: RunId,\n after: Schema.optionalKey(Seq),\n eventTypes: Schema.optionalKey(\n Schema.Array(Entry.fields.eventType).check(Schema.isMinLength(1), Schema.isMaxLength(64))\n ),\n limit: Schema.Int.check(Schema.isGreaterThan(0), Schema.isLessThanOrEqualTo(maxEntriesLimit))\n})\n\n/**\n * Cursor and page size for durable journal reads.\n *\n * @category models\n * @since 0.1.0\n */\nexport type EntriesOptions = typeof EntriesOptions.Type\n\n/**\n * One page of canonical durable journal entries.\n *\n * @category models\n * @since 0.1.0\n */\nexport const EntriesPage = Schema.Struct({\n entries: Schema.Array(Entry),\n hasMore: Schema.Boolean\n})\n\n/**\n * One page of durable journal entries.\n *\n * @category models\n * @since 0.1.0\n */\nexport type EntriesPage = typeof EntriesPage.Type\n\n/**\n * A durable checkpoint: the caller-captured state that replays a run from\n * `seq` without the entries before it.\n *\n * `state` is the caller's own replay snapshot and round-trips verbatim: the\n * journal never interprets it, and redaction deliberately does not apply,\n * exactly as it does not apply to executable state. A checkpoint at `seq`\n * must subsume every entry with a sequence at or below `seq`: replay is\n * `state` plus `stream({ runId, afterSequence: seq })`.\n *\n * `compactedAtMs` is `null` until a compaction has truncated the entries\n * strictly below `seq`. The largest compacted `seq` for a run is its\n * compaction floor.\n *\n * Prior art: Temporal's mutable state, a durable snapshot pinned to a\n * history offset, with history below it never replayed\n * (`reference/temporal/common/persistence/data_interfaces.go`,\n * `WorkflowSnapshot`).\n *\n * @category models\n * @since 0.1.0\n */\nexport class Checkpoint extends Schema.Class<Checkpoint>(\"@smthrs/journal/Journal/Checkpoint\")({\n runId: RunId,\n seq: Seq,\n state: Schema.Unknown,\n createdAtMs: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n compactedAtMs: Schema.NullOr(Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)))\n}) {}\n\n/**\n * Arguments for writing a checkpoint.\n *\n * `seq` must name a committed entry of the run: the surviving row is what\n * keeps the run's durable `MAX(seq)` allocation floor at or above the\n * compaction boundary, so a process restarted after compaction can never\n * re-allocate a truncated sequence.\n *\n * @category models\n * @since 0.1.0\n */\nexport const CheckpointOptions = Schema.Struct({\n runId: RunId,\n seq: Seq,\n state: Schema.Unknown\n})\n\n/**\n * Arguments for writing a checkpoint.\n *\n * @category models\n * @since 0.1.0\n */\nexport type CheckpointOptions = typeof CheckpointOptions.Type\n\n/**\n * Arguments for compacting a run.\n *\n * `upTo` selects the checkpoint to truncate below; omitted, the run's latest\n * checkpoint is used.\n *\n * @category models\n * @since 0.1.0\n */\nexport const CompactOptions = Schema.Struct({\n runId: RunId,\n upTo: Schema.optionalKey(Seq)\n})\n\n/**\n * Arguments for compacting a run.\n *\n * @category models\n * @since 0.1.0\n */\nexport type CompactOptions = typeof CompactOptions.Type\n\n/**\n * Receipt for a completed compaction.\n *\n * `deleted` is `0` when the checkpoint was already the compaction floor, a\n * retried compaction is idempotent.\n *\n * @category models\n * @since 0.1.0\n */\nexport const Compacted = Schema.Struct({\n runId: RunId,\n checkpointSeq: Seq,\n deleted: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0))\n})\n\n/**\n * Receipt for a completed compaction.\n *\n * @category models\n * @since 0.1.0\n */\nexport type Compacted = typeof Compacted.Type\n\n/**\n * Journal operations.\n *\n * There are two sequence domains:\n *\n * - `seq` is reserved synchronously per run. A lossy reservation is provisional;\n * the SQL writer moves it above the committed tail if overtaken. The committed\n * sequence is the canonical order for replay, paging, streams, and projections.\n * - `sourceSeq` is assigned synchronously per `(runId, sourceId)`, or supplied\n * by the producer, and is the idempotency key for producer retries.\n *\n * Rejected or dropped admissions consume both allocations, so gaps are valid.\n * A retry the in-process index still holds returns `Duplicate` with the\n * original `seq` (provisional while pending) and consumes neither allocation.\n *\n * A retry it no longer holds is admitted optimistically and settled by\n * `UNIQUE (run_id, source_id, source_seq)` at the insert: admission issues no\n * dedup read, so the receipt is `Accepted`, the entry collapses onto the\n * committed row instead of doubling it, and a reused identity carrying\n * different bytes surfaces its `idempotency_conflict` through `flush` rather\n * than through the emit. The read is deliberately absent. `emitLossy` exists\n * to be callable from inside somebody else's open write transaction, and a\n * SELECT there waits on the writer that is waiting on the caller: the agent\n * executor's exit flush deadlocked exactly so. What a producer keeps in\n * exchange is the choice of what a collision means, through `Input.dedupe`.\n *\n * This table is Smithers' logical (domain) write-ahead log and is intended to\n * become the authoritative state history. The storage engine's own WAL\n * underneath it is a durability substrate only and is never consumed as the\n * application event API. A durable boundary must not advance a run or expose\n * its result until its lifecycle entry is committed. No local commit makes a\n * remote effect atomic, so external effects still need idempotency keys,\n * fencing tokens, or compensation.\n *\n * `emitDurable` allocates `seq` inside the writer's SQL transaction, so the\n * returned sequence is already committed and independent writers never fork\n * the per-run clock.\n *\n * Caveat on scope: the stores above this log (`RunStore`, `AttemptStore`,\n * `CacheStore`, and engine-store's `DurableEngineState`) hold the executable\n * authoritative state, and no state is derived from these entries today.\n * `transact` is what keeps the two halves consistent anyway: a state\n * transition and the lifecycle entry describing it are appended in ONE write\n * transaction, so a crash can never leave durable state the journal does not\n * explain (or an entry for a transition that never landed).\n *\n * The surface is split into two channels:\n *\n * - The lifecycle channel, `emitDurable`, returns `DurableReceipt`, so a\n * dropped lifecycle event is unrepresentable: the write commits, dedupes, or\n * fails with a typed error.\n * - The lossy channel, `emitLossy`, keeps the optimistic queue and its\n * overflow policies for telemetry, where `Dropped` receipts and\n * `drop-oldest` evictions are acceptable.\n *\n * `emitDurable` is fenced on the run's ownership as arbitrated by the\n * injected `Consensus` strategy: the caller hands over its `OwnerId`, the\n * durable insert only commits while that strategy still records the owner as\n * holding the run, and a reclaimed run fails the write with a `fence_lost`\n * error. The fence is mandatory on the lifecycle channel: a lifecycle write is\n * what advances a run, and a zombie owner must not advance anything. The one\n * escape is {@link Service.emitDurableUnfenced}, for the rare admission that\n * is genuinely ownerless.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Service {\n /**\n * The durable rewind generation and its archive boundary. An append-only\n * adapter may omit this operation, which means generation zero forever.\n * Rewinding adapters must advance the generation atomically with truncation.\n */\n readonly generation?:\n | ((runId: RunId) => Effect.Effect<{\n readonly generation: number\n readonly afterSeq: number\n }, JournalError>)\n | undefined\n readonly emitLossy: (input: Input) => Effect.Effect<EmitReceipt, JournalError>\n readonly emitDurable: (input: Input, owner: OwnerId) => Effect.Effect<DurableReceipt, JournalError>\n /**\n * The unfenced durable write: same durability and receipt contract as\n * {@link Service.emitDurable}, with no ownership fence.\n *\n * This exists ONLY for admissions that are genuinely ownerless: writes\n * whose correctness does not depend on who currently owns the run because\n * they are first-writer-wins by design. The canonical case is the\n * external-trigger admission: a deferred completion or clock-schedule\n * record delivered by a sweeper that owns nothing, where the dedup index,\n * not the fence, is the idempotency mechanism. A caller that holds an\n * `OwnerId` must use `emitDurable`; reaching for this channel to dodge a\n * `fence_lost` is exactly the zombie write the fence exists to reject.\n */\n readonly emitDurableUnfenced: (input: Input) => Effect.Effect<DurableReceipt, JournalError>\n /**\n * Runs `effect`, a state projection plus the `emitDurable` calls describing\n * it, inside ONE write transaction.\n *\n * This is the seam that makes the logical WAL crash-consistent with\n * executable state. The stores above the journal (`RunStore`,\n * `AttemptStore`, `CacheStore`, `DurableEngineState`) write through the same\n * `DurableWriter`, so their writes join this transaction as savepoints: either\n * the transition and its lifecycle entry both commit, or neither does. It is\n * the local analogue of Temporal closing mutable state into a mutation plus\n * event batches and submitting them as one persistence request\n * (`reference/temporal/service/history/workflow/transaction_impl.go`).\n *\n * A `Duplicate` receipt is unaffected: an exact producer retry still\n * collapses onto the already-committed sequence.\n *\n * Two consequences a caller must plan for:\n *\n * - Publication (`changes`, `stream`, and the in-process source-event index)\n * is deferred until the transaction commits, so a subscriber never\n * observes an entry that later rolls back, and a rolled-back producer\n * identity stays re-emittable rather than deduplicating against a\n * sequence that does not exist.\n * - Everything inside runs while a write transaction is open. Keep it to\n * storage work: no flow bodies, no host calls, no waits.\n *\n * Nesting is safe: an inner `transact` becomes a savepoint of the outer\n * one and defers its publication to the outermost commit.\n */\n readonly transact: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E | JournalError, R>\n /**\n * Publishes a short, non-failing process-local update after the current\n * transaction commits, or immediately when no transaction is open.\n *\n * Returns false without publishing inside a raw SQL transaction whose\n * commit this journal cannot observe. A true result can mean deferred, not\n * already run. Failed savepoints and retries discard their registrations.\n * Test doubles that implement transactions must preserve this contract.\n */\n readonly whenCommitted: (update: Effect.Effect<void>) => Effect.Effect<boolean>\n /**\n * Replays the run's durable history from `afterSequence`, then follows it.\n *\n * This is the lossless follower. It pages the history rather than\n * materializing it, so the first entry arrives after one page rather than\n * after the whole run; it reports a sink loss that happens while it is\n * following; and a cursor below the run's compaction floor fails with\n * `compacted` and the sequence to resync from, never a silently shortened\n * history.\n */\n readonly stream: (options: StreamOptions) => Stream.Stream<Entry, JournalError>\n /**\n * Reads one page of the run's durable history in sequence order.\n *\n * `hasMore` reports whether another page follows. A cursor below the run's\n * compaction floor fails with `compacted`, exactly as `stream` does, so a\n * poller and a follower cannot disagree about what history exists.\n */\n readonly entries: (options: EntriesOptions) => Effect.Effect<EntriesPage, JournalError>\n /**\n * Subscribes to entries this process commits, across every run.\n *\n * This is a bounded SLIDING buffer sized by the layer's `capacity`: a slow\n * consumer silently loses entries, with no error and no gap signal. Use it\n * for a local tail or a UI feed, and use `stream` wherever a missing entry\n * would be a correctness bug, because that is the lossless path and the one\n * that reports sink losses.\n *\n * Only this process's commits arrive here. Another writer on the same\n * database publishes into its own buffer, which is the second reason\n * `stream` exists: it rechecks the durable tail.\n *\n * Published entries are deeply frozen, so one subscriber cannot mutate the\n * value another subscriber is about to read.\n */\n readonly changes: Effect.Effect<PubSub.Subscription<Entry>, never, Scope.Scope>\n readonly project: <S, E, R>(\n projection: Projection<S, E, R>,\n options: StreamOptions\n ) => Stream.Stream<S, JournalError, R>\n readonly flush: Effect.Effect<void, JournalError>\n /**\n * Durably records the state that replays the run from `options.seq`.\n *\n * The write shares `transact`'s discipline: it runs through the same\n * `DurableWriter`, so inside an open `transact` it joins the caller's\n * transaction as a savepoint and rolls back with it. `options.seq` must\n * name a committed entry and must lie above the run's compaction floor;\n * otherwise the write fails with `checkpoint_invalid`. Re-checkpointing an\n * uncompacted `seq` replaces its state: last writer wins.\n *\n * The write is fenced on the run's ownership through the consensus\n * strategy, exactly as `emitDurable` is: a reclaimed run fails with\n * `fence_lost`. The fence is mandatory: a zombie owner must not replace\n * replay state behind a live successor.\n */\n readonly checkpoint: (options: CheckpointOptions, owner: OwnerId) => Effect.Effect<Checkpoint, JournalError>\n /**\n * Reads the run's most recent checkpoint, compacted or not.\n *\n * A reader that fails with `compacted` resyncs here: apply\n * `checkpoint.state`, then continue from\n * `stream({ runId, afterSequence: checkpoint.seq })`.\n */\n readonly latestCheckpoint: (runId: RunId) => Effect.Effect<Option.Option<Checkpoint>, JournalError>\n /**\n * Deletes the run's entries strictly below a checkpoint, atomically with\n * advancing the run's compaction floor.\n *\n * Refusals are typed: `checkpoint_invalid` when the run has no checkpoint\n * to truncate below, `reader_behind` when a live in-process stream still\n * needs a sequence the truncation would delete, and `fence_lost` when the\n * supplied `owner` no longer holds the run. The fence is mandatory, so a\n * zombie owner can never truncate history behind a live successor. Readers\n * this process cannot see (pollers of `entries` and followers in other\n * processes) are protected by the read-side guard instead: any read whose cursor starts\n * below the floor fails with `compacted` and the floor to resync from,\n * never a silently shortened history.\n */\n readonly compact: (options: CompactOptions, owner: OwnerId) => Effect.Effect<Compacted, JournalError>\n}\n\n/**\n * Context service for durable lifecycle evidence and lossy telemetry.\n *\n * @category services\n * @since 0.1.0\n */\nexport class Journal extends Context.Service<Journal, Service>()(\"@smthrs/journal/Journal\") {}\n\n/**\n * Constructs a journal service from an implementation.\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const make = (implementation: Service): Service => Journal.of(implementation)\n\nconst unavailable = (method: string): JournalError =>\n new JournalError({\n code: \"journal_closed\",\n message: `${method} is unavailable`\n })\n\n/**\n * Constructs a closed journal stub, optionally overriding individual methods.\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const makeNoop = (overrides: Partial<Service> = {}): Service => {\n const service: Service = {\n emitLossy: Effect.fn(\"Journal.emitLossy\")(() => Effect.fail(unavailable(\"emitLossy\"))),\n emitDurable: Effect.fn(\"Journal.emitDurable\")(() => Effect.fail(unavailable(\"emitDurable\"))),\n emitDurableUnfenced: Effect.fn(\"Journal.emitDurableUnfenced\")(() =>\n Effect.fail(unavailable(\"emitDurableUnfenced\"))\n ),\n /**\n * The closed stub has no sink and therefore no transaction to open, so it\n * runs the effect directly, the same posture as\n * `DurableEngineState`'s in-memory twin, whose `transaction` has no crash\n * window to close. A test double that models rollback overrides it.\n */\n transact: <A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E | JournalError, R> => effect,\n whenCommitted: (update) => Effect.as(update, true),\n stream: (options) =>\n Stream.unwrap(\n Effect.fn(\"Journal.stream\")((_options: StreamOptions) => Effect.succeed(Stream.fail(unavailable(\"stream\"))))(\n options\n )\n ),\n entries: Effect.fn(\"Journal.entries\")(() => Effect.fail(unavailable(\"entries\"))),\n changes: Effect.acquireRelease(\n PubSub.sliding<Entry>(1),\n PubSub.shutdown\n ).pipe(Effect.flatMap(PubSub.subscribe)),\n project: (projection, options) =>\n Stream.unwrap(\n Effect.fn(\"Journal.project\")(\n <S, E, R>(_projection: Projection<S, E, R>, _options: StreamOptions) =>\n Effect.succeed(Stream.fail(unavailable(\"project\")))\n )(projection, options)\n ),\n flush: Effect.fn(\"Journal.flush\")(() => Effect.fail(unavailable(\"flush\")))(),\n checkpoint: Effect.fn(\"Journal.checkpoint\")(() => Effect.fail(unavailable(\"checkpoint\"))),\n latestCheckpoint: Effect.fn(\"Journal.latestCheckpoint\")(() => Effect.fail(unavailable(\"latestCheckpoint\"))),\n compact: Effect.fn(\"Journal.compact\")(() => Effect.fail(unavailable(\"compact\")))\n }\n return Journal.of({ ...service, ...overrides })\n}\n\n/**\n * Provides a closed journal stub.\n *\n * @category layers\n * @since 0.1.0\n */\nexport const layerNoop = (overrides: Partial<Service> = {}): Layer.Layer<Journal> =>\n Layer.succeed(Journal)(makeNoop(overrides))\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable event-envelope schemas for the journal.
|
|
3
|
+
*
|
|
4
|
+
* @since 0.1.0
|
|
5
|
+
*/
|
|
6
|
+
import * as Schema from "effect/Schema";
|
|
7
|
+
/**
|
|
8
|
+
* Longest identifier the journal persists.
|
|
9
|
+
*
|
|
10
|
+
* A run id, a source id and an event type are index columns of a permanent
|
|
11
|
+
* table and are held in per-run maps for the layer's lifetime, so an
|
|
12
|
+
* unbounded one costs durable index space and heap that nothing ever
|
|
13
|
+
* reclaims. Every identifier this repository mints is a uuid or a short
|
|
14
|
+
* dotted name, two orders of magnitude below this bound, so the ceiling
|
|
15
|
+
* refuses only the shapes that were never identifiers.
|
|
16
|
+
*
|
|
17
|
+
* @since 1.0.0
|
|
18
|
+
* @category constants
|
|
19
|
+
*/
|
|
20
|
+
export declare const maxIdentifierLength = 1024;
|
|
21
|
+
/**
|
|
22
|
+
* Schema for an identifier of one durable run.
|
|
23
|
+
*
|
|
24
|
+
* Between 1 and 1,024 UTF-16 code units, free of unpaired UTF-16 surrogates
|
|
25
|
+
* because the store cannot tell two ill-formed identifiers apart, and free of
|
|
26
|
+
* NUL because the store's own length check cannot see past one.
|
|
27
|
+
*
|
|
28
|
+
* @category schemas
|
|
29
|
+
* @since 0.1.0
|
|
30
|
+
*/
|
|
31
|
+
export declare const RunId: Schema.brand<Schema.String, "@smthrs/journal/JournalEvent/RunId">;
|
|
32
|
+
/**
|
|
33
|
+
* Branded identifier of one durable run.
|
|
34
|
+
*
|
|
35
|
+
* @category models
|
|
36
|
+
* @since 0.1.0
|
|
37
|
+
*/
|
|
38
|
+
export type RunId = typeof RunId.Type;
|
|
39
|
+
/**
|
|
40
|
+
* Schema for the canonical, durable sequence number within a run.
|
|
41
|
+
*
|
|
42
|
+
* `Number.MAX_SAFE_INTEGER` is excluded because the journal must always be
|
|
43
|
+
* able to allocate the next sequence. `Number.MAX_SAFE_INTEGER + 1` is not a
|
|
44
|
+
* distinct integer, so the maximum is not an allocatable sequence.
|
|
45
|
+
*
|
|
46
|
+
* @category schemas
|
|
47
|
+
* @since 0.1.0
|
|
48
|
+
*/
|
|
49
|
+
export declare const Seq: Schema.brand<Schema.Int, "@smthrs/journal/JournalEvent/Seq">;
|
|
50
|
+
/**
|
|
51
|
+
* Canonical durable per-run sequence number.
|
|
52
|
+
*
|
|
53
|
+
* @category models
|
|
54
|
+
* @since 0.1.0
|
|
55
|
+
*/
|
|
56
|
+
export type Seq = typeof Seq.Type;
|
|
57
|
+
/**
|
|
58
|
+
* Schema for an event producer identifier.
|
|
59
|
+
*
|
|
60
|
+
* The same shape `RunId` accepts, on the same terms: the pair identifies a
|
|
61
|
+
* producer's retries in the database.
|
|
62
|
+
*
|
|
63
|
+
* @category schemas
|
|
64
|
+
* @since 0.1.0
|
|
65
|
+
*/
|
|
66
|
+
export declare const SourceId: Schema.brand<Schema.String, "@smthrs/journal/JournalEvent/SourceId">;
|
|
67
|
+
/**
|
|
68
|
+
* Identifier of an event producer.
|
|
69
|
+
*
|
|
70
|
+
* @category models
|
|
71
|
+
* @since 0.1.0
|
|
72
|
+
*/
|
|
73
|
+
export type SourceId = typeof SourceId.Type;
|
|
74
|
+
/**
|
|
75
|
+
* Schema for a producer-local event sequence number.
|
|
76
|
+
*
|
|
77
|
+
* `Number.MAX_SAFE_INTEGER` is excluded because the journal must always be
|
|
78
|
+
* able to allocate the next sequence. `Number.MAX_SAFE_INTEGER + 1` is not a
|
|
79
|
+
* distinct integer, so the maximum is not an allocatable sequence.
|
|
80
|
+
*
|
|
81
|
+
* @category schemas
|
|
82
|
+
* @since 0.1.0
|
|
83
|
+
*/
|
|
84
|
+
export declare const SourceSeq: Schema.brand<Schema.Int, "@smthrs/journal/JournalEvent/SourceSeq">;
|
|
85
|
+
/**
|
|
86
|
+
* Producer-local event sequence number.
|
|
87
|
+
*
|
|
88
|
+
* @category models
|
|
89
|
+
* @since 0.1.0
|
|
90
|
+
*/
|
|
91
|
+
export type SourceSeq = typeof SourceSeq.Type;
|
|
92
|
+
/**
|
|
93
|
+
* Schema for what a re-emitted `(runId, sourceId, sourceSeq)` identity means.
|
|
94
|
+
*
|
|
95
|
+
* `content` is the default and the strict reading: the identity names one set
|
|
96
|
+
* of bytes, so a producer that re-emits it with different bytes has a bug and
|
|
97
|
+
* the journal says so with `idempotency_conflict`.
|
|
98
|
+
*
|
|
99
|
+
* `identity` is for a producer that derives the sequence from the event
|
|
100
|
+
* itself. There a collision IS the same event observed twice, and the bytes
|
|
101
|
+
* that differ between the two observations are metadata ABOUT the observation
|
|
102
|
+
* rather than the event: when a replayed frame was re-recorded, how long a
|
|
103
|
+
* step took the second time a durable engine served it from its record. The
|
|
104
|
+
* first admitted row stands and the re-emission settles as `Duplicate`. Only
|
|
105
|
+
* declare it with a sequence derived from the event's own content, because
|
|
106
|
+
* the journal then has nothing else with which to notice two different events
|
|
107
|
+
* wearing one identity.
|
|
108
|
+
*
|
|
109
|
+
* @category schemas
|
|
110
|
+
* @since 0.1.0
|
|
111
|
+
*/
|
|
112
|
+
export declare const Dedupe: Schema.Literals<readonly ["content", "identity"]>;
|
|
113
|
+
/**
|
|
114
|
+
* What a re-emitted producer identity means.
|
|
115
|
+
*
|
|
116
|
+
* @category models
|
|
117
|
+
* @since 0.1.0
|
|
118
|
+
*/
|
|
119
|
+
export type Dedupe = typeof Dedupe.Type;
|
|
120
|
+
declare const Input_base: Schema.Class<Input, Schema.Struct<{
|
|
121
|
+
readonly runId: Schema.brand<Schema.String, "@smthrs/journal/JournalEvent/RunId">;
|
|
122
|
+
readonly sourceId: Schema.brand<Schema.String, "@smthrs/journal/JournalEvent/SourceId">;
|
|
123
|
+
readonly sourceSeq: Schema.optional<Schema.brand<Schema.Int, "@smthrs/journal/JournalEvent/SourceSeq">>;
|
|
124
|
+
/** How a collision on this event's identity is settled. Defaults to `content`. */
|
|
125
|
+
readonly dedupe: Schema.optional<Schema.Literals<readonly ["content", "identity"]>>;
|
|
126
|
+
/** Non-empty, NUL-free, well-formed UTF-16 of at most 1,024 code units. */
|
|
127
|
+
readonly eventType: Schema.String;
|
|
128
|
+
readonly payload: Schema.Unknown;
|
|
129
|
+
readonly meta: Schema.optional<Schema.Unknown>;
|
|
130
|
+
}>, {}>;
|
|
131
|
+
/**
|
|
132
|
+
* Schema for an event submitted to the journal.
|
|
133
|
+
*
|
|
134
|
+
* Event types and values intentionally remain an open envelope. The durable
|
|
135
|
+
* core never closes this into an interpreter-specific union.
|
|
136
|
+
*
|
|
137
|
+
* @category schemas
|
|
138
|
+
* @since 0.1.0
|
|
139
|
+
*/
|
|
140
|
+
export declare class Input extends Input_base {
|
|
141
|
+
}
|
|
142
|
+
declare const Entry_base: Schema.Class<Entry, Schema.Struct<{
|
|
143
|
+
readonly runId: Schema.brand<Schema.String, "@smthrs/journal/JournalEvent/RunId">;
|
|
144
|
+
readonly seq: Schema.brand<Schema.Int, "@smthrs/journal/JournalEvent/Seq">;
|
|
145
|
+
/**
|
|
146
|
+
* Derived by {@link makeEventId} from the other three identity members, never
|
|
147
|
+
* supplied by a caller, so it carries no check of its own.
|
|
148
|
+
*/
|
|
149
|
+
readonly eventId: Schema.String;
|
|
150
|
+
readonly sourceId: Schema.brand<Schema.String, "@smthrs/journal/JournalEvent/SourceId">;
|
|
151
|
+
readonly sourceSeq: Schema.brand<Schema.Int, "@smthrs/journal/JournalEvent/SourceSeq">;
|
|
152
|
+
readonly emittedAtMs: Schema.Int;
|
|
153
|
+
/**
|
|
154
|
+
* The same bounded identifier `Input.eventType` accepts. It used to be a bare
|
|
155
|
+
* `Schema.String` here, so a consumer decoding an `Entry` accepted an empty,
|
|
156
|
+
* over-long, NUL-bearing, or ill-formed-UTF-16 event type that no emit could
|
|
157
|
+
* ever have produced.
|
|
158
|
+
*/
|
|
159
|
+
readonly eventType: Schema.String;
|
|
160
|
+
readonly payload: Schema.Unknown;
|
|
161
|
+
readonly meta: Schema.Unknown;
|
|
162
|
+
}>, {}>;
|
|
163
|
+
/**
|
|
164
|
+
* Schema for a committed durable journal row.
|
|
165
|
+
*
|
|
166
|
+
* `seq` is allocated synchronously at journal admission and is the only
|
|
167
|
+
* sequence used for replay and durable provenance. `sourceSeq` identifies
|
|
168
|
+
* retries from one producer.
|
|
169
|
+
*
|
|
170
|
+
* @category schemas
|
|
171
|
+
* @since 0.1.0
|
|
172
|
+
*/
|
|
173
|
+
export declare class Entry extends Entry_base {
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Makes a collision-free deterministic event identifier from the idempotency
|
|
177
|
+
* key `(runId, sourceId, sourceSeq)`.
|
|
178
|
+
*
|
|
179
|
+
* Length prefixes preserve tuple boundaries even when identifiers contain the
|
|
180
|
+
* separator. The value is deliberately not random: retrying the same source
|
|
181
|
+
* event must produce the same durable id.
|
|
182
|
+
*
|
|
183
|
+
* @category constructors
|
|
184
|
+
* @since 0.1.0
|
|
185
|
+
*/
|
|
186
|
+
export declare const makeEventId: (runId: RunId, sourceId: SourceId, sourceSeq: SourceSeq) => string;
|
|
187
|
+
/**
|
|
188
|
+
* The reserved prefix of every companion stream id.
|
|
189
|
+
*
|
|
190
|
+
* A run id that begins with it names a companion stream, never a run: stores
|
|
191
|
+
* that admit run ids (`@smthrs/run-store`'s `RunStore.create`) refuse it.
|
|
192
|
+
*
|
|
193
|
+
* @category constants
|
|
194
|
+
* @since 1.0.0
|
|
195
|
+
*/
|
|
196
|
+
export declare const companionPrefix = "flows.companion/";
|
|
197
|
+
/**
|
|
198
|
+
* The digest a journal fact uses to reference bytes kept outside the journal:
|
|
199
|
+
* the SHA-256 of the UTF-8 encoding of `text`, as 64 lowercase hex digits.
|
|
200
|
+
*
|
|
201
|
+
* The journal redacts every payload, so a fact never carries executable
|
|
202
|
+
* values. A store that folds state from its facts keeps the bytes in its own
|
|
203
|
+
* rows and records only their digest, which a rebuild checks the row against.
|
|
204
|
+
*
|
|
205
|
+
* @category constructors
|
|
206
|
+
* @since 1.0.0
|
|
207
|
+
*/
|
|
208
|
+
export declare const contentDigest: (text: string) => string;
|
|
209
|
+
/**
|
|
210
|
+
* The id of the companion stream that carries one store's facts about a run.
|
|
211
|
+
*
|
|
212
|
+
* A companion stream is an ordinary journal stream with its own sequence
|
|
213
|
+
* clock, kept beside the run's own stream rather than inside it. A consumer
|
|
214
|
+
* that reads the run's stream by position never sees a companion fact, and a
|
|
215
|
+
* rewind or compaction of the run's stream never truncates one. The id is
|
|
216
|
+
* `flows.companion/<stream>/<sha-256 of the run id>`, so it stays within
|
|
217
|
+
* {@link maxIdentifierLength} for every run id; each fact carries its run id
|
|
218
|
+
* in its payload.
|
|
219
|
+
*
|
|
220
|
+
* @category constructors
|
|
221
|
+
* @since 1.0.0
|
|
222
|
+
*/
|
|
223
|
+
export declare const companionRunId: (stream: string, runId: string) => RunId;
|
|
224
|
+
/**
|
|
225
|
+
* Whether a run id names a companion stream.
|
|
226
|
+
*
|
|
227
|
+
* @category predicates
|
|
228
|
+
* @since 1.0.0
|
|
229
|
+
*/
|
|
230
|
+
export declare const isCompanionRunId: (runId: string) => boolean;
|
|
231
|
+
/**
|
|
232
|
+
* Bounded durable text shared by namespace contracts.
|
|
233
|
+
*
|
|
234
|
+
* @category schemas
|
|
235
|
+
* @since 1.0.0
|
|
236
|
+
*/
|
|
237
|
+
export declare const Identifier: Schema.String;
|
|
238
|
+
/**
|
|
239
|
+
* A lineage coordinate, distinct from the run that currently hosts it.
|
|
240
|
+
*
|
|
241
|
+
* @category schemas
|
|
242
|
+
* @since 1.0.0
|
|
243
|
+
*/
|
|
244
|
+
export declare const LineageId: Schema.brand<Schema.String, "@smthrs/journal/LineageId">;
|
|
245
|
+
/**
|
|
246
|
+
* A lineage coordinate.
|
|
247
|
+
*
|
|
248
|
+
* @category models
|
|
249
|
+
* @since 1.0.0
|
|
250
|
+
*/
|
|
251
|
+
export type LineageId = typeof LineageId.Type;
|
|
252
|
+
/**
|
|
253
|
+
* A concrete wait identity.
|
|
254
|
+
*
|
|
255
|
+
* @category schemas
|
|
256
|
+
* @since 1.0.0
|
|
257
|
+
*/
|
|
258
|
+
export declare const WaitId: Schema.brand<Schema.String, "@smthrs/journal/WaitId">;
|
|
259
|
+
/**
|
|
260
|
+
* A concrete wait identity.
|
|
261
|
+
*
|
|
262
|
+
* @category models
|
|
263
|
+
* @since 1.0.0
|
|
264
|
+
*/
|
|
265
|
+
export type WaitId = typeof WaitId.Type;
|
|
266
|
+
/**
|
|
267
|
+
* An admitted command identity.
|
|
268
|
+
*
|
|
269
|
+
* @category schemas
|
|
270
|
+
* @since 1.0.0
|
|
271
|
+
*/
|
|
272
|
+
export declare const CommandId: Schema.brand<Schema.String, "@smthrs/journal/CommandId">;
|
|
273
|
+
/**
|
|
274
|
+
* An admitted command identity.
|
|
275
|
+
*
|
|
276
|
+
* @category models
|
|
277
|
+
* @since 1.0.0
|
|
278
|
+
*/
|
|
279
|
+
export type CommandId = typeof CommandId.Type;
|
|
280
|
+
/**
|
|
281
|
+
* A plan identity, never interchangeable with a dispatch or artifact.
|
|
282
|
+
*
|
|
283
|
+
* @category schemas
|
|
284
|
+
* @since 1.0.0
|
|
285
|
+
*/
|
|
286
|
+
export declare const PlanId: Schema.brand<Schema.String, "@smthrs/journal/PlanId">;
|
|
287
|
+
/**
|
|
288
|
+
* A plan identity.
|
|
289
|
+
*
|
|
290
|
+
* @category models
|
|
291
|
+
* @since 1.0.0
|
|
292
|
+
*/
|
|
293
|
+
export type PlanId = typeof PlanId.Type;
|
|
294
|
+
/**
|
|
295
|
+
* A dispatch identity. Branding does not verify its digest.
|
|
296
|
+
*
|
|
297
|
+
* @category schemas
|
|
298
|
+
* @since 1.0.0
|
|
299
|
+
*/
|
|
300
|
+
export declare const DispatchId: Schema.brand<Schema.String, "@smthrs/journal/DispatchId">;
|
|
301
|
+
/**
|
|
302
|
+
* A dispatch identity.
|
|
303
|
+
*
|
|
304
|
+
* @category models
|
|
305
|
+
* @since 1.0.0
|
|
306
|
+
*/
|
|
307
|
+
export type DispatchId = typeof DispatchId.Type;
|
|
308
|
+
/**
|
|
309
|
+
* An artifact identity. Branding does not verify content.
|
|
310
|
+
*
|
|
311
|
+
* @category schemas
|
|
312
|
+
* @since 1.0.0
|
|
313
|
+
*/
|
|
314
|
+
export declare const ArtifactId: Schema.brand<Schema.String, "@smthrs/journal/ArtifactId">;
|
|
315
|
+
/**
|
|
316
|
+
* An artifact identity.
|
|
317
|
+
*
|
|
318
|
+
* @category models
|
|
319
|
+
* @since 1.0.0
|
|
320
|
+
*/
|
|
321
|
+
export type ArtifactId = typeof ArtifactId.Type;
|
|
322
|
+
/**
|
|
323
|
+
* Integer quantities in the inclusive safe range, including zero.
|
|
324
|
+
*
|
|
325
|
+
* @category schemas
|
|
326
|
+
* @since 1.0.0
|
|
327
|
+
*/
|
|
328
|
+
export declare const NonNegativeQuantity: Schema.Int;
|
|
329
|
+
/**
|
|
330
|
+
* Integer quantities in the inclusive safe range, excluding zero.
|
|
331
|
+
*
|
|
332
|
+
* @category schemas
|
|
333
|
+
* @since 1.0.0
|
|
334
|
+
*/
|
|
335
|
+
export declare const PositiveQuantity: Schema.Int;
|
|
336
|
+
/**
|
|
337
|
+
* Non-negative integral milliseconds since the Unix epoch.
|
|
338
|
+
*
|
|
339
|
+
* @category schemas
|
|
340
|
+
* @since 1.0.0
|
|
341
|
+
*/
|
|
342
|
+
export declare const TimestampMs: Schema.brand<Schema.Int, "@smthrs/journal/TimestampMs">;
|
|
343
|
+
/**
|
|
344
|
+
* Non-negative integral milliseconds since the Unix epoch.
|
|
345
|
+
*
|
|
346
|
+
* @category models
|
|
347
|
+
* @since 1.0.0
|
|
348
|
+
*/
|
|
349
|
+
export type TimestampMs = typeof TimestampMs.Type;
|
|
350
|
+
/**
|
|
351
|
+
* Decode a run id without a cast; schema failures retain their issue.
|
|
352
|
+
*
|
|
353
|
+
* @category decoders
|
|
354
|
+
* @since 1.0.0
|
|
355
|
+
*/
|
|
356
|
+
export declare const decodeRunId: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => import("effect/Effect").Effect<string & import("effect/Brand").Brand<"@smthrs/journal/JournalEvent/RunId">, Schema.SchemaError, never>;
|
|
357
|
+
/**
|
|
358
|
+
* Decode a lineage id without a cast.
|
|
359
|
+
*
|
|
360
|
+
* @category decoders
|
|
361
|
+
* @since 1.0.0
|
|
362
|
+
*/
|
|
363
|
+
export declare const decodeLineageId: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => import("effect/Effect").Effect<string & import("effect/Brand").Brand<"@smthrs/journal/LineageId">, Schema.SchemaError, never>;
|
|
364
|
+
/**
|
|
365
|
+
* Decode a wait id without a cast.
|
|
366
|
+
*
|
|
367
|
+
* @category decoders
|
|
368
|
+
* @since 1.0.0
|
|
369
|
+
*/
|
|
370
|
+
export declare const decodeWaitId: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => import("effect/Effect").Effect<string & import("effect/Brand").Brand<"@smthrs/journal/WaitId">, Schema.SchemaError, never>;
|
|
371
|
+
/**
|
|
372
|
+
* Decode a command id without a cast.
|
|
373
|
+
*
|
|
374
|
+
* @category decoders
|
|
375
|
+
* @since 1.0.0
|
|
376
|
+
*/
|
|
377
|
+
export declare const decodeCommandId: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => import("effect/Effect").Effect<string & import("effect/Brand").Brand<"@smthrs/journal/CommandId">, Schema.SchemaError, never>;
|
|
378
|
+
/**
|
|
379
|
+
* Decode a plan id without a cast.
|
|
380
|
+
*
|
|
381
|
+
* @category decoders
|
|
382
|
+
* @since 1.0.0
|
|
383
|
+
*/
|
|
384
|
+
export declare const decodePlanId: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => import("effect/Effect").Effect<string & import("effect/Brand").Brand<"@smthrs/journal/PlanId">, Schema.SchemaError, never>;
|
|
385
|
+
/**
|
|
386
|
+
* Decode a dispatch id without a cast.
|
|
387
|
+
*
|
|
388
|
+
* @category decoders
|
|
389
|
+
* @since 1.0.0
|
|
390
|
+
*/
|
|
391
|
+
export declare const decodeDispatchId: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => import("effect/Effect").Effect<string & import("effect/Brand").Brand<"@smthrs/journal/DispatchId">, Schema.SchemaError, never>;
|
|
392
|
+
/**
|
|
393
|
+
* Decode an artifact id without a cast.
|
|
394
|
+
*
|
|
395
|
+
* @category decoders
|
|
396
|
+
* @since 1.0.0
|
|
397
|
+
*/
|
|
398
|
+
export declare const decodeArtifactId: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => import("effect/Effect").Effect<string & import("effect/Brand").Brand<"@smthrs/journal/ArtifactId">, Schema.SchemaError, never>;
|
|
399
|
+
/**
|
|
400
|
+
* Decode an absolute timestamp without coercion.
|
|
401
|
+
*
|
|
402
|
+
* @category decoders
|
|
403
|
+
* @since 1.0.0
|
|
404
|
+
*/
|
|
405
|
+
export declare const decodeTimestampMs: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => import("effect/Effect").Effect<number & import("effect/Brand").Brand<"@smthrs/journal/TimestampMs">, Schema.SchemaError, never>;
|
|
406
|
+
/**
|
|
407
|
+
* Decode a budget that permits zero. Units belong to the field.
|
|
408
|
+
*
|
|
409
|
+
* @category decoders
|
|
410
|
+
* @since 1.0.0
|
|
411
|
+
*/
|
|
412
|
+
export declare const decodeNonNegativeQuantity: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => import("effect/Effect").Effect<number, Schema.SchemaError, never>;
|
|
413
|
+
/**
|
|
414
|
+
* Decode a budget that requires positive capacity.
|
|
415
|
+
*
|
|
416
|
+
* @category decoders
|
|
417
|
+
* @since 1.0.0
|
|
418
|
+
*/
|
|
419
|
+
export declare const decodePositiveQuantity: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => import("effect/Effect").Effect<number, Schema.SchemaError, never>;
|
|
420
|
+
export {};
|
|
421
|
+
//# sourceMappingURL=JournalEvent.d.ts.map
|