@untangle-code/storage-local 0.0.0-stage → 0.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.
Files changed (65) hide show
  1. package/LICENSE +661 -0
  2. package/NOTICE +90 -0
  3. package/README.md +226 -2
  4. package/THIRD_PARTY_LICENSES.md +24 -0
  5. package/dist/abort.d.ts +18 -0
  6. package/dist/abort.d.ts.map +1 -0
  7. package/dist/abort.js +14 -0
  8. package/dist/abort.js.map +1 -0
  9. package/dist/analysis-cache.d.ts +81 -0
  10. package/dist/analysis-cache.d.ts.map +1 -0
  11. package/dist/analysis-cache.js +322 -0
  12. package/dist/analysis-cache.js.map +1 -0
  13. package/dist/checkpoint-store.d.ts +22 -0
  14. package/dist/checkpoint-store.d.ts.map +1 -0
  15. package/dist/checkpoint-store.js +123 -0
  16. package/dist/checkpoint-store.js.map +1 -0
  17. package/dist/embedding-cache.d.ts +38 -0
  18. package/dist/embedding-cache.d.ts.map +1 -0
  19. package/dist/embedding-cache.js +229 -0
  20. package/dist/embedding-cache.js.map +1 -0
  21. package/dist/fs-errors.d.ts +4 -0
  22. package/dist/fs-errors.d.ts.map +1 -0
  23. package/dist/fs-errors.js +14 -0
  24. package/dist/fs-errors.js.map +1 -0
  25. package/dist/index.d.ts +15 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +23 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/layout.d.ts +50 -0
  30. package/dist/layout.d.ts.map +1 -0
  31. package/dist/layout.js +99 -0
  32. package/dist/layout.js.map +1 -0
  33. package/dist/local-file-system.d.ts +37 -0
  34. package/dist/local-file-system.d.ts.map +1 -0
  35. package/dist/local-file-system.js +193 -0
  36. package/dist/local-file-system.js.map +1 -0
  37. package/dist/lock-provider.d.ts +59 -0
  38. package/dist/lock-provider.d.ts.map +1 -0
  39. package/dist/lock-provider.js +318 -0
  40. package/dist/lock-provider.js.map +1 -0
  41. package/dist/real-time.d.ts +16 -0
  42. package/dist/real-time.d.ts.map +1 -0
  43. package/dist/real-time.js +19 -0
  44. package/dist/real-time.js.map +1 -0
  45. package/dist/search-journey-store.d.ts +34 -0
  46. package/dist/search-journey-store.d.ts.map +1 -0
  47. package/dist/search-journey-store.js +530 -0
  48. package/dist/search-journey-store.js.map +1 -0
  49. package/dist/storage.d.ts +42 -0
  50. package/dist/storage.d.ts.map +1 -0
  51. package/dist/storage.js +34 -0
  52. package/dist/storage.js.map +1 -0
  53. package/package.json +60 -3
  54. package/src/abort.ts +26 -0
  55. package/src/analysis-cache.ts +404 -0
  56. package/src/checkpoint-store.ts +155 -0
  57. package/src/embedding-cache.ts +282 -0
  58. package/src/fs-errors.ts +19 -0
  59. package/src/index.ts +30 -0
  60. package/src/layout.ts +149 -0
  61. package/src/local-file-system.ts +232 -0
  62. package/src/lock-provider.ts +381 -0
  63. package/src/real-time.ts +18 -0
  64. package/src/search-journey-store.ts +638 -0
  65. package/src/storage.ts +98 -0
