@exaudeus/workrail 1.5.0 → 1.5.1
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/dist/manifest.json +378 -178
- package/dist/mcp/handlers/v2-advance-core/event-builders.d.ts +37 -0
- package/dist/mcp/handlers/v2-advance-core/event-builders.js +114 -0
- package/dist/mcp/handlers/v2-advance-core/index.d.ts +67 -0
- package/dist/mcp/handlers/v2-advance-core/index.js +100 -0
- package/dist/mcp/handlers/v2-advance-core/input-validation.d.ts +44 -0
- package/dist/mcp/handlers/v2-advance-core/input-validation.js +58 -0
- package/dist/mcp/handlers/v2-advance-core/outcome-blocked.d.ts +16 -0
- package/dist/mcp/handlers/v2-advance-core/outcome-blocked.js +64 -0
- package/dist/mcp/handlers/v2-advance-core/outcome-success.d.ts +15 -0
- package/dist/mcp/handlers/v2-advance-core/outcome-success.js +136 -0
- package/dist/mcp/handlers/v2-advance-core.d.ts +3 -45
- package/dist/mcp/handlers/v2-advance-core.js +3 -431
- package/dist/mcp/handlers/v2-advance-events.d.ts +61 -0
- package/dist/mcp/handlers/v2-advance-events.js +126 -0
- package/dist/mcp/handlers/v2-checkpoint.js +5 -4
- package/dist/mcp/handlers/v2-context-budget.js +2 -2
- package/dist/mcp/handlers/v2-execution/advance.d.ts +32 -0
- package/dist/mcp/handlers/v2-execution/advance.js +50 -0
- package/dist/mcp/handlers/v2-execution/continue-advance.d.ts +29 -0
- package/dist/mcp/handlers/v2-execution/continue-advance.js +170 -0
- package/dist/mcp/handlers/v2-execution/continue-rehydrate.d.ts +22 -0
- package/dist/mcp/handlers/v2-execution/continue-rehydrate.js +146 -0
- package/dist/mcp/handlers/v2-execution/index.d.ts +23 -0
- package/dist/mcp/handlers/v2-execution/index.js +113 -0
- package/dist/mcp/handlers/v2-execution/replay.d.ts +55 -0
- package/dist/mcp/handlers/v2-execution/replay.js +227 -0
- package/dist/mcp/handlers/v2-execution/start.d.ts +52 -0
- package/dist/mcp/handlers/v2-execution/start.js +350 -0
- package/dist/mcp/handlers/v2-execution-helpers.d.ts +23 -0
- package/dist/mcp/handlers/v2-execution-helpers.js +42 -1
- package/dist/mcp/handlers/v2-execution.d.ts +1 -23
- package/dist/mcp/handlers/v2-execution.js +5 -898
- package/dist/mcp/handlers/v2-state-conversion.d.ts +0 -5
- package/dist/mcp/handlers/v2-state-conversion.js +2 -21
- package/dist/mcp/handlers/v2-token-ops.d.ts +1 -1
- package/dist/mcp/handlers/v2-workflow.js +76 -64
- package/dist/v2/durable-core/constants.d.ts +60 -0
- package/dist/v2/durable-core/constants.js +55 -1
- package/dist/v2/durable-core/domain/ack-advance-append-plan.d.ts +23 -13
- package/dist/v2/durable-core/domain/ack-advance-append-plan.js +160 -113
- package/dist/v2/durable-core/domain/blocked-node-builder.js +8 -2
- package/dist/v2/durable-core/domain/blocking-decision.d.ts +2 -0
- package/dist/v2/durable-core/domain/blocking-decision.js +29 -12
- package/dist/v2/durable-core/domain/bundle-builder.d.ts +1 -0
- package/dist/v2/durable-core/domain/bundle-builder.js +1 -1
- package/dist/v2/durable-core/domain/bundle-validator.js +3 -2
- package/dist/v2/durable-core/domain/decision-trace-builder.js +7 -9
- package/dist/v2/durable-core/domain/function-definition-expander.js +1 -3
- package/dist/v2/durable-core/domain/gap-builder.js +2 -1
- package/dist/v2/durable-core/domain/observation-builder.js +2 -1
- package/dist/v2/durable-core/domain/outputs.d.ts +2 -1
- package/dist/v2/durable-core/domain/outputs.js +3 -2
- package/dist/v2/durable-core/domain/reason-model.d.ts +1 -1
- package/dist/v2/durable-core/domain/reason-model.js +4 -9
- package/dist/v2/durable-core/domain/validation-criteria-validator.js +2 -2
- package/dist/v2/durable-core/domain/validation-event-builder.js +4 -6
- package/dist/v2/durable-core/domain/validation-loader.js +2 -1
- package/dist/v2/durable-core/domain/validation-requirements-extractor.js +12 -18
- package/dist/v2/durable-core/encoding/base32-lower.d.ts +13 -1
- package/dist/v2/durable-core/encoding/base32-lower.js +13 -3
- package/dist/v2/durable-core/encoding/hex-to-bytes.d.ts +6 -0
- package/dist/v2/durable-core/encoding/hex-to-bytes.js +19 -0
- package/dist/v2/durable-core/ids/attempt-id-derivation.d.ts +6 -1
- package/dist/v2/durable-core/ids/attempt-id-derivation.js +9 -19
- package/dist/v2/durable-core/ids/event-ids.d.ts +9 -0
- package/dist/v2/durable-core/ids/event-ids.js +18 -0
- package/dist/v2/durable-core/ids/index.d.ts +13 -33
- package/dist/v2/durable-core/ids/index.js +22 -63
- package/dist/v2/durable-core/ids/session-ids.d.ts +9 -0
- package/dist/v2/durable-core/ids/session-ids.js +18 -0
- package/dist/v2/durable-core/ids/snapshot-ids.d.ts +6 -0
- package/dist/v2/durable-core/ids/snapshot-ids.js +10 -0
- package/dist/v2/durable-core/ids/token-ids.d.ts +3 -0
- package/dist/v2/durable-core/ids/token-ids.js +6 -0
- package/dist/v2/durable-core/ids/workflow-hash-ref.d.ts +3 -0
- package/dist/v2/durable-core/ids/workflow-hash-ref.js +5 -4
- package/dist/v2/durable-core/ids/workflow-ids.d.ts +11 -0
- package/dist/v2/durable-core/ids/workflow-ids.js +21 -0
- package/dist/v2/durable-core/lib/utf8-byte-length.d.ts +1 -0
- package/dist/v2/durable-core/lib/utf8-byte-length.js +6 -0
- package/dist/v2/durable-core/schemas/artifacts/loop-control.js +2 -1
- package/dist/v2/durable-core/schemas/execution-snapshot/blocked-snapshot.d.ts +24 -24
- package/dist/v2/durable-core/schemas/execution-snapshot/blocked-snapshot.js +5 -7
- package/dist/v2/durable-core/schemas/execution-snapshot/execution-snapshot.v1.d.ts +180 -180
- package/dist/v2/durable-core/schemas/export-bundle/index.d.ts +282 -287
- package/dist/v2/durable-core/schemas/export-bundle/index.js +0 -8
- package/dist/v2/durable-core/schemas/lib/dedupe-key.d.ts +9 -1
- package/dist/v2/durable-core/schemas/lib/dedupe-key.js +4 -3
- package/dist/v2/durable-core/schemas/lib/utf8-byte-length.d.ts +1 -0
- package/dist/v2/durable-core/schemas/lib/utf8-byte-length.js +6 -0
- package/dist/v2/durable-core/schemas/session/blockers.d.ts +305 -0
- package/dist/v2/durable-core/schemas/session/blockers.js +80 -0
- package/dist/v2/durable-core/schemas/session/dag-topology.d.ts +77 -0
- package/dist/v2/durable-core/schemas/session/dag-topology.js +45 -0
- package/dist/v2/durable-core/schemas/session/events.d.ts +36 -36
- package/dist/v2/durable-core/schemas/session/events.js +11 -182
- package/dist/v2/durable-core/schemas/session/gaps.d.ts +211 -0
- package/dist/v2/durable-core/schemas/session/gaps.js +37 -0
- package/dist/v2/durable-core/schemas/session/outputs.d.ts +148 -0
- package/dist/v2/durable-core/schemas/session/outputs.js +44 -0
- package/dist/v2/durable-core/schemas/session/validation-event.js +5 -7
- package/dist/v2/durable-core/tokens/token-codec.d.ts +1 -18
- package/dist/v2/durable-core/tokens/token-codec.js +0 -67
- package/dist/v2/durable-core/tokens/token-signer.d.ts +1 -8
- package/dist/v2/durable-core/tokens/token-signer.js +0 -43
- package/dist/v2/infra/local/base32/index.js +1 -23
- package/dist/v2/infra/local/bech32m/index.js +1 -1
- package/dist/v2/infra/local/data-dir/index.d.ts +7 -6
- package/dist/v2/infra/local/data-dir/index.js +3 -3
- package/dist/v2/infra/local/directory-listing/index.d.ts +2 -2
- package/dist/v2/infra/local/session-store/index.js +198 -182
- package/dist/v2/infra/local/session-summary-provider/index.js +5 -2
- package/dist/v2/infra/local/snapshot-store/index.js +2 -2
- package/dist/v2/ports/data-dir.port.d.ts +7 -6
- package/dist/v2/ports/fs.port.d.ts +18 -7
- package/dist/v2/ports/session-event-log-store.port.d.ts +5 -2
- package/dist/v2/projections/advance-outcomes.d.ts +1 -7
- package/dist/v2/projections/advance-outcomes.js +2 -1
- package/dist/v2/projections/artifacts.js +3 -2
- package/dist/v2/projections/capabilities.d.ts +1 -7
- package/dist/v2/projections/capabilities.js +2 -1
- package/dist/v2/projections/gaps.d.ts +1 -7
- package/dist/v2/projections/gaps.js +2 -1
- package/dist/v2/projections/node-outputs.d.ts +1 -7
- package/dist/v2/projections/node-outputs.js +4 -3
- package/dist/v2/projections/preferences.d.ts +1 -7
- package/dist/v2/projections/preferences.js +2 -1
- package/dist/v2/projections/projection-error.d.ts +7 -0
- package/dist/v2/projections/projection-error.js +2 -0
- package/dist/v2/projections/resume-ranking.js +3 -3
- package/dist/v2/projections/run-context.d.ts +1 -7
- package/dist/v2/projections/run-context.js +4 -2
- package/dist/v2/projections/run-dag.d.ts +9 -9
- package/dist/v2/projections/run-dag.js +88 -65
- package/dist/v2/projections/run-status-signals.d.ts +1 -7
- package/dist/v2/projections/run-status-signals.js +3 -2
- package/dist/v2/usecases/execution-session-gate.js +2 -5
- package/dist/v2/usecases/export-session.js +4 -2
- package/dist/v2/usecases/import-session.d.ts +3 -3
- package/package.json +1 -1
|
@@ -16,29 +16,7 @@ class Base32AdapterV2 {
|
|
|
16
16
|
position: invalidMatch?.index,
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
|
-
|
|
20
|
-
const bytes = (0, base32_lower_js_1.decodeBase32LowerNoPad)(encoded);
|
|
21
|
-
return (0, neverthrow_1.ok)(bytes);
|
|
22
|
-
}
|
|
23
|
-
catch (e) {
|
|
24
|
-
const message = e instanceof Error ? e.message : String(e);
|
|
25
|
-
if (/padding|non-canonical/i.test(message)) {
|
|
26
|
-
return (0, neverthrow_1.err)({
|
|
27
|
-
code: 'BASE32_NON_CANONICAL',
|
|
28
|
-
message: `Non-canonical base32 encoding: ${message}`,
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
if (/length/i.test(message)) {
|
|
32
|
-
return (0, neverthrow_1.err)({
|
|
33
|
-
code: 'BASE32_INVALID_LENGTH',
|
|
34
|
-
message: `Invalid base32 length: ${message}`,
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
return (0, neverthrow_1.err)({
|
|
38
|
-
code: 'BASE32_INVALID_CHARACTERS',
|
|
39
|
-
message: `Base32 decode failed: ${message}`,
|
|
40
|
-
});
|
|
41
|
-
}
|
|
19
|
+
return (0, base32_lower_js_1.decodeBase32LowerNoPad)(encoded);
|
|
42
20
|
}
|
|
43
21
|
}
|
|
44
22
|
exports.Base32AdapterV2 = Base32AdapterV2;
|
|
@@ -22,7 +22,7 @@ class Bech32mAdapterV2 {
|
|
|
22
22
|
}
|
|
23
23
|
catch (e) {
|
|
24
24
|
const msg = e instanceof Error ? e.message : String(e);
|
|
25
|
-
if (/checksum/i.test(msg)
|
|
25
|
+
if (/checksum/i.test(msg)) {
|
|
26
26
|
return (0, neverthrow_1.err)({
|
|
27
27
|
code: 'BECH32M_CHECKSUM_FAILED',
|
|
28
28
|
message: `Bech32m checksum validation failed (likely corruption): ${msg}`,
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import type { DataDirPortV2 } from '../../../ports/data-dir.port.js';
|
|
2
|
+
import type { SessionId, WorkflowHash, SnapshotRef } from '../../../durable-core/ids/index.js';
|
|
2
3
|
export declare class LocalDataDirV2 implements DataDirPortV2 {
|
|
3
4
|
private readonly env;
|
|
4
5
|
constructor(env: Record<string, string | undefined>);
|
|
5
6
|
private safeFileSegment;
|
|
6
7
|
private root;
|
|
7
8
|
snapshotsDir(): string;
|
|
8
|
-
snapshotPath(snapshotRef:
|
|
9
|
+
snapshotPath(snapshotRef: SnapshotRef): string;
|
|
9
10
|
keysDir(): string;
|
|
10
11
|
keyringPath(): string;
|
|
11
12
|
pinnedWorkflowsDir(): string;
|
|
12
|
-
pinnedWorkflowPath(workflowHash:
|
|
13
|
+
pinnedWorkflowPath(workflowHash: WorkflowHash): string;
|
|
13
14
|
sessionsDir(): string;
|
|
14
|
-
sessionDir(sessionId:
|
|
15
|
-
sessionEventsDir(sessionId:
|
|
16
|
-
sessionManifestPath(sessionId:
|
|
17
|
-
sessionLockPath(sessionId:
|
|
15
|
+
sessionDir(sessionId: SessionId): string;
|
|
16
|
+
sessionEventsDir(sessionId: SessionId): string;
|
|
17
|
+
sessionManifestPath(sessionId: SessionId): string;
|
|
18
|
+
sessionLockPath(sessionId: SessionId): string;
|
|
18
19
|
}
|
|
@@ -51,7 +51,7 @@ class LocalDataDirV2 {
|
|
|
51
51
|
return path.join(this.root(), 'snapshots');
|
|
52
52
|
}
|
|
53
53
|
snapshotPath(snapshotRef) {
|
|
54
|
-
return path.join(this.snapshotsDir(), `${this.safeFileSegment(snapshotRef)}.json`);
|
|
54
|
+
return path.join(this.snapshotsDir(), `${this.safeFileSegment(String(snapshotRef))}.json`);
|
|
55
55
|
}
|
|
56
56
|
keysDir() {
|
|
57
57
|
return path.join(this.root(), 'keys');
|
|
@@ -63,13 +63,13 @@ class LocalDataDirV2 {
|
|
|
63
63
|
return path.join(this.root(), 'workflows', 'pinned');
|
|
64
64
|
}
|
|
65
65
|
pinnedWorkflowPath(workflowHash) {
|
|
66
|
-
return path.join(this.pinnedWorkflowsDir(), `${this.safeFileSegment(workflowHash)}.json`);
|
|
66
|
+
return path.join(this.pinnedWorkflowsDir(), `${this.safeFileSegment(String(workflowHash))}.json`);
|
|
67
67
|
}
|
|
68
68
|
sessionsDir() {
|
|
69
69
|
return path.join(this.root(), 'sessions');
|
|
70
70
|
}
|
|
71
71
|
sessionDir(sessionId) {
|
|
72
|
-
return path.join(this.sessionsDir(), sessionId);
|
|
72
|
+
return path.join(this.sessionsDir(), String(sessionId));
|
|
73
73
|
}
|
|
74
74
|
sessionEventsDir(sessionId) {
|
|
75
75
|
return path.join(this.sessionDir(sessionId), 'events');
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { ResultAsync } from 'neverthrow';
|
|
2
|
-
import type { FsError,
|
|
2
|
+
import type { FsError, DirectoryListingOpsPortV2 } from '../../../ports/fs.port.js';
|
|
3
3
|
import type { DirectoryListingPortV2 } from '../../../ports/directory-listing.port.js';
|
|
4
4
|
export declare class LocalDirectoryListingV2 implements DirectoryListingPortV2 {
|
|
5
5
|
private readonly fs;
|
|
6
|
-
constructor(fs:
|
|
6
|
+
constructor(fs: DirectoryListingOpsPortV2);
|
|
7
7
|
readdir(dirPath: string): ResultAsync<readonly string[], FsError>;
|
|
8
8
|
}
|
|
@@ -37,6 +37,7 @@ exports.LocalSessionEventLogStoreV2 = void 0;
|
|
|
37
37
|
const neverthrow_1 = require("neverthrow");
|
|
38
38
|
const jsonl_js_1 = require("../../../durable-core/canonical/jsonl.js");
|
|
39
39
|
const index_js_1 = require("../../../durable-core/schemas/session/index.js");
|
|
40
|
+
const constants_js_1 = require("../../../durable-core/constants.js");
|
|
40
41
|
const path = __importStar(require("path"));
|
|
41
42
|
class LocalSessionEventLogStoreV2 {
|
|
42
43
|
constructor(dataDir, fs, sha256) {
|
|
@@ -108,7 +109,7 @@ class LocalSessionEventLogStoreV2 {
|
|
|
108
109
|
v: 1,
|
|
109
110
|
manifestIndex: nextManifestIndex(manifest),
|
|
110
111
|
sessionId,
|
|
111
|
-
kind:
|
|
112
|
+
kind: constants_js_1.MANIFEST_KIND.SEGMENT_CLOSED,
|
|
112
113
|
firstEventIndex: first,
|
|
113
114
|
lastEventIndex: last,
|
|
114
115
|
segmentRelPath,
|
|
@@ -125,7 +126,7 @@ class LocalSessionEventLogStoreV2 {
|
|
|
125
126
|
v: 1,
|
|
126
127
|
manifestIndex: startIndex + i,
|
|
127
128
|
sessionId,
|
|
128
|
-
kind:
|
|
129
|
+
kind: constants_js_1.MANIFEST_KIND.SNAPSHOT_PINNED,
|
|
129
130
|
eventIndex: p.eventIndex,
|
|
130
131
|
snapshotRef: p.snapshotRef,
|
|
131
132
|
createdByEventId: p.createdByEventId,
|
|
@@ -145,72 +146,16 @@ class LocalSessionEventLogStoreV2 {
|
|
|
145
146
|
const segRes = validateSegmentClosedContiguity(manifest);
|
|
146
147
|
if (segRes.isErr())
|
|
147
148
|
return (0, neverthrow_1.errAsync)(segRes.error);
|
|
148
|
-
const segments = manifest.filter((m) => m.kind ===
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
.mapErr((e) => {
|
|
156
|
-
if (e.code === 'FS_NOT_FOUND') {
|
|
157
|
-
return {
|
|
158
|
-
code: 'SESSION_STORE_CORRUPTION_DETECTED',
|
|
159
|
-
location: 'tail',
|
|
160
|
-
reason: { code: 'missing_attested_segment', message: `Missing attested segment: ${head.segmentRelPath}` },
|
|
161
|
-
message: `Missing attested segment: ${head.segmentRelPath}`,
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
return mapFsToStoreError(e);
|
|
165
|
-
})
|
|
166
|
-
.andThen((bytes) => {
|
|
167
|
-
const actual = this.sha256.sha256(bytes);
|
|
168
|
-
if (actual !== head.sha256) {
|
|
169
|
-
return (0, neverthrow_1.errAsync)({
|
|
170
|
-
code: 'SESSION_STORE_CORRUPTION_DETECTED',
|
|
171
|
-
location: 'tail',
|
|
172
|
-
reason: { code: 'digest_mismatch', message: `Segment digest mismatch: ${head.segmentRelPath}` },
|
|
173
|
-
message: `Segment digest mismatch: ${head.segmentRelPath}`,
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
const parsedRes = parseJsonlLines(bytes, index_js_1.DomainEventV1Schema);
|
|
177
|
-
if (parsedRes.isErr())
|
|
178
|
-
return (0, neverthrow_1.errAsync)(parsedRes.error);
|
|
179
|
-
const parsed = parsedRes.value;
|
|
180
|
-
if (parsed.length === 0) {
|
|
181
|
-
return (0, neverthrow_1.errAsync)({
|
|
182
|
-
code: 'SESSION_STORE_CORRUPTION_DETECTED',
|
|
183
|
-
location: 'tail',
|
|
184
|
-
reason: { code: 'non_contiguous_indices', message: `Empty segment referenced by manifest: ${head.segmentRelPath}` },
|
|
185
|
-
message: `Empty segment referenced by manifest: ${head.segmentRelPath}`,
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
if (parsed[0].eventIndex !== head.firstEventIndex || parsed[parsed.length - 1].eventIndex !== head.lastEventIndex) {
|
|
189
|
-
return (0, neverthrow_1.errAsync)({
|
|
190
|
-
code: 'SESSION_STORE_CORRUPTION_DETECTED',
|
|
191
|
-
location: 'tail',
|
|
192
|
-
reason: { code: 'non_contiguous_indices', message: `Segment bounds mismatch: ${head.segmentRelPath}` },
|
|
193
|
-
message: `Segment bounds mismatch: ${head.segmentRelPath}`,
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
for (let i = 1; i < parsed.length; i++) {
|
|
197
|
-
if (parsed[i].eventIndex !== parsed[i - 1].eventIndex + 1) {
|
|
198
|
-
return (0, neverthrow_1.errAsync)({
|
|
199
|
-
code: 'SESSION_STORE_CORRUPTION_DETECTED',
|
|
200
|
-
location: 'tail',
|
|
201
|
-
reason: { code: 'non_contiguous_indices', message: `Non-contiguous eventIndex inside segment: ${head.segmentRelPath}` },
|
|
202
|
-
message: `Non-contiguous eventIndex inside segment: ${head.segmentRelPath}`,
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
return (0, neverthrow_1.okAsync)(parsed);
|
|
207
|
-
})
|
|
208
|
-
.andThen((events) => loadSegments(tail).map((rest) => [...events, ...rest]));
|
|
209
|
-
};
|
|
210
|
-
return loadSegments(segments).andThen((events) => {
|
|
149
|
+
const segments = manifest.filter((m) => m.kind === constants_js_1.MANIFEST_KIND.SEGMENT_CLOSED);
|
|
150
|
+
return loadSegmentsRecursive({
|
|
151
|
+
segments,
|
|
152
|
+
sessionDir,
|
|
153
|
+
sha256: this.sha256,
|
|
154
|
+
fs: this.fs,
|
|
155
|
+
}).andThen((events) => {
|
|
211
156
|
const expectedPins = extractSnapshotPinsFromEvents(events);
|
|
212
157
|
const actualPins = new Set(manifest
|
|
213
|
-
.filter((m) => m.kind ===
|
|
158
|
+
.filter((m) => m.kind === constants_js_1.MANIFEST_KIND.SNAPSHOT_PINNED)
|
|
214
159
|
.map((p) => `${p.eventIndex}:${p.createdByEventId}:${p.snapshotRef}`));
|
|
215
160
|
for (const ep of expectedPins) {
|
|
216
161
|
const key = `${ep.eventIndex}:${ep.createdByEventId}:${ep.snapshotRef}`;
|
|
@@ -247,44 +192,10 @@ class LocalSessionEventLogStoreV2 {
|
|
|
247
192
|
.orElse((e) => (e.code === 'FS_NOT_FOUND' ? (0, neverthrow_1.okAsync)('') : (0, neverthrow_1.errAsync)(mapFsToStoreError(e))))
|
|
248
193
|
.andThen((raw) => {
|
|
249
194
|
if (raw.trim() === '') {
|
|
250
|
-
return (0, neverthrow_1.okAsync)({ truth: { manifest: [], events: [] }
|
|
195
|
+
return (0, neverthrow_1.okAsync)({ kind: 'complete', truth: { manifest: [], events: [] } });
|
|
251
196
|
}
|
|
252
197
|
const lines = raw.split('\n').filter((l) => l.trim() !== '');
|
|
253
|
-
const manifest =
|
|
254
|
-
let isComplete = true;
|
|
255
|
-
let tailReason = null;
|
|
256
|
-
for (let i = 0; i < lines.length; i++) {
|
|
257
|
-
const line = lines[i];
|
|
258
|
-
let parsed;
|
|
259
|
-
try {
|
|
260
|
-
parsed = JSON.parse(line);
|
|
261
|
-
}
|
|
262
|
-
catch {
|
|
263
|
-
isComplete = false;
|
|
264
|
-
tailReason ?? (tailReason = { code: 'non_contiguous_indices', message: 'Invalid JSON in manifest (corrupt tail)' });
|
|
265
|
-
break;
|
|
266
|
-
}
|
|
267
|
-
const validated = index_js_1.ManifestRecordV1Schema.safeParse(parsed);
|
|
268
|
-
if (!validated.success) {
|
|
269
|
-
isComplete = false;
|
|
270
|
-
const rawVersion = (typeof parsed === 'object' && parsed !== null && 'v' in parsed)
|
|
271
|
-
? parsed.v
|
|
272
|
-
: undefined;
|
|
273
|
-
if (rawVersion !== 1) {
|
|
274
|
-
tailReason ?? (tailReason = { code: 'unknown_schema_version', message: `Expected v=1, got v=${rawVersion}` });
|
|
275
|
-
}
|
|
276
|
-
else {
|
|
277
|
-
tailReason ?? (tailReason = { code: 'schema_validation_failed', message: 'Manifest record schema validation failed (corrupt tail)' });
|
|
278
|
-
}
|
|
279
|
-
break;
|
|
280
|
-
}
|
|
281
|
-
if (validated.data.manifestIndex !== i) {
|
|
282
|
-
isComplete = false;
|
|
283
|
-
tailReason ?? (tailReason = { code: 'non_contiguous_indices', message: 'Non-contiguous manifestIndex in prefix (corrupt tail)' });
|
|
284
|
-
break;
|
|
285
|
-
}
|
|
286
|
-
manifest.push(validated.data);
|
|
287
|
-
}
|
|
198
|
+
const { manifest, isComplete, tailReason } = parseManifestPrefix(lines);
|
|
288
199
|
if (manifest.length === 0) {
|
|
289
200
|
return (0, neverthrow_1.errAsync)({
|
|
290
201
|
code: 'SESSION_STORE_CORRUPTION_DETECTED',
|
|
@@ -293,84 +204,29 @@ class LocalSessionEventLogStoreV2 {
|
|
|
293
204
|
message: 'No validated manifest prefix',
|
|
294
205
|
});
|
|
295
206
|
}
|
|
296
|
-
const segments = manifest.filter((m) => m.kind ===
|
|
207
|
+
const segments = manifest.filter((m) => m.kind === constants_js_1.MANIFEST_KIND.SEGMENT_CLOSED);
|
|
297
208
|
const initial = { events: [], isComplete, tailReason, done: false };
|
|
298
|
-
const processSegment = (seg, state) => {
|
|
299
|
-
if (state.done)
|
|
300
|
-
return (0, neverthrow_1.okAsync)(state);
|
|
301
|
-
const segmentPath = path.join(sessionDir, seg.segmentRelPath);
|
|
302
|
-
return this.fs
|
|
303
|
-
.readFileBytes(segmentPath)
|
|
304
|
-
.map((bytes) => ({ kind: 'present', bytes }))
|
|
305
|
-
.orElse((e) => (e.code === 'FS_NOT_FOUND' ? (0, neverthrow_1.okAsync)({ kind: 'missing' }) : (0, neverthrow_1.errAsync)(mapFsToStoreError(e))))
|
|
306
|
-
.andThen((res) => {
|
|
307
|
-
if (res.kind === 'missing') {
|
|
308
|
-
return (0, neverthrow_1.okAsync)({
|
|
309
|
-
...state,
|
|
310
|
-
isComplete: false,
|
|
311
|
-
tailReason: state.tailReason ?? { code: 'missing_attested_segment', message: `Missing attested segment: ${seg.segmentRelPath}` },
|
|
312
|
-
done: true,
|
|
313
|
-
});
|
|
314
|
-
}
|
|
315
|
-
const bytes = res.bytes;
|
|
316
|
-
const actual = this.sha256.sha256(bytes);
|
|
317
|
-
if (actual !== seg.sha256) {
|
|
318
|
-
return (0, neverthrow_1.okAsync)({
|
|
319
|
-
...state,
|
|
320
|
-
isComplete: false,
|
|
321
|
-
tailReason: state.tailReason ?? { code: 'digest_mismatch', message: `Segment digest mismatch: ${seg.segmentRelPath}` },
|
|
322
|
-
done: true,
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
const parsedRes = parseJsonlLines(bytes, index_js_1.DomainEventV1Schema);
|
|
326
|
-
if (parsedRes.isErr()) {
|
|
327
|
-
return (0, neverthrow_1.okAsync)({
|
|
328
|
-
...state,
|
|
329
|
-
isComplete: false,
|
|
330
|
-
tailReason: state.tailReason ?? { code: 'non_contiguous_indices', message: `Invalid JSONL inside segment: ${seg.segmentRelPath}` },
|
|
331
|
-
done: true,
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
const parsed = parsedRes.value;
|
|
335
|
-
if (parsed.length === 0) {
|
|
336
|
-
return (0, neverthrow_1.okAsync)({
|
|
337
|
-
...state,
|
|
338
|
-
isComplete: false,
|
|
339
|
-
tailReason: state.tailReason ?? { code: 'non_contiguous_indices', message: `Empty segment referenced by manifest: ${seg.segmentRelPath}` },
|
|
340
|
-
done: true,
|
|
341
|
-
});
|
|
342
|
-
}
|
|
343
|
-
if (parsed[0].eventIndex !== seg.firstEventIndex || parsed[parsed.length - 1].eventIndex !== seg.lastEventIndex) {
|
|
344
|
-
return (0, neverthrow_1.okAsync)({
|
|
345
|
-
...state,
|
|
346
|
-
isComplete: false,
|
|
347
|
-
tailReason: state.tailReason ?? { code: 'non_contiguous_indices', message: `Segment bounds mismatch: ${seg.segmentRelPath}` },
|
|
348
|
-
done: true,
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
for (let i = 1; i < parsed.length; i++) {
|
|
352
|
-
if (parsed[i].eventIndex !== parsed[i - 1].eventIndex + 1) {
|
|
353
|
-
return (0, neverthrow_1.okAsync)({
|
|
354
|
-
...state,
|
|
355
|
-
isComplete: false,
|
|
356
|
-
tailReason: state.tailReason ?? { code: 'non_contiguous_indices', message: `Non-contiguous eventIndex inside segment: ${seg.segmentRelPath}` },
|
|
357
|
-
done: true,
|
|
358
|
-
});
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
return (0, neverthrow_1.okAsync)({
|
|
362
|
-
...state,
|
|
363
|
-
events: [...state.events, ...parsed],
|
|
364
|
-
});
|
|
365
|
-
});
|
|
366
|
-
};
|
|
367
209
|
return segments
|
|
368
|
-
.reduce((acc, seg) => acc.andThen((s) =>
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
210
|
+
.reduce((acc, seg) => acc.andThen((s) => processSegmentForSalvage({
|
|
211
|
+
segment: seg,
|
|
212
|
+
sessionDir,
|
|
213
|
+
sha256: this.sha256,
|
|
214
|
+
fs: this.fs,
|
|
215
|
+
state: s,
|
|
216
|
+
})), (0, neverthrow_1.okAsync)(initial))
|
|
217
|
+
.map((final) => {
|
|
218
|
+
if (final.isComplete) {
|
|
219
|
+
return { kind: 'complete', truth: { manifest, events: final.events } };
|
|
220
|
+
}
|
|
221
|
+
return {
|
|
222
|
+
kind: 'truncated',
|
|
223
|
+
truth: { manifest, events: final.events },
|
|
224
|
+
tailReason: final.tailReason ?? {
|
|
225
|
+
code: 'non_contiguous_indices',
|
|
226
|
+
message: 'Unknown truncation reason',
|
|
227
|
+
},
|
|
228
|
+
};
|
|
229
|
+
});
|
|
374
230
|
});
|
|
375
231
|
}
|
|
376
232
|
loadTruthOrEmpty(sessionId) {
|
|
@@ -378,7 +234,7 @@ class LocalSessionEventLogStoreV2 {
|
|
|
378
234
|
.andThen((manifest) => {
|
|
379
235
|
if (manifest.length === 0)
|
|
380
236
|
return (0, neverthrow_1.okAsync)({ manifest: [], events: [] });
|
|
381
|
-
const segments = manifest.filter((m) => m.kind ===
|
|
237
|
+
const segments = manifest.filter((m) => m.kind === constants_js_1.MANIFEST_KIND.SEGMENT_CLOSED);
|
|
382
238
|
const sessionDir = this.dataDir.sessionDir(sessionId);
|
|
383
239
|
const loadSegments = (segs) => {
|
|
384
240
|
if (segs.length === 0)
|
|
@@ -425,7 +281,7 @@ function nextManifestIndex(manifest) {
|
|
|
425
281
|
return manifest[manifest.length - 1].manifestIndex + 1;
|
|
426
282
|
}
|
|
427
283
|
function nextEventIndexFromManifest(manifest) {
|
|
428
|
-
const segments = manifest.filter((m) => m.kind ===
|
|
284
|
+
const segments = manifest.filter((m) => m.kind === constants_js_1.MANIFEST_KIND.SEGMENT_CLOSED);
|
|
429
285
|
if (segments.length === 0)
|
|
430
286
|
return 0;
|
|
431
287
|
return segments[segments.length - 1].lastEventIndex + 1;
|
|
@@ -448,7 +304,7 @@ function validateManifestContiguity(manifest) {
|
|
|
448
304
|
return (0, neverthrow_1.ok)(undefined);
|
|
449
305
|
}
|
|
450
306
|
function validateSegmentClosedContiguity(manifest) {
|
|
451
|
-
const segments = manifest.filter((m) => m.kind ===
|
|
307
|
+
const segments = manifest.filter((m) => m.kind === constants_js_1.MANIFEST_KIND.SEGMENT_CLOSED);
|
|
452
308
|
for (let i = 1; i < segments.length; i++) {
|
|
453
309
|
const prev = segments[i - 1];
|
|
454
310
|
const cur = segments[i];
|
|
@@ -589,9 +445,169 @@ function parseJsonlLines(bytes, schema) {
|
|
|
589
445
|
function extractSnapshotPinsFromEvents(events) {
|
|
590
446
|
const out = [];
|
|
591
447
|
for (const e of events) {
|
|
592
|
-
if (e.kind !==
|
|
448
|
+
if (e.kind !== constants_js_1.EVENT_KIND.NODE_CREATED)
|
|
593
449
|
continue;
|
|
594
450
|
out.push({ snapshotRef: e.data.snapshotRef, eventIndex: e.eventIndex, createdByEventId: e.eventId });
|
|
595
451
|
}
|
|
596
452
|
return out;
|
|
597
453
|
}
|
|
454
|
+
function validateSegmentBounds(parsed, segment) {
|
|
455
|
+
if (parsed.length === 0) {
|
|
456
|
+
return (0, neverthrow_1.err)({
|
|
457
|
+
code: 'SESSION_STORE_CORRUPTION_DETECTED',
|
|
458
|
+
location: 'tail',
|
|
459
|
+
reason: { code: 'non_contiguous_indices', message: `Empty segment referenced by manifest: ${segment.segmentRelPath}` },
|
|
460
|
+
message: `Empty segment referenced by manifest: ${segment.segmentRelPath}`,
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
if (parsed[0].eventIndex !== segment.firstEventIndex || parsed[parsed.length - 1].eventIndex !== segment.lastEventIndex) {
|
|
464
|
+
return (0, neverthrow_1.err)({
|
|
465
|
+
code: 'SESSION_STORE_CORRUPTION_DETECTED',
|
|
466
|
+
location: 'tail',
|
|
467
|
+
reason: { code: 'non_contiguous_indices', message: `Segment bounds mismatch: ${segment.segmentRelPath}` },
|
|
468
|
+
message: `Segment bounds mismatch: ${segment.segmentRelPath}`,
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
for (let i = 1; i < parsed.length; i++) {
|
|
472
|
+
if (parsed[i].eventIndex !== parsed[i - 1].eventIndex + 1) {
|
|
473
|
+
return (0, neverthrow_1.err)({
|
|
474
|
+
code: 'SESSION_STORE_CORRUPTION_DETECTED',
|
|
475
|
+
location: 'tail',
|
|
476
|
+
reason: { code: 'non_contiguous_indices', message: `Non-contiguous eventIndex inside segment: ${segment.segmentRelPath}` },
|
|
477
|
+
message: `Non-contiguous eventIndex inside segment: ${segment.segmentRelPath}`,
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
return (0, neverthrow_1.ok)(undefined);
|
|
482
|
+
}
|
|
483
|
+
function parseManifestPrefix(lines) {
|
|
484
|
+
const manifest = [];
|
|
485
|
+
let isComplete = true;
|
|
486
|
+
let tailReason = null;
|
|
487
|
+
for (let i = 0; i < lines.length; i++) {
|
|
488
|
+
const line = lines[i];
|
|
489
|
+
let parsed;
|
|
490
|
+
try {
|
|
491
|
+
parsed = JSON.parse(line);
|
|
492
|
+
}
|
|
493
|
+
catch {
|
|
494
|
+
isComplete = false;
|
|
495
|
+
tailReason ?? (tailReason = { code: 'non_contiguous_indices', message: 'Invalid JSON in manifest (corrupt tail)' });
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
const validated = index_js_1.ManifestRecordV1Schema.safeParse(parsed);
|
|
499
|
+
if (!validated.success) {
|
|
500
|
+
isComplete = false;
|
|
501
|
+
const rawVersion = (typeof parsed === 'object' && parsed !== null && 'v' in parsed)
|
|
502
|
+
? parsed.v
|
|
503
|
+
: undefined;
|
|
504
|
+
if (rawVersion !== 1) {
|
|
505
|
+
tailReason ?? (tailReason = { code: 'unknown_schema_version', message: `Expected v=1, got v=${rawVersion}` });
|
|
506
|
+
}
|
|
507
|
+
else {
|
|
508
|
+
tailReason ?? (tailReason = { code: 'schema_validation_failed', message: 'Manifest record schema validation failed (corrupt tail)' });
|
|
509
|
+
}
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
512
|
+
if (validated.data.manifestIndex !== i) {
|
|
513
|
+
isComplete = false;
|
|
514
|
+
tailReason ?? (tailReason = { code: 'non_contiguous_indices', message: 'Non-contiguous manifestIndex in prefix (corrupt tail)' });
|
|
515
|
+
break;
|
|
516
|
+
}
|
|
517
|
+
manifest.push(validated.data);
|
|
518
|
+
}
|
|
519
|
+
return { manifest, isComplete, tailReason };
|
|
520
|
+
}
|
|
521
|
+
function processSegmentForSalvage(args) {
|
|
522
|
+
if (args.state.done)
|
|
523
|
+
return (0, neverthrow_1.okAsync)(args.state);
|
|
524
|
+
const segmentPath = path.join(args.sessionDir, args.segment.segmentRelPath);
|
|
525
|
+
return args.fs
|
|
526
|
+
.readFileBytes(segmentPath)
|
|
527
|
+
.map((bytes) => ({ kind: 'present', bytes }))
|
|
528
|
+
.orElse((e) => (e.code === 'FS_NOT_FOUND' ? (0, neverthrow_1.okAsync)({ kind: 'missing' }) : (0, neverthrow_1.errAsync)(mapFsToStoreError(e))))
|
|
529
|
+
.andThen((res) => {
|
|
530
|
+
if (res.kind === 'missing') {
|
|
531
|
+
return (0, neverthrow_1.okAsync)({
|
|
532
|
+
...args.state,
|
|
533
|
+
isComplete: false,
|
|
534
|
+
tailReason: args.state.tailReason ?? { code: 'missing_attested_segment', message: `Missing attested segment: ${args.segment.segmentRelPath}` },
|
|
535
|
+
done: true,
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
const bytes = res.bytes;
|
|
539
|
+
const actual = args.sha256.sha256(bytes);
|
|
540
|
+
if (actual !== args.segment.sha256) {
|
|
541
|
+
return (0, neverthrow_1.okAsync)({
|
|
542
|
+
...args.state,
|
|
543
|
+
isComplete: false,
|
|
544
|
+
tailReason: args.state.tailReason ?? { code: 'digest_mismatch', message: `Segment digest mismatch: ${args.segment.segmentRelPath}` },
|
|
545
|
+
done: true,
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
const parsedRes = parseJsonlLines(bytes, index_js_1.DomainEventV1Schema);
|
|
549
|
+
if (parsedRes.isErr()) {
|
|
550
|
+
return (0, neverthrow_1.okAsync)({
|
|
551
|
+
...args.state,
|
|
552
|
+
isComplete: false,
|
|
553
|
+
tailReason: args.state.tailReason ?? { code: 'non_contiguous_indices', message: `Invalid JSONL inside segment: ${args.segment.segmentRelPath}` },
|
|
554
|
+
done: true,
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
const parsed = parsedRes.value;
|
|
558
|
+
const boundsResult = validateSegmentBounds(parsed, args.segment);
|
|
559
|
+
if (boundsResult.isErr()) {
|
|
560
|
+
const reason = boundsResult.error.code === 'SESSION_STORE_CORRUPTION_DETECTED'
|
|
561
|
+
? boundsResult.error.reason
|
|
562
|
+
: { code: 'non_contiguous_indices', message: boundsResult.error.message };
|
|
563
|
+
return (0, neverthrow_1.okAsync)({
|
|
564
|
+
...args.state,
|
|
565
|
+
isComplete: false,
|
|
566
|
+
tailReason: args.state.tailReason ?? reason,
|
|
567
|
+
done: true,
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
return (0, neverthrow_1.okAsync)({
|
|
571
|
+
...args.state,
|
|
572
|
+
events: [...args.state.events, ...parsed],
|
|
573
|
+
});
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
function loadSegmentsRecursive(args) {
|
|
577
|
+
if (args.segments.length === 0)
|
|
578
|
+
return (0, neverthrow_1.okAsync)([]);
|
|
579
|
+
const [head, ...tail] = args.segments;
|
|
580
|
+
const segmentPath = path.join(args.sessionDir, head.segmentRelPath);
|
|
581
|
+
return args.fs.readFileBytes(segmentPath)
|
|
582
|
+
.mapErr((e) => {
|
|
583
|
+
if (e.code === 'FS_NOT_FOUND') {
|
|
584
|
+
return {
|
|
585
|
+
code: 'SESSION_STORE_CORRUPTION_DETECTED',
|
|
586
|
+
location: 'tail',
|
|
587
|
+
reason: { code: 'missing_attested_segment', message: `Missing attested segment: ${head.segmentRelPath}` },
|
|
588
|
+
message: `Missing attested segment: ${head.segmentRelPath}`,
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
return mapFsToStoreError(e);
|
|
592
|
+
})
|
|
593
|
+
.andThen((bytes) => {
|
|
594
|
+
const actual = args.sha256.sha256(bytes);
|
|
595
|
+
if (actual !== head.sha256) {
|
|
596
|
+
return (0, neverthrow_1.errAsync)({
|
|
597
|
+
code: 'SESSION_STORE_CORRUPTION_DETECTED',
|
|
598
|
+
location: 'tail',
|
|
599
|
+
reason: { code: 'digest_mismatch', message: `Segment digest mismatch: ${head.segmentRelPath}` },
|
|
600
|
+
message: `Segment digest mismatch: ${head.segmentRelPath}`,
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
const parsedRes = parseJsonlLines(bytes, index_js_1.DomainEventV1Schema);
|
|
604
|
+
if (parsedRes.isErr())
|
|
605
|
+
return (0, neverthrow_1.errAsync)(parsedRes.error);
|
|
606
|
+
const parsed = parsedRes.value;
|
|
607
|
+
const boundsResult = validateSegmentBounds(parsed, head);
|
|
608
|
+
if (boundsResult.isErr())
|
|
609
|
+
return (0, neverthrow_1.errAsync)(boundsResult.error);
|
|
610
|
+
return (0, neverthrow_1.okAsync)(parsed);
|
|
611
|
+
})
|
|
612
|
+
.andThen((events) => loadSegmentsRecursive({ ...args, segments: tail }).map((rest) => [...events, ...rest]));
|
|
613
|
+
}
|
|
@@ -7,6 +7,7 @@ const enumerate_sessions_js_1 = require("../../../usecases/enumerate-sessions.js
|
|
|
7
7
|
const session_health_js_1 = require("../../../projections/session-health.js");
|
|
8
8
|
const run_dag_js_1 = require("../../../projections/run-dag.js");
|
|
9
9
|
const node_outputs_js_1 = require("../../../projections/node-outputs.js");
|
|
10
|
+
const constants_js_1 = require("../../../durable-core/constants.js");
|
|
10
11
|
const MAX_SESSIONS_TO_SCAN = 50;
|
|
11
12
|
class LocalSessionSummaryProviderV2 {
|
|
12
13
|
constructor(ports) {
|
|
@@ -107,7 +108,7 @@ function extractObservations(events) {
|
|
|
107
108
|
let gitBranch = null;
|
|
108
109
|
let repoRootHash = null;
|
|
109
110
|
for (const event of events) {
|
|
110
|
-
if (event.kind !==
|
|
111
|
+
if (event.kind !== constants_js_1.EVENT_KIND.OBSERVATION_RECORDED)
|
|
111
112
|
continue;
|
|
112
113
|
const data = event.data;
|
|
113
114
|
switch (data.key) {
|
|
@@ -120,13 +121,15 @@ function extractObservations(events) {
|
|
|
120
121
|
case 'repo_root_hash':
|
|
121
122
|
repoRootHash = data.value.value;
|
|
122
123
|
break;
|
|
124
|
+
default:
|
|
125
|
+
break;
|
|
123
126
|
}
|
|
124
127
|
}
|
|
125
128
|
return { gitHeadSha, gitBranch, repoRootHash };
|
|
126
129
|
}
|
|
127
130
|
function extractWorkflowIdentity(events, runId) {
|
|
128
131
|
for (const event of events) {
|
|
129
|
-
if (event.kind !==
|
|
132
|
+
if (event.kind !== constants_js_1.EVENT_KIND.RUN_STARTED)
|
|
130
133
|
continue;
|
|
131
134
|
const scope = event.scope;
|
|
132
135
|
if (scope?.runId !== runId)
|
|
@@ -20,7 +20,7 @@ class LocalSnapshotStoreV2 {
|
|
|
20
20
|
return (0, neverthrow_1.errAsync)(canonical.error);
|
|
21
21
|
const ref = (0, index_js_1.asSnapshotRef)(this.crypto.sha256(canonical.value));
|
|
22
22
|
const dir = this.dataDir.snapshotsDir();
|
|
23
|
-
const filePath = this.dataDir.snapshotPath(
|
|
23
|
+
const filePath = this.dataDir.snapshotPath(ref);
|
|
24
24
|
const tmpPath = `${filePath}.tmp`;
|
|
25
25
|
return this.fs
|
|
26
26
|
.mkdirp(dir)
|
|
@@ -35,7 +35,7 @@ class LocalSnapshotStoreV2 {
|
|
|
35
35
|
.mapErr((e) => ({ code: 'SNAPSHOT_STORE_IO_ERROR', message: e.message }));
|
|
36
36
|
}
|
|
37
37
|
getExecutionSnapshotV1(snapshotRef) {
|
|
38
|
-
const filePath = this.dataDir.snapshotPath(
|
|
38
|
+
const filePath = this.dataDir.snapshotPath(snapshotRef);
|
|
39
39
|
return this.fs
|
|
40
40
|
.readFileBytes(filePath)
|
|
41
41
|
.andThen((bytes) => {
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
import type { SessionId, WorkflowHash, SnapshotRef } from '../durable-core/ids/index.js';
|
|
1
2
|
export interface DataDirPortV2 {
|
|
2
3
|
pinnedWorkflowsDir(): string;
|
|
3
|
-
pinnedWorkflowPath(workflowHash:
|
|
4
|
+
pinnedWorkflowPath(workflowHash: WorkflowHash): string;
|
|
4
5
|
snapshotsDir(): string;
|
|
5
|
-
snapshotPath(snapshotRef:
|
|
6
|
+
snapshotPath(snapshotRef: SnapshotRef): string;
|
|
6
7
|
keysDir(): string;
|
|
7
8
|
keyringPath(): string;
|
|
8
9
|
sessionsDir(): string;
|
|
9
|
-
sessionDir(sessionId:
|
|
10
|
-
sessionEventsDir(sessionId:
|
|
11
|
-
sessionManifestPath(sessionId:
|
|
12
|
-
sessionLockPath(sessionId:
|
|
10
|
+
sessionDir(sessionId: SessionId): string;
|
|
11
|
+
sessionEventsDir(sessionId: SessionId): string;
|
|
12
|
+
sessionManifestPath(sessionId: SessionId): string;
|
|
13
|
+
sessionLockPath(sessionId: SessionId): string;
|
|
13
14
|
}
|