@claudexor/journal 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/frame-codec.d.ts +46 -0
- package/dist/frame-codec.d.ts.map +1 -0
- package/dist/frame-codec.js +187 -0
- package/dist/frame-codec.js.map +1 -0
- package/dist/index.d.ts +93 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +459 -0
- package/dist/index.js.map +1 -0
- package/package.json +40 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 joi-lab
|
|
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.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export declare const HASH_BYTES = 32;
|
|
2
|
+
export declare const MAX_PAYLOAD_BYTES: number;
|
|
3
|
+
export declare const ZERO_HASH: string;
|
|
4
|
+
export declare const COMPACTED_SNAPSHOT = "journal.compacted_snapshot";
|
|
5
|
+
export interface JournalRecord<T = unknown> {
|
|
6
|
+
partition: string;
|
|
7
|
+
epoch: string;
|
|
8
|
+
seq: number;
|
|
9
|
+
previousFrameHash: string;
|
|
10
|
+
frameHash: string;
|
|
11
|
+
time: string;
|
|
12
|
+
type: string;
|
|
13
|
+
payload: T;
|
|
14
|
+
byteOffset: number;
|
|
15
|
+
}
|
|
16
|
+
export interface FrameHeader {
|
|
17
|
+
partition: string;
|
|
18
|
+
epoch: string;
|
|
19
|
+
seq: number;
|
|
20
|
+
previousFrameHash: string;
|
|
21
|
+
time: string;
|
|
22
|
+
type: string;
|
|
23
|
+
logicalSpan?: number;
|
|
24
|
+
}
|
|
25
|
+
export interface CompactedSnapshotPayload {
|
|
26
|
+
version: 1;
|
|
27
|
+
count: number;
|
|
28
|
+
encoding: "gzip-base64";
|
|
29
|
+
data: string;
|
|
30
|
+
}
|
|
31
|
+
export interface CompactedRecord {
|
|
32
|
+
time: string;
|
|
33
|
+
type: string;
|
|
34
|
+
payload: unknown;
|
|
35
|
+
}
|
|
36
|
+
export interface ReplayResult {
|
|
37
|
+
records: JournalRecord[];
|
|
38
|
+
incompleteOffset: number | null;
|
|
39
|
+
error: {
|
|
40
|
+
offset: number;
|
|
41
|
+
reason: string;
|
|
42
|
+
} | null;
|
|
43
|
+
}
|
|
44
|
+
export declare function replayFrames(bytes: Buffer, partition: string): ReplayResult;
|
|
45
|
+
export declare function encodeFrame(header: FrameHeader, payload: Buffer): Buffer;
|
|
46
|
+
//# sourceMappingURL=frame-codec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frame-codec.d.ts","sourceRoot":"","sources":["../src/frame-codec.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,UAAU,KAAK,CAAC;AAE7B,eAAO,MAAM,iBAAiB,QAAmB,CAAC;AAClD,eAAO,MAAM,SAAS,QAAiB,CAAC;AACxC,eAAO,MAAM,kBAAkB,+BAA+B,CAAC;AAE/D,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,OAAO;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,CAAC,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,iBAAiB,EAAE,MAAM,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,CAAC,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,aAAa,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAClD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,YAAY,CA+F3E;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAexE"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { gunzipSync } from "node:zlib";
|
|
3
|
+
const MAGIC = Buffer.from([0x43, 0x4c, 0x58, 0x4a, 0x4e, 0x4c, 0x32, 0x00]);
|
|
4
|
+
const VERSION = 1;
|
|
5
|
+
const PREFIX_CORE_BYTES = MAGIC.length + 2 + 4 + 4;
|
|
6
|
+
const PREFIX_CHECKSUM_BYTES = 8;
|
|
7
|
+
const PREFIX_BYTES = PREFIX_CORE_BYTES + PREFIX_CHECKSUM_BYTES;
|
|
8
|
+
export const HASH_BYTES = 32;
|
|
9
|
+
const MAX_HEADER_BYTES = 64 * 1024;
|
|
10
|
+
export const MAX_PAYLOAD_BYTES = 16 * 1024 * 1024;
|
|
11
|
+
export const ZERO_HASH = "0".repeat(64);
|
|
12
|
+
export const COMPACTED_SNAPSHOT = "journal.compacted_snapshot";
|
|
13
|
+
export function replayFrames(bytes, partition) {
|
|
14
|
+
const records = [];
|
|
15
|
+
let offset = 0;
|
|
16
|
+
let epoch = null;
|
|
17
|
+
let expectedSeq = 1;
|
|
18
|
+
let previous = ZERO_HASH;
|
|
19
|
+
while (offset < bytes.length) {
|
|
20
|
+
const remaining = bytes.length - offset;
|
|
21
|
+
if (remaining < PREFIX_BYTES)
|
|
22
|
+
return { records, incompleteOffset: offset, error: null };
|
|
23
|
+
if (!bytes.subarray(offset, offset + MAGIC.length).equals(MAGIC)) {
|
|
24
|
+
return corrupt(records, offset, "frame magic mismatch");
|
|
25
|
+
}
|
|
26
|
+
const prefix = bytes.subarray(offset, offset + PREFIX_BYTES);
|
|
27
|
+
const expectedPrefix = createHash("sha256")
|
|
28
|
+
.update(prefix.subarray(0, PREFIX_CORE_BYTES))
|
|
29
|
+
.digest()
|
|
30
|
+
.subarray(0, PREFIX_CHECKSUM_BYTES);
|
|
31
|
+
if (!prefix.subarray(PREFIX_CORE_BYTES).equals(expectedPrefix)) {
|
|
32
|
+
return corrupt(records, offset, "frame prefix checksum mismatch");
|
|
33
|
+
}
|
|
34
|
+
const version = bytes.readUInt16BE(offset + MAGIC.length);
|
|
35
|
+
const headerLength = bytes.readUInt32BE(offset + MAGIC.length + 2);
|
|
36
|
+
const payloadLength = bytes.readUInt32BE(offset + MAGIC.length + 6);
|
|
37
|
+
if (version !== VERSION)
|
|
38
|
+
return corrupt(records, offset, `unsupported frame version ${version}`);
|
|
39
|
+
if (headerLength === 0 ||
|
|
40
|
+
headerLength > MAX_HEADER_BYTES ||
|
|
41
|
+
payloadLength > MAX_PAYLOAD_BYTES) {
|
|
42
|
+
return corrupt(records, offset, "invalid frame lengths");
|
|
43
|
+
}
|
|
44
|
+
const frameLength = PREFIX_BYTES + headerLength + payloadLength + HASH_BYTES;
|
|
45
|
+
if (frameLength > remaining)
|
|
46
|
+
return { records, incompleteOffset: offset, error: null };
|
|
47
|
+
const headerStart = offset + PREFIX_BYTES;
|
|
48
|
+
const payloadStart = headerStart + headerLength;
|
|
49
|
+
const bodyEnd = payloadStart + payloadLength;
|
|
50
|
+
const body = bytes.subarray(offset, bodyEnd);
|
|
51
|
+
const frameHashBytes = createHash("sha256").update(body).digest();
|
|
52
|
+
if (!bytes.subarray(bodyEnd, bodyEnd + HASH_BYTES).equals(frameHashBytes)) {
|
|
53
|
+
return corrupt(records, offset, "frame checksum mismatch");
|
|
54
|
+
}
|
|
55
|
+
let header;
|
|
56
|
+
let payload;
|
|
57
|
+
try {
|
|
58
|
+
header = JSON.parse(bytes.subarray(headerStart, payloadStart).toString("utf8"));
|
|
59
|
+
payload = JSON.parse(bytes.subarray(payloadStart, bodyEnd).toString("utf8"));
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return corrupt(records, offset, "frame JSON is malformed");
|
|
63
|
+
}
|
|
64
|
+
const semantic = validateHeader(header, partition, epoch, expectedSeq, previous);
|
|
65
|
+
if (semantic)
|
|
66
|
+
return corrupt(records, offset, semantic);
|
|
67
|
+
const frameHash = frameHashBytes.toString("hex");
|
|
68
|
+
if (header.type === COMPACTED_SNAPSHOT) {
|
|
69
|
+
let compacted;
|
|
70
|
+
try {
|
|
71
|
+
compacted = decodeCompactedSnapshot(payload, header.logicalSpan);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
return corrupt(records, offset, `compacted snapshot is invalid: ${String(error)}`);
|
|
75
|
+
}
|
|
76
|
+
compacted.forEach((record, index) => records.push({
|
|
77
|
+
partition,
|
|
78
|
+
epoch: header.epoch,
|
|
79
|
+
seq: header.seq + index,
|
|
80
|
+
previousFrameHash: index === 0 ? header.previousFrameHash : frameHash,
|
|
81
|
+
frameHash,
|
|
82
|
+
time: record.time,
|
|
83
|
+
type: record.type,
|
|
84
|
+
payload: record.payload,
|
|
85
|
+
byteOffset: offset,
|
|
86
|
+
}));
|
|
87
|
+
expectedSeq += compacted.length;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
records.push({
|
|
91
|
+
partition,
|
|
92
|
+
epoch: header.epoch,
|
|
93
|
+
seq: header.seq,
|
|
94
|
+
previousFrameHash: header.previousFrameHash,
|
|
95
|
+
frameHash,
|
|
96
|
+
time: header.time,
|
|
97
|
+
type: header.type,
|
|
98
|
+
payload,
|
|
99
|
+
byteOffset: offset,
|
|
100
|
+
});
|
|
101
|
+
expectedSeq += 1;
|
|
102
|
+
}
|
|
103
|
+
epoch ??= header.epoch;
|
|
104
|
+
previous = frameHash;
|
|
105
|
+
offset += frameLength;
|
|
106
|
+
}
|
|
107
|
+
return { records, incompleteOffset: null, error: null };
|
|
108
|
+
}
|
|
109
|
+
export function encodeFrame(header, payload) {
|
|
110
|
+
const headerBytes = encodeJson(header);
|
|
111
|
+
if (headerBytes.length > MAX_HEADER_BYTES)
|
|
112
|
+
throw new Error("journal header is too large");
|
|
113
|
+
const prefix = Buffer.alloc(PREFIX_BYTES);
|
|
114
|
+
MAGIC.copy(prefix);
|
|
115
|
+
prefix.writeUInt16BE(VERSION, MAGIC.length);
|
|
116
|
+
prefix.writeUInt32BE(headerBytes.length, MAGIC.length + 2);
|
|
117
|
+
prefix.writeUInt32BE(payload.length, MAGIC.length + 6);
|
|
118
|
+
createHash("sha256")
|
|
119
|
+
.update(prefix.subarray(0, PREFIX_CORE_BYTES))
|
|
120
|
+
.digest()
|
|
121
|
+
.subarray(0, PREFIX_CHECKSUM_BYTES)
|
|
122
|
+
.copy(prefix, PREFIX_CORE_BYTES);
|
|
123
|
+
const body = Buffer.concat([prefix, headerBytes, payload]);
|
|
124
|
+
return Buffer.concat([body, createHash("sha256").update(body).digest()]);
|
|
125
|
+
}
|
|
126
|
+
function corrupt(records, offset, reason) {
|
|
127
|
+
return { records, incompleteOffset: null, error: { offset, reason } };
|
|
128
|
+
}
|
|
129
|
+
function validateHeader(header, partition, epoch, seq, previous) {
|
|
130
|
+
if (!header || typeof header !== "object")
|
|
131
|
+
return "frame header is not an object";
|
|
132
|
+
if (header.partition !== partition)
|
|
133
|
+
return "frame partition mismatch";
|
|
134
|
+
if (typeof header.epoch !== "string" || !header.epoch)
|
|
135
|
+
return "frame epoch is invalid";
|
|
136
|
+
if (epoch !== null && header.epoch !== epoch)
|
|
137
|
+
return "frame epoch changed";
|
|
138
|
+
if (header.seq !== seq)
|
|
139
|
+
return "frame sequence mismatch";
|
|
140
|
+
if (header.previousFrameHash !== previous)
|
|
141
|
+
return "frame hash-chain mismatch";
|
|
142
|
+
if (typeof header.time !== "string" || !header.time)
|
|
143
|
+
return "frame timestamp is invalid";
|
|
144
|
+
if (typeof header.type !== "string" || !header.type)
|
|
145
|
+
return "frame type is invalid";
|
|
146
|
+
if (header.type === COMPACTED_SNAPSHOT) {
|
|
147
|
+
if (!Number.isSafeInteger(header.logicalSpan) || Number(header.logicalSpan) <= 0) {
|
|
148
|
+
return "compacted snapshot logical span is invalid";
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
else if (header.logicalSpan !== undefined)
|
|
152
|
+
return "ordinary frame declares a logical span";
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
function decodeCompactedSnapshot(payload, logicalSpan) {
|
|
156
|
+
if (!isRecord(payload) || payload.version !== 1 || payload.encoding !== "gzip-base64") {
|
|
157
|
+
throw new Error("unsupported payload");
|
|
158
|
+
}
|
|
159
|
+
if (!Number.isSafeInteger(payload.count) || payload.count !== logicalSpan) {
|
|
160
|
+
throw new Error("record count mismatch");
|
|
161
|
+
}
|
|
162
|
+
if (typeof payload.data !== "string")
|
|
163
|
+
throw new Error("encoded data is missing");
|
|
164
|
+
const decoded = JSON.parse(gunzipSync(Buffer.from(payload.data, "base64")).toString("utf8"));
|
|
165
|
+
if (!Array.isArray(decoded) || decoded.length !== payload.count)
|
|
166
|
+
throw new Error("invalid records");
|
|
167
|
+
return decoded.map((record) => {
|
|
168
|
+
if (!isRecord(record) ||
|
|
169
|
+
typeof record.time !== "string" ||
|
|
170
|
+
typeof record.type !== "string" ||
|
|
171
|
+
!record.type ||
|
|
172
|
+
record.type === COMPACTED_SNAPSHOT) {
|
|
173
|
+
throw new Error("invalid logical record");
|
|
174
|
+
}
|
|
175
|
+
return { time: record.time, type: record.type, payload: record.payload };
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
function encodeJson(value) {
|
|
179
|
+
const encoded = JSON.stringify(value);
|
|
180
|
+
if (encoded === undefined)
|
|
181
|
+
throw new Error("journal value is not JSON serializable");
|
|
182
|
+
return Buffer.from(encoded);
|
|
183
|
+
}
|
|
184
|
+
function isRecord(value) {
|
|
185
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=frame-codec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frame-codec.js","sourceRoot":"","sources":["../src/frame-codec.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { type JournalRecord } from "./frame-codec.js";
|
|
2
|
+
export type { JournalRecord } from "./frame-codec.js";
|
|
3
|
+
export type JournalRecoveryLocation = {
|
|
4
|
+
kind: "byte";
|
|
5
|
+
byteOffset: number;
|
|
6
|
+
} | {
|
|
7
|
+
kind: "cursor";
|
|
8
|
+
epoch: string;
|
|
9
|
+
seq: number;
|
|
10
|
+
};
|
|
11
|
+
export type JournalRecoveryState = {
|
|
12
|
+
status: "ready";
|
|
13
|
+
discardedTailBytes: number;
|
|
14
|
+
} | {
|
|
15
|
+
status: "recovery_required";
|
|
16
|
+
location: JournalRecoveryLocation;
|
|
17
|
+
reason: string;
|
|
18
|
+
discardedTailBytes: number;
|
|
19
|
+
};
|
|
20
|
+
export interface DurableJournalOptions {
|
|
21
|
+
rootDir: string;
|
|
22
|
+
partition: string;
|
|
23
|
+
now?: () => Date;
|
|
24
|
+
epochFactory?: () => string;
|
|
25
|
+
appendAndSync?: (fd: number, bytes: Buffer) => void;
|
|
26
|
+
compactionThresholdBytes?: number;
|
|
27
|
+
}
|
|
28
|
+
export declare function journalPartitionDirectory(rootDir: string, partition: string): string;
|
|
29
|
+
export declare class JournalRecoveryRequiredError extends Error {
|
|
30
|
+
readonly code: string;
|
|
31
|
+
readonly status = 503;
|
|
32
|
+
readonly retryable = false;
|
|
33
|
+
readonly requiredActions: string[];
|
|
34
|
+
readonly evidenceRefs: string[];
|
|
35
|
+
readonly recovery: Extract<JournalRecoveryState, {
|
|
36
|
+
status: "recovery_required";
|
|
37
|
+
}>;
|
|
38
|
+
constructor(recovery: Extract<JournalRecoveryState, {
|
|
39
|
+
status: "recovery_required";
|
|
40
|
+
}>);
|
|
41
|
+
}
|
|
42
|
+
export declare class JournalAppendUncertainError extends JournalRecoveryRequiredError {
|
|
43
|
+
readonly code = "journal_append_uncertain";
|
|
44
|
+
constructor(recovery: Extract<JournalRecoveryState, {
|
|
45
|
+
status: "recovery_required";
|
|
46
|
+
}>, options?: ErrorOptions);
|
|
47
|
+
}
|
|
48
|
+
export declare class JournalCursorError extends Error {
|
|
49
|
+
readonly code = "journal_cursor_invalid";
|
|
50
|
+
readonly status = 409;
|
|
51
|
+
readonly retryable = true;
|
|
52
|
+
readonly requiredActions: string[];
|
|
53
|
+
}
|
|
54
|
+
/** Single-writer, checksummed journal. A returned append has reached fsync. */
|
|
55
|
+
export declare class DurableJournal {
|
|
56
|
+
readonly options: Readonly<DurableJournalOptions>;
|
|
57
|
+
readonly partitionDir: string;
|
|
58
|
+
readonly path: string;
|
|
59
|
+
private readonly now;
|
|
60
|
+
private readonly appendFrame;
|
|
61
|
+
private fd;
|
|
62
|
+
private readonly entries;
|
|
63
|
+
private epoch;
|
|
64
|
+
private nextSeq;
|
|
65
|
+
private previousFrameHash;
|
|
66
|
+
private knownFileBytes;
|
|
67
|
+
private recovery;
|
|
68
|
+
private closed;
|
|
69
|
+
constructor(options: DurableJournalOptions);
|
|
70
|
+
state(): JournalRecoveryState;
|
|
71
|
+
records<T = unknown>(afterSeq?: number): JournalRecord<T>[];
|
|
72
|
+
close(): void;
|
|
73
|
+
currentCursor(): string;
|
|
74
|
+
cursorAt(seq: number): string;
|
|
75
|
+
currentSequence(): number;
|
|
76
|
+
currentEpoch(): string;
|
|
77
|
+
physicalBytes(): number;
|
|
78
|
+
/** Atomically replace physical frames with one checksummed compressed frame. */
|
|
79
|
+
compact(): {
|
|
80
|
+
beforeBytes: number;
|
|
81
|
+
afterBytes: number;
|
|
82
|
+
records: number;
|
|
83
|
+
} | null;
|
|
84
|
+
sequenceAfter(cursor: string | null | undefined): number;
|
|
85
|
+
cursorFor(record: Pick<JournalRecord, "partition" | "epoch" | "seq">): string;
|
|
86
|
+
append<T>(type: string, payload: T): JournalRecord<T>;
|
|
87
|
+
private recover;
|
|
88
|
+
private intentPath;
|
|
89
|
+
private requireRecovery;
|
|
90
|
+
private assertReadable;
|
|
91
|
+
private assertOpen;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { gzipSync } from "node:zlib";
|
|
3
|
+
import { closeSync, constants, existsSync, fchmodSync, fstatSync, ftruncateSync, fsyncSync, lstatSync, openSync, readFileSync, renameSync, rmSync, writeSync, } from "node:fs";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { ensureCanonicalPrivateDirectory } from "@claudexor/util";
|
|
6
|
+
import { COMPACTED_SNAPSHOT, HASH_BYTES, MAX_PAYLOAD_BYTES, ZERO_HASH, encodeFrame, replayFrames, } from "./frame-codec.js";
|
|
7
|
+
export function journalPartitionDirectory(rootDir, partition) {
|
|
8
|
+
if (!partition.trim())
|
|
9
|
+
throw new Error("journal partition must not be empty");
|
|
10
|
+
const slug = partition.replace(/[^A-Za-z0-9._-]+/g, "-").slice(0, 48) || "partition";
|
|
11
|
+
return join(rootDir, `${slug}-${sha256(Buffer.from(partition)).slice(0, 12)}`);
|
|
12
|
+
}
|
|
13
|
+
export class JournalRecoveryRequiredError extends Error {
|
|
14
|
+
code = "journal_recovery_required";
|
|
15
|
+
status = 503;
|
|
16
|
+
retryable = false;
|
|
17
|
+
requiredActions = ["inspect_recovery", "export_recovery", "quarantine_partition"];
|
|
18
|
+
evidenceRefs = [];
|
|
19
|
+
recovery;
|
|
20
|
+
constructor(recovery) {
|
|
21
|
+
const safe = Object.freeze({ ...recovery, location: Object.freeze({ ...recovery.location }) });
|
|
22
|
+
const where = safe.location.kind === "byte"
|
|
23
|
+
? `byte ${safe.location.byteOffset}`
|
|
24
|
+
: `cursor ${safe.location.epoch}:${safe.location.seq}`;
|
|
25
|
+
super(`journal partition requires recovery at ${where}: ${safe.reason}`);
|
|
26
|
+
this.name = "JournalRecoveryRequiredError";
|
|
27
|
+
this.recovery = safe;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export class JournalAppendUncertainError extends JournalRecoveryRequiredError {
|
|
31
|
+
code = "journal_append_uncertain";
|
|
32
|
+
constructor(recovery, options) {
|
|
33
|
+
super(recovery);
|
|
34
|
+
this.name = "JournalAppendUncertainError";
|
|
35
|
+
if (options?.cause !== undefined)
|
|
36
|
+
Object.defineProperty(this, "cause", { value: options.cause });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export class JournalCursorError extends Error {
|
|
40
|
+
code = "journal_cursor_invalid";
|
|
41
|
+
status = 409;
|
|
42
|
+
retryable = true;
|
|
43
|
+
requiredActions = ["resnapshot"];
|
|
44
|
+
}
|
|
45
|
+
/** Single-writer, checksummed journal. A returned append has reached fsync. */
|
|
46
|
+
export class DurableJournal {
|
|
47
|
+
options;
|
|
48
|
+
partitionDir;
|
|
49
|
+
path;
|
|
50
|
+
now;
|
|
51
|
+
appendFrame;
|
|
52
|
+
fd;
|
|
53
|
+
entries = [];
|
|
54
|
+
epoch;
|
|
55
|
+
nextSeq = 1;
|
|
56
|
+
previousFrameHash = ZERO_HASH;
|
|
57
|
+
knownFileBytes = 0;
|
|
58
|
+
recovery = { status: "ready", discardedTailBytes: 0 };
|
|
59
|
+
closed = false;
|
|
60
|
+
constructor(options) {
|
|
61
|
+
if (!options.partition.trim())
|
|
62
|
+
throw new Error("journal partition must not be empty");
|
|
63
|
+
this.options = Object.freeze({ ...options });
|
|
64
|
+
this.now = options.now ?? (() => new Date());
|
|
65
|
+
this.appendFrame = options.appendAndSync ?? appendAndSync;
|
|
66
|
+
ensureCanonicalPrivateDirectory(options.rootDir);
|
|
67
|
+
this.partitionDir = journalPartitionDirectory(options.rootDir, options.partition);
|
|
68
|
+
ensureCanonicalPrivateDirectory(this.partitionDir);
|
|
69
|
+
this.path = join(this.partitionDir, "journal.bin");
|
|
70
|
+
ensurePrivateFile(this.path);
|
|
71
|
+
this.fd = openSync(this.path, constants.O_RDWR | constants.O_APPEND | constants.O_NOFOLLOW);
|
|
72
|
+
const stat = fstatSync(this.fd);
|
|
73
|
+
if (!stat.isFile() || stat.nlink !== 1)
|
|
74
|
+
throw new Error("journal file is not privately owned");
|
|
75
|
+
if ((stat.mode & 0o777) !== 0o600) {
|
|
76
|
+
fchmodSync(this.fd, 0o600);
|
|
77
|
+
fsyncSync(this.fd);
|
|
78
|
+
}
|
|
79
|
+
this.epoch = (options.epochFactory ?? randomUUID)();
|
|
80
|
+
this.recover();
|
|
81
|
+
if (this.recovery.status === "ready" &&
|
|
82
|
+
this.knownFileBytes >= (options.compactionThresholdBytes ?? 8 * 1024 * 1024)) {
|
|
83
|
+
this.compact();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
state() {
|
|
87
|
+
this.assertOpen();
|
|
88
|
+
return structuredClone(this.recovery);
|
|
89
|
+
}
|
|
90
|
+
records(afterSeq = 0) {
|
|
91
|
+
this.assertReadable();
|
|
92
|
+
return this.entries
|
|
93
|
+
.filter((record) => record.seq > afterSeq)
|
|
94
|
+
.map((record) => ({ ...record, payload: cloneJson(record.payload) }));
|
|
95
|
+
}
|
|
96
|
+
close() {
|
|
97
|
+
if (this.closed)
|
|
98
|
+
return;
|
|
99
|
+
this.closed = true;
|
|
100
|
+
closeSync(this.fd);
|
|
101
|
+
}
|
|
102
|
+
currentCursor() {
|
|
103
|
+
this.assertReadable();
|
|
104
|
+
return encodeCursor(this.options.partition, this.epoch, this.nextSeq - 1);
|
|
105
|
+
}
|
|
106
|
+
cursorAt(seq) {
|
|
107
|
+
this.assertReadable();
|
|
108
|
+
if (!Number.isSafeInteger(seq) || seq < 0 || seq >= this.nextSeq) {
|
|
109
|
+
throw new JournalCursorError("journal cursor sequence is outside the current epoch");
|
|
110
|
+
}
|
|
111
|
+
return encodeCursor(this.options.partition, this.epoch, seq);
|
|
112
|
+
}
|
|
113
|
+
currentSequence() {
|
|
114
|
+
this.assertReadable();
|
|
115
|
+
return this.nextSeq - 1;
|
|
116
|
+
}
|
|
117
|
+
currentEpoch() {
|
|
118
|
+
this.assertReadable();
|
|
119
|
+
return this.epoch;
|
|
120
|
+
}
|
|
121
|
+
physicalBytes() {
|
|
122
|
+
this.assertOpen();
|
|
123
|
+
return this.knownFileBytes;
|
|
124
|
+
}
|
|
125
|
+
/** Atomically replace physical frames with one checksummed compressed frame. */
|
|
126
|
+
compact() {
|
|
127
|
+
this.assertReadable();
|
|
128
|
+
if (this.entries.length === 0)
|
|
129
|
+
return null;
|
|
130
|
+
const logical = this.entries.map((record) => ({
|
|
131
|
+
time: record.time,
|
|
132
|
+
type: record.type,
|
|
133
|
+
payload: cloneJson(record.payload),
|
|
134
|
+
}));
|
|
135
|
+
const compressed = gzipSync(Buffer.from(JSON.stringify(logical)));
|
|
136
|
+
const payload = {
|
|
137
|
+
version: 1,
|
|
138
|
+
count: logical.length,
|
|
139
|
+
encoding: "gzip-base64",
|
|
140
|
+
data: compressed.toString("base64"),
|
|
141
|
+
};
|
|
142
|
+
const payloadBytes = encodeJson(payload);
|
|
143
|
+
// Oversized history stays readable in its existing frames; compaction is
|
|
144
|
+
// an optimization, not a corruption or recovery boundary.
|
|
145
|
+
if (payloadBytes.length > MAX_PAYLOAD_BYTES)
|
|
146
|
+
return null;
|
|
147
|
+
const epoch = randomUUID();
|
|
148
|
+
const header = {
|
|
149
|
+
partition: this.options.partition,
|
|
150
|
+
epoch,
|
|
151
|
+
seq: 1,
|
|
152
|
+
previousFrameHash: ZERO_HASH,
|
|
153
|
+
time: this.now().toISOString(),
|
|
154
|
+
type: COMPACTED_SNAPSHOT,
|
|
155
|
+
logicalSpan: logical.length,
|
|
156
|
+
};
|
|
157
|
+
const frame = encodeFrame(header, payloadBytes);
|
|
158
|
+
if (frame.length >= this.knownFileBytes)
|
|
159
|
+
return null;
|
|
160
|
+
const temp = `${this.path}.${randomUUID()}.compact`;
|
|
161
|
+
const tempFd = openSync(temp, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL, 0o600);
|
|
162
|
+
try {
|
|
163
|
+
appendAndSync(tempFd, frame);
|
|
164
|
+
}
|
|
165
|
+
finally {
|
|
166
|
+
closeSync(tempFd);
|
|
167
|
+
}
|
|
168
|
+
const beforeBytes = this.knownFileBytes;
|
|
169
|
+
renameSync(temp, this.path);
|
|
170
|
+
fsyncDirectory(dirname(this.path));
|
|
171
|
+
closeSync(this.fd);
|
|
172
|
+
this.fd = openSync(this.path, constants.O_RDWR | constants.O_APPEND | constants.O_NOFOLLOW);
|
|
173
|
+
const frameHash = frame.subarray(frame.length - HASH_BYTES).toString("hex");
|
|
174
|
+
this.entries.splice(0, this.entries.length, ...logical.map((record, index) => ({
|
|
175
|
+
partition: this.options.partition,
|
|
176
|
+
epoch,
|
|
177
|
+
seq: index + 1,
|
|
178
|
+
previousFrameHash: index === 0 ? ZERO_HASH : frameHash,
|
|
179
|
+
frameHash,
|
|
180
|
+
time: record.time,
|
|
181
|
+
type: record.type,
|
|
182
|
+
payload: cloneJson(record.payload),
|
|
183
|
+
byteOffset: 0,
|
|
184
|
+
})));
|
|
185
|
+
this.epoch = epoch;
|
|
186
|
+
this.nextSeq = logical.length + 1;
|
|
187
|
+
this.previousFrameHash = frameHash;
|
|
188
|
+
this.knownFileBytes = frame.length;
|
|
189
|
+
return { beforeBytes, afterBytes: frame.length, records: logical.length };
|
|
190
|
+
}
|
|
191
|
+
sequenceAfter(cursor) {
|
|
192
|
+
this.assertReadable();
|
|
193
|
+
if (!cursor)
|
|
194
|
+
return 0;
|
|
195
|
+
if (!/^[A-Za-z0-9_-]{1,4096}$/.test(cursor))
|
|
196
|
+
throw cursorError("malformed");
|
|
197
|
+
let value;
|
|
198
|
+
try {
|
|
199
|
+
value = JSON.parse(Buffer.from(cursor, "base64url").toString("utf8"));
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
throw cursorError("malformed");
|
|
203
|
+
}
|
|
204
|
+
if (!isRecord(value) || Object.keys(value).sort().join(",") !== "e,p,s,v" || value.v !== 1) {
|
|
205
|
+
throw cursorError("unsupported");
|
|
206
|
+
}
|
|
207
|
+
if (value.p !== this.options.partition || value.e !== this.epoch)
|
|
208
|
+
throw cursorError("stale epoch");
|
|
209
|
+
if (!Number.isSafeInteger(value.s) || Number(value.s) < 0 || Number(value.s) >= this.nextSeq) {
|
|
210
|
+
throw cursorError("ahead of the durable partition");
|
|
211
|
+
}
|
|
212
|
+
if (encodeCursor(value.p, value.e, value.s) !== cursor) {
|
|
213
|
+
throw cursorError("not canonically encoded");
|
|
214
|
+
}
|
|
215
|
+
return value.s;
|
|
216
|
+
}
|
|
217
|
+
cursorFor(record) {
|
|
218
|
+
this.assertReadable();
|
|
219
|
+
if (record.partition !== this.options.partition || record.epoch !== this.epoch) {
|
|
220
|
+
throw new JournalCursorError("cannot encode a cursor for another partition or epoch");
|
|
221
|
+
}
|
|
222
|
+
return encodeCursor(record.partition, record.epoch, record.seq);
|
|
223
|
+
}
|
|
224
|
+
append(type, payload) {
|
|
225
|
+
this.assertReadable();
|
|
226
|
+
if (!type.trim())
|
|
227
|
+
throw new Error("journal record type must not be empty");
|
|
228
|
+
const actualBytes = Number(fstatSync(this.fd, { bigint: true }).size);
|
|
229
|
+
if (actualBytes !== this.knownFileBytes) {
|
|
230
|
+
throw new JournalRecoveryRequiredError(this.requireRecovery(this.knownFileBytes, "journal changed outside its single writer"));
|
|
231
|
+
}
|
|
232
|
+
const payloadBytes = encodeJson(payload);
|
|
233
|
+
if (payloadBytes.length > MAX_PAYLOAD_BYTES)
|
|
234
|
+
throw new Error("journal payload is too large");
|
|
235
|
+
const header = {
|
|
236
|
+
partition: this.options.partition,
|
|
237
|
+
epoch: this.epoch,
|
|
238
|
+
seq: this.nextSeq,
|
|
239
|
+
previousFrameHash: this.previousFrameHash,
|
|
240
|
+
time: this.now().toISOString(),
|
|
241
|
+
type,
|
|
242
|
+
};
|
|
243
|
+
const frame = encodeFrame(header, payloadBytes);
|
|
244
|
+
const byteOffset = this.knownFileBytes;
|
|
245
|
+
writeIntent(this.intentPath(), { v: 1, offset: byteOffset, length: frame.length });
|
|
246
|
+
try {
|
|
247
|
+
this.appendFrame(this.fd, frame);
|
|
248
|
+
if (Number(fstatSync(this.fd, { bigint: true }).size) !== byteOffset + frame.length) {
|
|
249
|
+
throw new Error("journal append did not write exactly one frame");
|
|
250
|
+
}
|
|
251
|
+
removeFile(this.intentPath());
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
const recovery = this.requireRecovery(byteOffset, "append/fsync completion is uncertain; restart and inspect before further mutations");
|
|
255
|
+
throw new JournalAppendUncertainError(recovery, { cause: error });
|
|
256
|
+
}
|
|
257
|
+
const frameHash = frame.subarray(frame.length - HASH_BYTES).toString("hex");
|
|
258
|
+
const record = {
|
|
259
|
+
partition: header.partition,
|
|
260
|
+
epoch: header.epoch,
|
|
261
|
+
seq: header.seq,
|
|
262
|
+
previousFrameHash: header.previousFrameHash,
|
|
263
|
+
frameHash,
|
|
264
|
+
time: header.time,
|
|
265
|
+
type: header.type,
|
|
266
|
+
payload: JSON.parse(payloadBytes.toString("utf8")),
|
|
267
|
+
byteOffset,
|
|
268
|
+
};
|
|
269
|
+
this.entries.push(record);
|
|
270
|
+
this.nextSeq += 1;
|
|
271
|
+
this.previousFrameHash = frameHash;
|
|
272
|
+
this.knownFileBytes += frame.length;
|
|
273
|
+
return { ...record, payload: cloneJson(record.payload) };
|
|
274
|
+
}
|
|
275
|
+
recover() {
|
|
276
|
+
let bytes = readDescriptor(this.fd);
|
|
277
|
+
let discardedBytes = 0;
|
|
278
|
+
try {
|
|
279
|
+
const intent = readIntent(this.intentPath());
|
|
280
|
+
if (intent) {
|
|
281
|
+
const prefix = replayFrames(bytes.subarray(0, intent.offset), this.options.partition);
|
|
282
|
+
if (intent.offset > bytes.length ||
|
|
283
|
+
bytes.length > intent.offset + intent.length ||
|
|
284
|
+
prefix.error ||
|
|
285
|
+
prefix.incompleteOffset !== null) {
|
|
286
|
+
this.requireRecovery(intent.offset, "append intent does not match the journal prefix");
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
discardedBytes = bytes.length - intent.offset;
|
|
290
|
+
if (discardedBytes > 0) {
|
|
291
|
+
ftruncateSync(this.fd, intent.offset);
|
|
292
|
+
fsyncSync(this.fd);
|
|
293
|
+
bytes = bytes.subarray(0, intent.offset);
|
|
294
|
+
}
|
|
295
|
+
removeFile(this.intentPath());
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
catch (error) {
|
|
299
|
+
this.requireRecovery(0, `append intent is malformed: ${String(error)}`);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
const decoded = replayFrames(bytes, this.options.partition);
|
|
303
|
+
if (decoded.incompleteOffset !== null) {
|
|
304
|
+
this.requireRecovery(decoded.incompleteOffset, "unexplained suffix without append intent");
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
if (decoded.error) {
|
|
308
|
+
this.requireRecovery(decoded.error.offset, decoded.error.reason);
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
this.entries.push(...decoded.records);
|
|
312
|
+
const last = this.entries.at(-1);
|
|
313
|
+
if (last) {
|
|
314
|
+
this.epoch = last.epoch;
|
|
315
|
+
this.nextSeq = last.seq + 1;
|
|
316
|
+
this.previousFrameHash = last.frameHash;
|
|
317
|
+
}
|
|
318
|
+
this.knownFileBytes = bytes.length;
|
|
319
|
+
if (discardedBytes > 0) {
|
|
320
|
+
this.recovery = { status: "ready", discardedTailBytes: discardedBytes };
|
|
321
|
+
this.append("journal.recovery_tail_discarded", {
|
|
322
|
+
recoveryId: randomUUID(),
|
|
323
|
+
discardedBytes,
|
|
324
|
+
validBytes: bytes.length,
|
|
325
|
+
originalBytes: bytes.length + discardedBytes,
|
|
326
|
+
detectedAt: this.now().toISOString(),
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
intentPath() {
|
|
331
|
+
return join(this.partitionDir, "append.pending.json");
|
|
332
|
+
}
|
|
333
|
+
requireRecovery(byteOffset, reason) {
|
|
334
|
+
const value = {
|
|
335
|
+
status: "recovery_required",
|
|
336
|
+
location: { kind: "byte", byteOffset },
|
|
337
|
+
reason,
|
|
338
|
+
discardedTailBytes: 0,
|
|
339
|
+
};
|
|
340
|
+
this.recovery = value;
|
|
341
|
+
return value;
|
|
342
|
+
}
|
|
343
|
+
assertReadable() {
|
|
344
|
+
this.assertOpen();
|
|
345
|
+
if (this.recovery.status === "recovery_required") {
|
|
346
|
+
throw new JournalRecoveryRequiredError(this.recovery);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
assertOpen() {
|
|
350
|
+
if (this.closed)
|
|
351
|
+
throw new Error("journal writer is closed");
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
function appendAndSync(fd, bytes) {
|
|
355
|
+
let offset = 0;
|
|
356
|
+
while (offset < bytes.length)
|
|
357
|
+
offset += writeSync(fd, bytes, offset, bytes.length - offset);
|
|
358
|
+
fsyncSync(fd);
|
|
359
|
+
}
|
|
360
|
+
function ensurePrivateFile(path) {
|
|
361
|
+
if (!existsSync(path)) {
|
|
362
|
+
const fd = openSync(path, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL, 0o600);
|
|
363
|
+
try {
|
|
364
|
+
fsyncSync(fd);
|
|
365
|
+
}
|
|
366
|
+
finally {
|
|
367
|
+
closeSync(fd);
|
|
368
|
+
}
|
|
369
|
+
fsyncDirectory(dirname(path));
|
|
370
|
+
}
|
|
371
|
+
const stat = lstatSync(path);
|
|
372
|
+
if (stat.isSymbolicLink() || !stat.isFile() || stat.nlink !== 1) {
|
|
373
|
+
throw new Error("journal path is not a private regular file");
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
function readDescriptor(fd) {
|
|
377
|
+
const size = Number(fstatSync(fd, { bigint: true }).size);
|
|
378
|
+
if (!Number.isSafeInteger(size) || size < 0)
|
|
379
|
+
throw new Error("journal file size is invalid");
|
|
380
|
+
const bytes = readFileSync(fd);
|
|
381
|
+
if (bytes.length !== size)
|
|
382
|
+
throw new Error("journal changed while being read");
|
|
383
|
+
return bytes;
|
|
384
|
+
}
|
|
385
|
+
function readIntent(path) {
|
|
386
|
+
if (!existsSync(path))
|
|
387
|
+
return null;
|
|
388
|
+
const fd = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
389
|
+
try {
|
|
390
|
+
const stat = fstatSync(fd);
|
|
391
|
+
if (!stat.isFile() || stat.nlink !== 1 || stat.size > 1024)
|
|
392
|
+
throw new Error("unsafe file");
|
|
393
|
+
const value = JSON.parse(readFileSync(fd, "utf8"));
|
|
394
|
+
if (!isRecord(value) ||
|
|
395
|
+
value.v !== 1 ||
|
|
396
|
+
!Number.isSafeInteger(value.offset) ||
|
|
397
|
+
Number(value.offset) < 0 ||
|
|
398
|
+
!Number.isSafeInteger(value.length) ||
|
|
399
|
+
Number(value.length) <= 0)
|
|
400
|
+
throw new Error("invalid shape");
|
|
401
|
+
return value;
|
|
402
|
+
}
|
|
403
|
+
finally {
|
|
404
|
+
closeSync(fd);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
function writeIntent(path, value) {
|
|
408
|
+
const temp = `${path}.${randomUUID()}.tmp`;
|
|
409
|
+
const bytes = Buffer.from(`${JSON.stringify(value)}\n`);
|
|
410
|
+
const fd = openSync(temp, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL, 0o600);
|
|
411
|
+
try {
|
|
412
|
+
let offset = 0;
|
|
413
|
+
while (offset < bytes.length)
|
|
414
|
+
offset += writeSync(fd, bytes, offset, bytes.length - offset);
|
|
415
|
+
fsyncSync(fd);
|
|
416
|
+
}
|
|
417
|
+
finally {
|
|
418
|
+
closeSync(fd);
|
|
419
|
+
}
|
|
420
|
+
renameSync(temp, path);
|
|
421
|
+
fsyncDirectory(dirname(path));
|
|
422
|
+
}
|
|
423
|
+
function removeFile(path) {
|
|
424
|
+
if (!existsSync(path))
|
|
425
|
+
return;
|
|
426
|
+
rmSync(path);
|
|
427
|
+
fsyncDirectory(dirname(path));
|
|
428
|
+
}
|
|
429
|
+
function fsyncDirectory(path) {
|
|
430
|
+
const fd = openSync(path, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
|
|
431
|
+
try {
|
|
432
|
+
fsyncSync(fd);
|
|
433
|
+
}
|
|
434
|
+
finally {
|
|
435
|
+
closeSync(fd);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
function encodeCursor(partition, epoch, seq) {
|
|
439
|
+
return Buffer.from(JSON.stringify({ v: 1, p: partition, e: epoch, s: seq })).toString("base64url");
|
|
440
|
+
}
|
|
441
|
+
function cursorError(detail) {
|
|
442
|
+
return new JournalCursorError(`journal cursor is ${detail}; resnapshot is required`);
|
|
443
|
+
}
|
|
444
|
+
function encodeJson(value) {
|
|
445
|
+
const encoded = JSON.stringify(value);
|
|
446
|
+
if (encoded === undefined)
|
|
447
|
+
throw new Error("journal value is not JSON serializable");
|
|
448
|
+
return Buffer.from(encoded);
|
|
449
|
+
}
|
|
450
|
+
function sha256(bytes) {
|
|
451
|
+
return createHash("sha256").update(bytes).digest("hex");
|
|
452
|
+
}
|
|
453
|
+
function cloneJson(value) {
|
|
454
|
+
return JSON.parse(JSON.stringify(value));
|
|
455
|
+
}
|
|
456
|
+
function isRecord(value) {
|
|
457
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
458
|
+
}
|
|
459
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@claudexor/journal",
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"description": "Checksummed append-only durable journal for daemon command and lifecycle state.",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@claudexor/util": "2.1.0"
|
|
20
|
+
},
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/razzant/claudexor.git",
|
|
24
|
+
"directory": "packages/journal"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://github.com/razzant/claudexor#readme",
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/razzant/claudexor/issues"
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=20.19"
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsc",
|
|
38
|
+
"typecheck": "tsc --noEmit"
|
|
39
|
+
}
|
|
40
|
+
}
|