@@ -0,0 +1,34 @@
1
+ import { type Clock, type FileSystemPort, type LockProvider, type PortCallOptions, type Random, type SearchJourneyStorePort, type SearchJourneyV1 } from "@untangle-code/domain";
2
+ export declare const MAX_SEARCH_JOURNEY_RECORD_BYTES: number;
3
+ export declare const MAX_SEARCH_JOURNEY_FILES = 10000;
4
+ export declare const SEARCH_JOURNEY_LOCK_LEASE_MS = 30000;
5
+ export declare const SEARCH_JOURNEY_LOCK_RENEW_INTERVAL_MS: number;
6
+ /**
7
+ * Hard aggregate read budget for one report/list snapshot. Four maximum-size
8
+ * sessions fit, so a three-session evidence cohort remains representable,
9
+ * while one call can never intentionally retain the full 10,000-file disk cap.
10
+ */
11
+ export declare const MAX_SEARCH_JOURNEY_LIST_BYTES: number;
12
+ export declare class LocalSearchJourneyStore implements SearchJourneyStorePort {
13
+ private readonly fs;
14
+ private readonly sessionsDir;
15
+ private readonly random;
16
+ private readonly locks;
17
+ private readonly clock;
18
+ private readonly fingerprintKeyPath;
19
+ constructor(fs: FileSystemPort, sessionsDir: string, random: Random, locks: LockProvider, clock: Pick<Clock, "nowEpochMs">);
20
+ private pathFor;
21
+ private read;
22
+ private parse;
23
+ /**
24
+ * Liefert den geheimen lokalen HMAC-Schluessel fuer Journey-Fingerprints.
25
+ * Er liegt absichtlich ausserhalb der exportierbaren Session-Datensaetze.
26
+ */
27
+ getOrCreateFingerprintKey(options?: PortCallOptions): Promise<Uint8Array>;
28
+ get(sessionId: string, options?: PortCallOptions): Promise<SearchJourneyV1 | null>;
29
+ put(session: SearchJourneyV1, options: PortCallOptions & {
30
+ expectedRevision: number | null;
31
+ }): Promise<void>;
32
+ list(workspaceId: string, options?: PortCallOptions): Promise<SearchJourneyV1[]>;
33
+ }
34
+ //# sourceMappingURL=search-journey-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-journey-store.d.ts","sourceRoot":"","sources":["../src/search-journey-store.ts"],"names":[],"mappings":"AAWA,OAAO,EAIL,KAAK,KAAK,EACV,KAAK,cAAc,EAEnB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,MAAM,EACX,KAAK,sBAAsB,EAC3B,KAAK,eAAe,EACrB,MAAM,uBAAuB,CAAC;AAK/B,eAAO,MAAM,+BAA+B,QAAmB,CAAC;AAChE,eAAO,MAAM,wBAAwB,QAAS,CAAC;AAC/C,eAAO,MAAM,4BAA4B,QAAS,CAAC;AACnD,eAAO,MAAM,qCAAqC,QAA+C,CAAC;AAClG;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,QAAoB,CAAC;AAiK/D,qBAAa,uBAAwB,YAAW,sBAAsB;IAIlE,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAPxB,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAS;gBAGzB,EAAE,EAAE,cAAc,EAClB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,YAAY,CAAC;IAKnD,OAAO,CAAC,OAAO;YAKD,IAAI;IAuClB,OAAO,CAAC,KAAK;IAiBb;;;OAGG;IACU,yBAAyB,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC;IAqEzE,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAKlF,GAAG,CACd,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,eAAe,GAAG;QAAE,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAC7D,OAAO,CAAC,IAAI,CAAC;IA4HH,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;CAgK9F"}
@@ -0,0 +1,530 @@
1
+ /**
2
+ * Lokale, atomare Search-Journey-Persistenz unter
3
+ * `.untangle/product-complexity/sessions/`.
4
+ *
5
+ * Ein CAS-Revisionstest laeuft zusammen mit dem Schreiben unter demselben
6
+ * pro-Session-Dateilock. So verlieren mehrere lokale Agenten keine Schritte,
7
+ * obwohl sie dieselbe Session in getrennten Prozessen bedienen.
8
+ */
9
+ import { Buffer } from "node:buffer";
10
+ import path from "node:path";
11
+ import { UntangleError, compareCodepoints, searchJourneyValidationIssue, } from "@untangle-code/domain";
12
+ import { assertNotAborted } from "./abort.js";
13
+ import { isNotFoundError } from "./fs-errors.js";
14
+ export const MAX_SEARCH_JOURNEY_RECORD_BYTES = 32 * 1024 * 1024;
15
+ export const MAX_SEARCH_JOURNEY_FILES = 10_000;
16
+ export const SEARCH_JOURNEY_LOCK_LEASE_MS = 30_000;
17
+ export const SEARCH_JOURNEY_LOCK_RENEW_INTERVAL_MS = Math.floor(SEARCH_JOURNEY_LOCK_LEASE_MS / 3);
18
+ /**
19
+ * Hard aggregate read budget for one report/list snapshot. Four maximum-size
20
+ * sessions fit, so a three-session evidence cohort remains representable,
21
+ * while one call can never intentionally retain the full 10,000-file disk cap.
22
+ */
23
+ export const MAX_SEARCH_JOURNEY_LIST_BYTES = 128 * 1024 * 1024;
24
+ const SESSION_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
25
+ const FINGERPRINT_KEY = /^[0-9a-f]{64}$/u;
26
+ /**
27
+ * Keeps one finite lock lease alive without overlapping renewal calls.
28
+ * Commit preparation pauses the heartbeat, waits for any in-flight renewal
29
+ * and keeps periodic scheduling stopped while the coordinated freshness gate
30
+ * below proves every required lock immediately before an atomic publish.
31
+ */
32
+ class RenewingLease {
33
+ handle;
34
+ options;
35
+ timer;
36
+ inFlight;
37
+ failure;
38
+ hasFailure = false;
39
+ committing = false;
40
+ closed = false;
41
+ constructor(handle, options) {
42
+ this.handle = handle;
43
+ this.options = options;
44
+ this.schedule();
45
+ }
46
+ get key() {
47
+ return this.handle.key;
48
+ }
49
+ schedule() {
50
+ if (this.closed || this.committing || this.hasFailure)
51
+ return;
52
+ this.timer = setTimeout(() => {
53
+ this.timer = undefined;
54
+ if (this.closed || this.committing || this.hasFailure)
55
+ return;
56
+ const renewal = this.handle
57
+ .renew(signalOptions(this.options))
58
+ .catch((error) => {
59
+ this.hasFailure = true;
60
+ this.failure = error;
61
+ })
62
+ .finally(() => {
63
+ if (this.inFlight === renewal)
64
+ this.inFlight = undefined;
65
+ this.schedule();
66
+ });
67
+ this.inFlight = renewal;
68
+ }, SEARCH_JOURNEY_LOCK_RENEW_INTERVAL_MS);
69
+ }
70
+ async prepareForCommit() {
71
+ this.committing = true;
72
+ if (this.timer !== undefined)
73
+ clearTimeout(this.timer);
74
+ this.timer = undefined;
75
+ await this.inFlight;
76
+ if (this.hasFailure)
77
+ throw this.failure;
78
+ }
79
+ async renewForCommit() {
80
+ await this.prepareForCommit();
81
+ const renewal = this.handle.renew(signalOptions(this.options)).catch((error) => {
82
+ this.hasFailure = true;
83
+ this.failure = error;
84
+ });
85
+ this.inFlight = renewal;
86
+ await renewal;
87
+ if (this.inFlight === renewal)
88
+ this.inFlight = undefined;
89
+ if (this.hasFailure)
90
+ throw this.failure;
91
+ }
92
+ leaseExpiresAtEpochMs() {
93
+ const expiresAt = Date.parse(this.handle.record.leaseExpiresAt);
94
+ if (!Number.isFinite(expiresAt)) {
95
+ throw new UntangleError("LOCK_HELD", `Lock "${this.handle.key}" has an invalid lease expiry`, {
96
+ retryable: true,
97
+ operation: "lock_renew",
98
+ context: { key: this.handle.key, leaseExpiresAt: this.handle.record.leaseExpiresAt },
99
+ });
100
+ }
101
+ return expiresAt;
102
+ }
103
+ async release() {
104
+ this.closed = true;
105
+ this.committing = true;
106
+ if (this.timer !== undefined)
107
+ clearTimeout(this.timer);
108
+ this.timer = undefined;
109
+ await this.inFlight;
110
+ await this.handle.release();
111
+ }
112
+ }
113
+ const MAX_COMMIT_LEASE_RENEWAL_ROUNDS = 8;
114
+ /**
115
+ * Stops every heartbeat and establishes one overlapping freshness window for
116
+ * all commit locks. A slow renewal may make an earlier lease stale, so only
117
+ * the stale subset is renewed again until every lease has at least one
118
+ * heartbeat interval left at the same instant. If the windows cannot
119
+ * converge, publication fails closed.
120
+ */
121
+ async function verifyLeasesForCommit(leases, clock) {
122
+ await Promise.all(leases.map((lease) => lease.prepareForCommit()));
123
+ let renew = [...leases];
124
+ for (let round = 1; round <= MAX_COMMIT_LEASE_RENEWAL_ROUNDS; round += 1) {
125
+ await Promise.all(renew.map((lease) => lease.renewForCommit()));
126
+ const freshnessBoundary = clock.nowEpochMs() + SEARCH_JOURNEY_LOCK_RENEW_INTERVAL_MS;
127
+ renew = leases.filter((lease) => lease.leaseExpiresAtEpochMs() < freshnessBoundary);
128
+ if (renew.length === 0)
129
+ return;
130
+ }
131
+ throw new UntangleError("LOCK_HELD", "search journey commit locks could not be proven simultaneously fresh", {
132
+ retryable: true,
133
+ operation: "search_journey_lock_commit",
134
+ context: {
135
+ keys: leases.map((lease) => lease.key),
136
+ minimumRemainingMs: SEARCH_JOURNEY_LOCK_RENEW_INTERVAL_MS,
137
+ },
138
+ });
139
+ }
140
+ function encode(text) {
141
+ return new TextEncoder().encode(text);
142
+ }
143
+ function hex(bytes) {
144
+ return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
145
+ }
146
+ function decodeHex(value) {
147
+ return Uint8Array.from(value.match(/.{2}/gu) ?? [], (byte) => Number.parseInt(byte, 16));
148
+ }
149
+ function signalOptions(options) {
150
+ return options?.signal === undefined ? undefined : { signal: options.signal };
151
+ }
152
+ function assertSessionId(sessionId) {
153
+ if (!SESSION_ID.test(sessionId)) {
154
+ throw new UntangleError("SEARCH_SESSION_NOT_FOUND", "invalid search journey session id", {
155
+ operation: "search_journey_store",
156
+ context: { sessionId },
157
+ });
158
+ }
159
+ }
160
+ export class LocalSearchJourneyStore {
161
+ fs;
162
+ sessionsDir;
163
+ random;
164
+ locks;
165
+ clock;
166
+ fingerprintKeyPath;
167
+ constructor(fs, sessionsDir, random, locks, clock) {
168
+ this.fs = fs;
169
+ this.sessionsDir = sessionsDir;
170
+ this.random = random;
171
+ this.locks = locks;
172
+ this.clock = clock;
173
+ this.fingerprintKeyPath = path.join(path.dirname(sessionsDir), "fingerprint.key");
174
+ }
175
+ pathFor(sessionId) {
176
+ assertSessionId(sessionId);
177
+ return path.join(this.sessionsDir, `${sessionId}.json`);
178
+ }
179
+ async read(sessionId, options) {
180
+ const recordPath = this.pathFor(sessionId);
181
+ const recordStat = await this.fs.stat(recordPath, options);
182
+ if (recordStat === null)
183
+ return null;
184
+ if (recordStat.kind !== "file" || recordStat.sizeBytes > MAX_SEARCH_JOURNEY_RECORD_BYTES) {
185
+ throw new UntangleError("INDEX_INCOMPLETE", `search journey "${sessionId}" is corrupted`, {
186
+ operation: "search_journey_read",
187
+ context: {
188
+ sessionId,
189
+ kind: recordStat.kind,
190
+ sizeBytes: recordStat.sizeBytes,
191
+ maximumBytes: MAX_SEARCH_JOURNEY_RECORD_BYTES,
192
+ },
193
+ });
194
+ }
195
+ let text;
196
+ try {
197
+ text = await this.fs.readTextFile(recordPath, options);
198
+ }
199
+ catch (error) {
200
+ if (isNotFoundError(error))
201
+ return null;
202
+ throw error;
203
+ }
204
+ const actualBytes = Buffer.byteLength(text, "utf8");
205
+ if (actualBytes > MAX_SEARCH_JOURNEY_RECORD_BYTES) {
206
+ throw new UntangleError("INDEX_INCOMPLETE", `search journey "${sessionId}" is corrupted`, {
207
+ operation: "search_journey_read",
208
+ context: {
209
+ sessionId,
210
+ actualBytes,
211
+ maximumBytes: MAX_SEARCH_JOURNEY_RECORD_BYTES,
212
+ },
213
+ });
214
+ }
215
+ return this.parse(sessionId, text, "search_journey_read");
216
+ }
217
+ parse(sessionId, text, operation) {
218
+ try {
219
+ const parsed = JSON.parse(text);
220
+ const issue = searchJourneyValidationIssue(parsed);
221
+ if (issue !== null)
222
+ throw new Error(issue);
223
+ const validated = parsed;
224
+ if (validated.sessionId !== sessionId)
225
+ throw new Error("session id mismatch");
226
+ return validated;
227
+ }
228
+ catch (error) {
229
+ throw new UntangleError("INDEX_INCOMPLETE", `search journey "${sessionId}" is corrupted`, {
230
+ operation,
231
+ context: { sessionId },
232
+ cause: error,
233
+ });
234
+ }
235
+ }
236
+ /**
237
+ * Liefert den geheimen lokalen HMAC-Schluessel fuer Journey-Fingerprints.
238
+ * Er liegt absichtlich ausserhalb der exportierbaren Session-Datensaetze.
239
+ */
240
+ async getOrCreateFingerprintKey(options) {
241
+ assertNotAborted(options, "search_journey_fingerprint_key");
242
+ await this.fs.mkdir(path.dirname(this.fingerprintKeyPath), {
243
+ recursive: true,
244
+ ...signalOptions(options),
245
+ });
246
+ const lock = await this.locks.acquire("search-journey:fingerprint-key", {
247
+ ...signalOptions(options),
248
+ leaseMs: SEARCH_JOURNEY_LOCK_LEASE_MS,
249
+ waitMs: 5_000,
250
+ });
251
+ const lease = new RenewingLease(lock, options);
252
+ try {
253
+ try {
254
+ const persisted = (await this.fs.readTextFile(this.fingerprintKeyPath, options)).trim();
255
+ if (!FINGERPRINT_KEY.test(persisted))
256
+ throw new Error("invalid fingerprint key");
257
+ return decodeHex(persisted);
258
+ }
259
+ catch (error) {
260
+ if (!isNotFoundError(error)) {
261
+ throw new UntangleError("INDEX_INCOMPLETE", "search journey fingerprint key is corrupted", {
262
+ operation: "search_journey_fingerprint_key",
263
+ cause: error,
264
+ });
265
+ }
266
+ }
267
+ let existingRecordCount = 0;
268
+ try {
269
+ existingRecordCount = (await this.fs.readDir(this.sessionsDir, options)).filter((entry) => entry.kind === "file" && entry.name.endsWith(".json")).length;
270
+ }
271
+ catch (error) {
272
+ if (!isNotFoundError(error))
273
+ throw error;
274
+ }
275
+ if (existingRecordCount > 0) {
276
+ throw new UntangleError("INDEX_INCOMPLETE", "search journey fingerprint key is missing while session records exist", {
277
+ operation: "search_journey_fingerprint_key",
278
+ context: { existingRecordCount },
279
+ });
280
+ }
281
+ const key = this.random.bytes(32);
282
+ const tempPath = `${this.fingerprintKeyPath}.${this.random.uuid()}.tmp`;
283
+ try {
284
+ await this.fs.writeFile(tempPath, encode(hex(key)), {
285
+ ...signalOptions(options),
286
+ mode: 0o600,
287
+ });
288
+ await verifyLeasesForCommit([lease], this.clock);
289
+ await this.fs.rename(tempPath, this.fingerprintKeyPath, options);
290
+ return key.slice();
291
+ }
292
+ finally {
293
+ // Cleanup deliberately ignores an aborted caller signal: otherwise
294
+ // cancellation could strand unbounded temp bytes outside record limits.
295
+ await this.fs.remove(tempPath).catch(() => undefined);
296
+ }
297
+ }
298
+ finally {
299
+ await lease.release();
300
+ }
301
+ }
302
+ async get(sessionId, options) {
303
+ assertNotAborted(options, "search_journey_get");
304
+ return await this.read(sessionId, options);
305
+ }
306
+ async put(session, options) {
307
+ assertNotAborted(options, "search_journey_put");
308
+ if (options?.expectedRevision === undefined) {
309
+ throw new UntangleError("SEARCH_SESSION_INVALID_STATE", "search journey writes require an expected revision", { operation: "search_journey_put", context: { sessionId: session.sessionId } });
310
+ }
311
+ assertSessionId(session.sessionId);
312
+ const validationIssue = searchJourneyValidationIssue(session);
313
+ if (validationIssue !== null) {
314
+ throw new UntangleError("SEARCH_SESSION_INVALID_STATE", `search journey cannot be persisted: ${validationIssue}`, {
315
+ operation: "search_journey_put",
316
+ context: { sessionId: session.sessionId, validationIssue },
317
+ });
318
+ }
319
+ const expected = options.expectedRevision;
320
+ const requiredRevision = expected === null ? 0 : expected + 1;
321
+ if (session.revision !== requiredRevision) {
322
+ throw new UntangleError("SEARCH_SESSION_INVALID_STATE", `search journey revision ${String(session.revision)} does not follow expected revision ${String(expected)}`, {
323
+ operation: "search_journey_put",
324
+ context: {
325
+ sessionId: session.sessionId,
326
+ expectedRevision: expected,
327
+ suppliedRevision: session.revision,
328
+ requiredRevision,
329
+ },
330
+ });
331
+ }
332
+ const body = JSON.stringify(session);
333
+ const bytes = encode(body);
334
+ if (bytes.byteLength > MAX_SEARCH_JOURNEY_RECORD_BYTES) {
335
+ throw new UntangleError("SEARCH_SESSION_INVALID_STATE", `search journey exceeds the ${String(MAX_SEARCH_JOURNEY_RECORD_BYTES)} byte record limit`, {
336
+ operation: "search_journey_put",
337
+ context: { sessionId: session.sessionId, byteLength: bytes.byteLength },
338
+ });
339
+ }
340
+ await this.fs.mkdir(this.sessionsDir, { recursive: true, ...signalOptions(options) });
341
+ const creationLock = expected === null
342
+ ? await this.locks.acquire("search-journey:create", {
343
+ ...signalOptions(options),
344
+ leaseMs: SEARCH_JOURNEY_LOCK_LEASE_MS,
345
+ waitMs: 5_000,
346
+ })
347
+ : null;
348
+ const creationLease = creationLock === null ? null : new RenewingLease(creationLock, options);
349
+ try {
350
+ const lock = await this.locks.acquire(`search-journey:${session.sessionId}`, {
351
+ ...signalOptions(options),
352
+ leaseMs: SEARCH_JOURNEY_LOCK_LEASE_MS,
353
+ waitMs: 5_000,
354
+ });
355
+ const lease = new RenewingLease(lock, options);
356
+ try {
357
+ const current = await this.read(session.sessionId, options);
358
+ const conflict = expected === null ? current !== null : current?.revision !== expected;
359
+ if (conflict) {
360
+ throw new UntangleError("SEARCH_SESSION_CONFLICT", `search journey "${session.sessionId}" changed concurrently`, {
361
+ retryable: true,
362
+ operation: "search_journey_put",
363
+ context: {
364
+ sessionId: session.sessionId,
365
+ expectedRevision: expected,
366
+ actualRevision: current?.revision ?? null,
367
+ },
368
+ });
369
+ }
370
+ if (expected === null) {
371
+ const recordCount = (await this.fs.readDir(this.sessionsDir, options)).filter((entry) => entry.kind === "file" && entry.name.endsWith(".json")).length;
372
+ if (recordCount >= MAX_SEARCH_JOURNEY_FILES) {
373
+ throw new UntangleError("SEARCH_SESSION_INVALID_STATE", `search journey store reached its limit of ${String(MAX_SEARCH_JOURNEY_FILES)} records`, {
374
+ operation: "search_journey_put",
375
+ context: { recordCount },
376
+ });
377
+ }
378
+ }
379
+ const finalPath = this.pathFor(session.sessionId);
380
+ const tempPath = `${finalPath}.${this.random.uuid()}.tmp`;
381
+ try {
382
+ await this.fs.writeFile(tempPath, bytes, {
383
+ ...signalOptions(options),
384
+ mode: 0o600,
385
+ });
386
+ await verifyLeasesForCommit(creationLease === null ? [lease] : [creationLease, lease], this.clock);
387
+ await this.fs.rename(tempPath, finalPath, options);
388
+ }
389
+ finally {
390
+ await this.fs.remove(tempPath).catch(() => undefined);
391
+ }
392
+ }
393
+ finally {
394
+ await lease.release();
395
+ }
396
+ }
397
+ finally {
398
+ await creationLease?.release();
399
+ }
400
+ }
401
+ async list(workspaceId, options) {
402
+ assertNotAborted(options, "search_journey_list");
403
+ try {
404
+ const stat = await this.fs.stat(this.sessionsDir, options);
405
+ if (stat === null)
406
+ return [];
407
+ const entries = (await this.fs.readDir(this.sessionsDir, options))
408
+ .filter((entry) => entry.kind === "file" && entry.name.endsWith(".json"))
409
+ .sort((left, right) => compareCodepoints(left.name, right.name));
410
+ if (entries.length > MAX_SEARCH_JOURNEY_FILES) {
411
+ throw new UntangleError("SEARCH_SESSION_INVALID_STATE", `search journey store contains ${String(entries.length)} records; limit is ${String(MAX_SEARCH_JOURNEY_FILES)}`, { operation: "search_journey_list", context: { recordCount: entries.length } });
412
+ }
413
+ const manifest = [];
414
+ let aggregateBytes = 0;
415
+ for (const entry of entries) {
416
+ assertNotAborted(options, "search_journey_list_budget");
417
+ const sessionId = entry.name.slice(0, -".json".length);
418
+ const recordPath = this.pathFor(sessionId);
419
+ const entryStat = await this.fs.stat(recordPath, options);
420
+ if (entryStat === null) {
421
+ throw new UntangleError("SEARCH_SESSION_CONFLICT", `search journey record "${entry.name}" disappeared during snapshot preflight`, {
422
+ operation: "search_journey_list",
423
+ retryable: true,
424
+ context: { fileName: entry.name, phase: "preflight" },
425
+ });
426
+ }
427
+ if (entryStat.kind !== "file" || entryStat.sizeBytes > MAX_SEARCH_JOURNEY_RECORD_BYTES) {
428
+ throw new UntangleError("INDEX_INCOMPLETE", `search journey record "${entry.name}" is corrupted`, {
429
+ operation: "search_journey_list",
430
+ context: {
431
+ fileName: entry.name,
432
+ kind: entryStat.kind,
433
+ sizeBytes: entryStat.sizeBytes,
434
+ maximumRecordBytes: MAX_SEARCH_JOURNEY_RECORD_BYTES,
435
+ },
436
+ });
437
+ }
438
+ manifest.push({
439
+ fileName: entry.name,
440
+ path: recordPath,
441
+ sessionId,
442
+ sizeBytes: entryStat.sizeBytes,
443
+ });
444
+ aggregateBytes += entryStat.sizeBytes;
445
+ if (aggregateBytes > MAX_SEARCH_JOURNEY_LIST_BYTES) {
446
+ throw new UntangleError("SEARCH_SESSION_INVALID_STATE", `search journey snapshot exceeds the ${String(MAX_SEARCH_JOURNEY_LIST_BYTES)} byte aggregate read limit`, {
447
+ operation: "search_journey_list",
448
+ context: {
449
+ recordCount: entries.length,
450
+ aggregateBytes,
451
+ maximumBytes: MAX_SEARCH_JOURNEY_LIST_BYTES,
452
+ },
453
+ });
454
+ }
455
+ }
456
+ const sessions = [];
457
+ let actualAggregateBytes = 0;
458
+ for (const entry of manifest) {
459
+ assertNotAborted(options, "search_journey_list_read");
460
+ let text;
461
+ try {
462
+ text = await this.fs.readTextFile(entry.path, options);
463
+ }
464
+ catch (error) {
465
+ if (isNotFoundError(error)) {
466
+ throw new UntangleError("SEARCH_SESSION_CONFLICT", `search journey record "${entry.fileName}" disappeared during snapshot read`, {
467
+ operation: "search_journey_list",
468
+ retryable: true,
469
+ context: { fileName: entry.fileName, phase: "read" },
470
+ cause: error,
471
+ });
472
+ }
473
+ throw error;
474
+ }
475
+ const actualBytes = Buffer.byteLength(text, "utf8");
476
+ if (actualBytes > MAX_SEARCH_JOURNEY_RECORD_BYTES) {
477
+ throw new UntangleError("INDEX_INCOMPLETE", `search journey record "${entry.fileName}" exceeds its byte limit during snapshot read`, {
478
+ operation: "search_journey_list",
479
+ context: {
480
+ fileName: entry.fileName,
481
+ actualBytes,
482
+ maximumRecordBytes: MAX_SEARCH_JOURNEY_RECORD_BYTES,
483
+ },
484
+ });
485
+ }
486
+ actualAggregateBytes += actualBytes;
487
+ if (actualAggregateBytes > MAX_SEARCH_JOURNEY_LIST_BYTES) {
488
+ throw new UntangleError("SEARCH_SESSION_INVALID_STATE", `search journey snapshot exceeds the ${String(MAX_SEARCH_JOURNEY_LIST_BYTES)} byte aggregate read limit`, {
489
+ operation: "search_journey_list",
490
+ context: {
491
+ recordCount: manifest.length,
492
+ aggregateBytes: actualAggregateBytes,
493
+ maximumBytes: MAX_SEARCH_JOURNEY_LIST_BYTES,
494
+ phase: "read",
495
+ },
496
+ });
497
+ }
498
+ const postReadStat = await this.fs.stat(entry.path, options);
499
+ if (postReadStat === null ||
500
+ postReadStat.kind !== "file" ||
501
+ postReadStat.sizeBytes !== entry.sizeBytes ||
502
+ actualBytes !== entry.sizeBytes) {
503
+ throw new UntangleError("SEARCH_SESSION_CONFLICT", `search journey record "${entry.fileName}" changed during snapshot read`, {
504
+ operation: "search_journey_list",
505
+ retryable: true,
506
+ context: {
507
+ fileName: entry.fileName,
508
+ phase: "post-read",
509
+ expectedBytes: entry.sizeBytes,
510
+ actualBytes,
511
+ observedBytes: postReadStat?.sizeBytes ?? null,
512
+ observedKind: postReadStat?.kind ?? "missing",
513
+ },
514
+ });
515
+ }
516
+ const session = this.parse(entry.sessionId, text, "search_journey_list");
517
+ if (session.workspaceId === workspaceId)
518
+ sessions.push(session);
519
+ }
520
+ return sessions.sort((left, right) => compareCodepoints(left.createdAt, right.createdAt) ||
521
+ compareCodepoints(left.sessionId, right.sessionId));
522
+ }
523
+ catch (error) {
524
+ if (isNotFoundError(error))
525
+ return [];
526
+ throw error;
527
+ }
528
+ }
529
+ }
530
+ //# sourceMappingURL=search-journey-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-journey-store.js","sourceRoot":"","sources":["../src/search-journey-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Convenience wiring: one call that builds the `.untangle/` layout, ensures
3
+ * every directory exists, and hands back the adapters this package provides
4
+ * — a `FileSystemPort` sandboxed to that state root, the embedding cache,
5
+ * the three content-addressed analysis caches (WP-100), the checkpoint mirror
6
+ * and the file-based lock provider, all sharing the same underlying
7
+ * `FileSystemPort`.
8
+ */
9
+ import type { Clock, FileSystemPort, LockProvider, PortCallOptions, Random } from "@untangle-code/domain";
10
+ import { LocalAnalysisCache } from "./analysis-cache.js";
11
+ import { LocalCheckpointStore } from "./checkpoint-store.js";
12
+ import { LocalEmbeddingCache } from "./embedding-cache.js";
13
+ import { type StateDirLayout } from "./layout.js";
14
+ import { LocalSearchJourneyStore } from "./search-journey-store.js";
15
+ export interface LocalStorageOptions {
16
+ clock: Clock;
17
+ random: Random;
18
+ /** Overrides the persistent embedding cache's size limit (bytes). */
19
+ embeddingCacheMaxBytes?: number;
20
+ /** Overrides the size limit (bytes) of EACH of the three analysis caches (WP-100). */
21
+ analysisCacheMaxBytes?: number;
22
+ /** Overrides `os.hostname()` for lock records — mainly for tests. */
23
+ host?: string;
24
+ }
25
+ export interface LocalStorage {
26
+ layout: StateDirLayout;
27
+ fs: FileSystemPort;
28
+ embeddingCache: LocalEmbeddingCache;
29
+ /** Parse-, Chunk- und Metrik-Cache, inhaltsadressiert (WP-100). */
30
+ analysisCache: LocalAnalysisCache;
31
+ checkpoints: LocalCheckpointStore;
32
+ locks: LockProvider;
33
+ searchJourneys: LocalSearchJourneyStore;
34
+ }
35
+ /**
36
+ * Builds the `.untangle/` layout under `stateRoot` (creating every directory
37
+ * if needed) and returns the wired-up local storage adapters. `stateRoot`
38
+ * becomes the ONLY root the returned `FileSystemPort` will resolve paths
39
+ * within (rule 3: "kein Schreiben ausserhalb des Zustandsverzeichnisses").
40
+ */
41
+ export declare function openLocalStorage(stateRoot: string, options: LocalStorageOptions, callOptions?: PortCallOptions): Promise<LocalStorage>;
42
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EACV,KAAK,EACL,cAAc,EACd,YAAY,EACZ,eAAe,EACf,MAAM,EACP,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAEL,kBAAkB,EAEnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAqC,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC9F,OAAO,EAA6C,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAG7F,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAEpE,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,KAAK,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,sFAAsF;IACtF,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,cAAc,CAAC;IACvB,EAAE,EAAE,cAAc,CAAC;IACnB,cAAc,EAAE,mBAAmB,CAAC;IACpC,mEAAmE;IACnE,aAAa,EAAE,kBAAkB,CAAC;IAClC,WAAW,EAAE,oBAAoB,CAAC;IAClC,KAAK,EAAE,YAAY,CAAC;IACpB,cAAc,EAAE,uBAAuB,CAAC;CACzC;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,mBAAmB,EAC5B,WAAW,CAAC,EAAE,eAAe,GAC5B,OAAO,CAAC,YAAY,CAAC,CAqCvB"}