@hraness/sponge 0.1.2 → 0.2.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.
Files changed (174) hide show
  1. package/README.md +164 -17
  2. package/bin/sponge.js +9 -2
  3. package/dist/contracts/index.d.ts +164 -0
  4. package/dist/contracts/index.js +6 -0
  5. package/dist/contracts/validate.d.ts +14 -0
  6. package/dist/contracts/validate.js +187 -0
  7. package/dist/migrations/001.d.ts +3 -0
  8. package/dist/migrations/001.js +33 -0
  9. package/dist/migrations/002.d.ts +3 -0
  10. package/dist/migrations/002.js +6 -0
  11. package/dist/migrations/003.d.ts +3 -0
  12. package/dist/migrations/003.js +10 -0
  13. package/dist/migrations/004.d.ts +3 -0
  14. package/dist/migrations/004.js +9 -0
  15. package/dist/src/acquisition/capture.d.ts +29 -0
  16. package/dist/src/acquisition/capture.js +160 -0
  17. package/dist/src/acquisition/cleanup.d.ts +6 -0
  18. package/dist/src/acquisition/cleanup.js +20 -0
  19. package/dist/src/acquisition/errors.d.ts +3 -0
  20. package/dist/src/acquisition/errors.js +20 -0
  21. package/dist/src/acquisition/files.d.ts +4 -0
  22. package/dist/src/acquisition/files.js +49 -0
  23. package/dist/src/acquisition/index.d.ts +6 -0
  24. package/dist/src/acquisition/index.js +4 -0
  25. package/dist/src/acquisition/lock.d.ts +1 -0
  26. package/dist/src/acquisition/lock.js +2 -0
  27. package/dist/src/acquisition/normalize.d.ts +11 -0
  28. package/dist/src/acquisition/normalize.js +62 -0
  29. package/dist/src/acquisition/pins.d.ts +3 -0
  30. package/dist/src/acquisition/pins.js +9 -0
  31. package/dist/src/acquisition/process.d.ts +16 -0
  32. package/dist/src/acquisition/process.js +63 -0
  33. package/dist/src/acquisition/runtime.d.ts +54 -0
  34. package/dist/src/acquisition/runtime.js +218 -0
  35. package/dist/src/acquisition/verify-helper.d.ts +1 -0
  36. package/dist/src/acquisition/verify-helper.js +19 -0
  37. package/dist/src/app/article.d.ts +23 -0
  38. package/dist/src/app/article.js +82 -0
  39. package/dist/src/app/bundle-files.d.ts +8 -0
  40. package/dist/src/app/bundle-files.js +66 -0
  41. package/dist/src/app/markdown.d.ts +6 -0
  42. package/dist/src/app/markdown.js +90 -0
  43. package/dist/src/app/source.d.ts +15 -0
  44. package/dist/src/app/source.js +40 -0
  45. package/dist/src/cli/arguments.d.ts +9 -0
  46. package/dist/src/cli/arguments.js +106 -0
  47. package/dist/src/cli/config.d.ts +8 -0
  48. package/dist/src/cli/config.js +45 -0
  49. package/dist/src/cli/import.d.ts +4 -0
  50. package/dist/src/cli/import.js +3 -0
  51. package/dist/src/cli/indexing.d.ts +7 -0
  52. package/dist/src/cli/indexing.js +21 -0
  53. package/dist/src/cli/main.d.ts +1 -0
  54. package/dist/src/cli/main.js +333 -0
  55. package/dist/src/cli/portability.d.ts +9 -0
  56. package/dist/src/cli/portability.js +39 -0
  57. package/dist/src/cli/queue.d.ts +2 -0
  58. package/dist/src/cli/queue.js +23 -0
  59. package/dist/src/cli/terminal.d.ts +2 -0
  60. package/dist/src/cli/terminal.js +4 -0
  61. package/dist/src/cli/worker.d.ts +16 -0
  62. package/dist/src/cli/worker.js +62 -0
  63. package/dist/src/importers/apply.d.ts +29 -0
  64. package/dist/src/importers/apply.js +85 -0
  65. package/dist/src/importers/custody.d.ts +6 -0
  66. package/dist/src/importers/custody.js +35 -0
  67. package/dist/src/importers/inspect.d.ts +21 -0
  68. package/dist/src/importers/inspect.js +97 -0
  69. package/dist/src/importers/manifest.d.ts +22 -0
  70. package/dist/src/importers/manifest.js +43 -0
  71. package/dist/src/importers/verify-helper.d.ts +1 -0
  72. package/dist/src/importers/verify-helper.js +27 -0
  73. package/dist/src/indexing/image.d.ts +10 -0
  74. package/dist/src/indexing/image.js +34 -0
  75. package/dist/src/indexing/index.d.ts +53 -0
  76. package/dist/src/indexing/index.js +123 -0
  77. package/dist/src/indexing/jobs.d.ts +14 -0
  78. package/dist/src/indexing/jobs.js +49 -0
  79. package/dist/src/indexing/runner.d.ts +23 -0
  80. package/dist/src/indexing/runner.js +114 -0
  81. package/dist/src/inference/asr/bridge.d.ts +1 -0
  82. package/dist/src/inference/asr/bridge.js +16 -0
  83. package/dist/src/inference/asr/protocol.d.ts +23 -0
  84. package/dist/src/inference/asr/protocol.js +60 -0
  85. package/dist/src/inference/asr/runtime.d.ts +29 -0
  86. package/dist/src/inference/asr/runtime.js +103 -0
  87. package/dist/src/inference/asr/windows.d.ts +9 -0
  88. package/dist/src/inference/asr/windows.js +41 -0
  89. package/dist/src/inference/embedding/index.d.ts +47 -0
  90. package/dist/src/inference/embedding/index.js +122 -0
  91. package/dist/src/media/capture-helper.d.ts +1 -0
  92. package/dist/src/media/capture-helper.js +16 -0
  93. package/dist/src/media/capture.d.ts +32 -0
  94. package/dist/src/media/capture.js +193 -0
  95. package/dist/src/media/handler.d.ts +22 -0
  96. package/dist/src/media/handler.js +82 -0
  97. package/dist/src/media/transcribe.d.ts +29 -0
  98. package/dist/src/media/transcribe.js +93 -0
  99. package/dist/src/metadata/article.d.ts +5 -0
  100. package/dist/src/metadata/article.js +51 -0
  101. package/dist/src/models/artifacts.d.ts +36 -0
  102. package/dist/src/models/artifacts.js +274 -0
  103. package/dist/src/models/catalog.d.ts +35 -0
  104. package/dist/src/models/catalog.js +71 -0
  105. package/dist/src/models/download.d.ts +9 -0
  106. package/dist/src/models/download.js +147 -0
  107. package/dist/src/models/runtime.d.ts +24 -0
  108. package/dist/src/models/runtime.js +37 -0
  109. package/dist/src/pdf/capture-helper.d.ts +1 -0
  110. package/dist/src/pdf/capture-helper.js +12 -0
  111. package/dist/src/pdf/capture.d.ts +29 -0
  112. package/dist/src/pdf/capture.js +156 -0
  113. package/dist/src/pdf/errors.d.ts +2 -0
  114. package/dist/src/pdf/errors.js +13 -0
  115. package/dist/src/pdf/handler.d.ts +24 -0
  116. package/dist/src/pdf/handler.js +84 -0
  117. package/dist/src/pdf/index.d.ts +4 -0
  118. package/dist/src/pdf/index.js +4 -0
  119. package/dist/src/pdf/input.d.ts +2 -0
  120. package/dist/src/pdf/input.js +46 -0
  121. package/dist/src/pdf/normalize.d.ts +10 -0
  122. package/dist/src/pdf/normalize.js +64 -0
  123. package/dist/src/pdf/source-identity.d.ts +4 -0
  124. package/dist/src/pdf/source-identity.js +12 -0
  125. package/dist/src/pdf/source.d.ts +6 -0
  126. package/dist/src/pdf/source.js +22 -0
  127. package/dist/src/pdf/verify-helper.d.ts +1 -0
  128. package/dist/src/pdf/verify-helper.js +17 -0
  129. package/dist/src/portability/backup.d.ts +23 -0
  130. package/dist/src/portability/backup.js +138 -0
  131. package/dist/src/portability/database.d.ts +14 -0
  132. package/dist/src/portability/database.js +78 -0
  133. package/dist/src/portability/export.d.ts +8 -0
  134. package/dist/src/portability/export.js +36 -0
  135. package/dist/src/portability/files.d.ts +33 -0
  136. package/dist/src/portability/files.js +78 -0
  137. package/dist/src/portability/gc.d.ts +21 -0
  138. package/dist/src/portability/gc.js +66 -0
  139. package/dist/src/search/extension.d.ts +3 -0
  140. package/dist/src/search/extension.js +17 -0
  141. package/dist/src/search/hybrid.d.ts +39 -0
  142. package/dist/src/search/hybrid.js +118 -0
  143. package/dist/src/search/query.d.ts +12 -0
  144. package/dist/src/search/query.js +47 -0
  145. package/dist/src/search/vector.d.ts +21 -0
  146. package/dist/src/search/vector.js +21 -0
  147. package/dist/src/service/launch-agent.d.ts +47 -0
  148. package/dist/src/service/launch-agent.js +179 -0
  149. package/dist/src/service/lifetime.d.ts +7 -0
  150. package/dist/src/service/lifetime.js +73 -0
  151. package/dist/src/service/loop.d.ts +21 -0
  152. package/dist/src/service/loop.js +94 -0
  153. package/dist/src/store/files.d.ts +12 -0
  154. package/dist/src/store/files.js +101 -0
  155. package/dist/src/store/index.d.ts +118 -0
  156. package/dist/src/store/index.js +727 -0
  157. package/dist/src/store/types.d.ts +90 -0
  158. package/dist/src/store/types.js +8 -0
  159. package/dist/src/worker/basic.d.ts +10 -0
  160. package/dist/src/worker/basic.js +27 -0
  161. package/dist/src/worker/custody.d.ts +13 -0
  162. package/dist/src/worker/custody.js +185 -0
  163. package/dist/src/worker/engine.d.ts +28 -0
  164. package/dist/src/worker/engine.js +78 -0
  165. package/dist/src/worker/identity.d.ts +7 -0
  166. package/dist/src/worker/identity.js +27 -0
  167. package/dist/src/worker/journal.d.ts +5 -0
  168. package/dist/src/worker/journal.js +30 -0
  169. package/dist/src/worker/supervisor-child.d.ts +1 -0
  170. package/dist/src/worker/supervisor-child.js +33 -0
  171. package/dist/src/worker/supervisor.d.ts +3 -0
  172. package/dist/src/worker/supervisor.js +47 -0
  173. package/native/runtime-manifest.json +40 -0
  174. package/package.json +31 -5
@@ -0,0 +1,94 @@
1
+ import { constants, openSync, closeSync, fstatSync, writeSync, renameSync, lstatSync, existsSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { safeDirectory, regularFile, syncDirectory } from '../store/files.js';
4
+ import { writePrivateExclusive } from '../portability/files.js';
5
+ import { processIdentity } from '../worker/identity.js';
6
+ import { randomUUID } from 'node:crypto';
7
+ import { acquireServiceLifetime } from './lifetime.js';
8
+ /** Fixed event vocabulary; source URLs, credentials, content and raw errors never enter logs. */
9
+ export function serviceLog(root, event) {
10
+ const directory = safeDirectory(join(root, 'runtime', 'service'), true), path = join(directory, 'worker.log');
11
+ if (existsSync(path)) {
12
+ regularFile(path);
13
+ if (lstatSync(path).size >= 1024 * 1024) {
14
+ for (let i = 3; i >= 1; i--) {
15
+ const old = i === 1 ? path : path + '.' + (i - 1), next = path + '.' + i;
16
+ if (existsSync(next))
17
+ regularFile(next);
18
+ if (existsSync(old)) {
19
+ regularFile(old);
20
+ renameSync(old, next);
21
+ }
22
+ }
23
+ }
24
+ }
25
+ const fd = openSync(path, constants.O_WRONLY | constants.O_CREAT | constants.O_APPEND | constants.O_NOFOLLOW, 0o600);
26
+ try {
27
+ const stat = fstatSync(fd);
28
+ if (!stat.isFile() || stat.nlink !== 1)
29
+ throw Error('integrity');
30
+ writeSync(fd, JSON.stringify({ at: new Date().toISOString(), event }) + '\n');
31
+ }
32
+ finally {
33
+ closeSync(fd);
34
+ }
35
+ }
36
+ export function idleWait(ms, signal) { return new Promise(resolve => { if (signal.aborted) {
37
+ resolve();
38
+ return;
39
+ } const done = () => { clearTimeout(timer); signal.removeEventListener('abort', done); resolve(); }; const timer = setTimeout(done, ms); signal.addEventListener('abort', done, { once: true }); }); }
40
+ /** Uses the existing drain engine; it owns locking, cancellation and descendant collection. */
41
+ export async function runWorkerService(store, options) {
42
+ const idleMs = options.idleMs ?? 15000;
43
+ if (!Number.isSafeInteger(idleMs) || idleMs < 1000 || idleMs > 60000 || !/^[a-f0-9-]{36}$/u.test(options.installationId))
44
+ throw Error('invalid-input');
45
+ const root = safeDirectory(join(store.root, 'runtime', 'service'), true), identity = await (options.identity ?? (() => processIdentity(process.pid)))();
46
+ if (!identity)
47
+ throw Error('unavailable');
48
+ const lifetime = await acquireServiceLifetime(root, options.installationId, identity);
49
+ const runId = randomUUID(), runPath = join(root, 'run.json');
50
+ const record = (state) => { const temp = join(root, `run-${runId}.tmp`); writePrivateExclusive(temp, JSON.stringify({ schemaVersion: 1, installationId: options.installationId, runId, identity, state }) + '\n'); if (existsSync(runPath))
51
+ regularFile(runPath); renameSync(temp, runPath); syncDirectory(root); };
52
+ const log = options.log ?? (event => serviceLog(store.root, event));
53
+ let cycles = 0, cleanup = 'settled';
54
+ try {
55
+ record('running');
56
+ log('started');
57
+ while (!options.signal.aborted) {
58
+ try {
59
+ const results = await options.drain(options.signal);
60
+ cycles++;
61
+ log(results.length ? 'drained' : 'idle');
62
+ }
63
+ catch (error) {
64
+ const code = error.code;
65
+ if (code === 'owner-busy')
66
+ log('busy');
67
+ else {
68
+ log('repair-required');
69
+ if (code === 'cleanup-required')
70
+ cleanup = 'pending';
71
+ break;
72
+ }
73
+ }
74
+ await options.onIdle?.();
75
+ if (options.signal.aborted)
76
+ break;
77
+ await (options.wait ?? idleWait)(idleMs, options.signal);
78
+ }
79
+ if (store.pendingCleanupCount() > 0)
80
+ cleanup = 'pending';
81
+ return { cycles, cleanup };
82
+ }
83
+ finally {
84
+ try {
85
+ if (store.pendingCleanupCount() > 0)
86
+ cleanup = 'pending';
87
+ record(cleanup === 'settled' ? 'stopped' : 'cleanup-required');
88
+ log('stopped');
89
+ }
90
+ finally {
91
+ await lifetime.release();
92
+ }
93
+ }
94
+ }
@@ -0,0 +1,12 @@
1
+ export declare const digest: (value: string | Uint8Array) => string;
2
+ export declare function hash(value: string): void;
3
+ export declare function text(value: string, max?: number): void;
4
+ export declare function integer(value: number, maximum?: number): void;
5
+ export declare function syncDirectory(path: string): void;
6
+ /** Reject symlinks in every existing component; callers use canonical /private/tmp on macOS. */
7
+ export declare function safeDirectory(path: string, create?: boolean): string;
8
+ export declare function confinedFile(root: string, path: string): string;
9
+ export declare function regularFile(path: string): void;
10
+ export declare function pathExists(path: string): boolean;
11
+ export declare function verifyFile(path: string, expectedHash: string, expectedBytes: number): void;
12
+ export declare function readVerifiedFile(path: string, expectedHash: string, expectedBytes: number): Buffer;
@@ -0,0 +1,101 @@
1
+ import { constants, closeSync, fstatSync, fsyncSync, lstatSync, mkdirSync, openSync, readSync, realpathSync } from 'node:fs';
2
+ import { dirname, isAbsolute, join, parse, relative, sep } from 'node:path';
3
+ import { createHash } from 'node:crypto';
4
+ import { StoreError } from './types.js';
5
+ export const digest = (value) => createHash('sha256').update(value).digest('hex');
6
+ export function hash(value) {
7
+ if (!/^[a-f0-9]{64}$/.test(value))
8
+ throw new StoreError('invalid-input');
9
+ }
10
+ export function text(value, max = 4096) {
11
+ if (typeof value !== 'string' || value.length === 0 || Buffer.byteLength(value) > max || value.includes('\0'))
12
+ throw new StoreError('invalid-input');
13
+ }
14
+ export function integer(value, maximum = Number.MAX_SAFE_INTEGER) {
15
+ if (!Number.isSafeInteger(value) || value < 0 || value > maximum)
16
+ throw new StoreError('invalid-input');
17
+ }
18
+ export function syncDirectory(path) {
19
+ const fd = openSync(path, constants.O_RDONLY);
20
+ try {
21
+ fsyncSync(fd);
22
+ }
23
+ finally {
24
+ closeSync(fd);
25
+ }
26
+ }
27
+ /** Reject symlinks in every existing component; callers use canonical /private/tmp on macOS. */
28
+ export function safeDirectory(path, create = false) {
29
+ if (!isAbsolute(path) || path.includes('\0') || path.split(sep).includes('..'))
30
+ throw new StoreError('invalid-input');
31
+ let current = parse(path).root;
32
+ for (const part of path.slice(current.length).split(sep).filter(Boolean)) {
33
+ current = join(current, part);
34
+ try {
35
+ const stat = lstatSync(current);
36
+ if (!stat.isDirectory() || stat.isSymbolicLink())
37
+ throw new StoreError('integrity');
38
+ }
39
+ catch (error) {
40
+ if (error.code !== 'ENOENT' || !create)
41
+ throw error;
42
+ mkdirSync(current, { mode: 0o700 });
43
+ syncDirectory(dirname(current));
44
+ }
45
+ }
46
+ return realpathSync(current);
47
+ }
48
+ export function confinedFile(root, path) {
49
+ const rel = relative(root, path);
50
+ if (!rel || rel.startsWith('..' + sep) || rel === '..' || isAbsolute(rel))
51
+ throw new StoreError('integrity');
52
+ safeDirectory(dirname(path));
53
+ return path;
54
+ }
55
+ export function regularFile(path) {
56
+ const stat = lstatSync(path);
57
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.nlink !== 1)
58
+ throw new StoreError('integrity');
59
+ }
60
+ function checkedFile(path, expectedHash, expectedBytes, retain) {
61
+ regularFile(path);
62
+ const fd = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW);
63
+ try {
64
+ const stat = fstatSync(fd);
65
+ if (!stat.isFile() || stat.size !== expectedBytes || stat.nlink !== 1)
66
+ throw new StoreError('integrity');
67
+ const h = createHash('sha256'), buffer = Buffer.allocUnsafe(64 * 1024);
68
+ let count = 0;
69
+ const chunks = [];
70
+ for (;;) {
71
+ const read = readSync(fd, buffer, 0, buffer.length, null);
72
+ if (!read)
73
+ break;
74
+ count += read;
75
+ if (count > expectedBytes)
76
+ throw new StoreError('integrity');
77
+ h.update(buffer.subarray(0, read));
78
+ if (retain)
79
+ chunks.push(Buffer.from(buffer.subarray(0, read)));
80
+ }
81
+ if (count !== expectedBytes || h.digest('hex') !== expectedHash)
82
+ throw new StoreError('integrity');
83
+ return Buffer.concat(chunks);
84
+ }
85
+ finally {
86
+ closeSync(fd);
87
+ }
88
+ }
89
+ export function pathExists(path) {
90
+ try {
91
+ lstatSync(path);
92
+ return true;
93
+ }
94
+ catch (error) {
95
+ if (error.code === 'ENOENT')
96
+ return false;
97
+ throw error;
98
+ }
99
+ }
100
+ export function verifyFile(path, expectedHash, expectedBytes) { checkedFile(path, expectedHash, expectedBytes, false); }
101
+ export function readVerifiedFile(path, expectedHash, expectedBytes) { return checkedFile(path, expectedHash, expectedBytes, true); }
@@ -0,0 +1,118 @@
1
+ import { DatabaseSync } from 'node:sqlite';
2
+ import type { JobCheckpoint } from '../../contracts/index.js';
3
+ import { type AttemptToken, type OwnedAttempt, type BlobReference, type CommitRevision, type OwnerToken, type ReadableItem, type SourceSubmission, type StoreOptions, type Submission } from './types.js';
4
+ import * as indexing from '../indexing/index.js';
5
+ import { hybridSearch } from '../search/hybrid.js';
6
+ export * from './types.js';
7
+ export declare const libraryMigrations: readonly string[];
8
+ type Row = Record<string, any>;
9
+ export declare function openLibrary(path: string, options?: StoreOptions): Promise<LibraryStore>;
10
+ /** Storage CAS authority only. The worker separately establishes OS/process custody. */
11
+ export declare class LibraryStore {
12
+ readonly root: string;
13
+ private readonly db;
14
+ private readonly options;
15
+ private closed;
16
+ constructor(root: string, db: DatabaseSync, options: StoreOptions);
17
+ createIndexGeneration(options: Parameters<typeof indexing.createGeneration>[1]): indexing.GenerationStatus;
18
+ submitIndexJob(generationId: string): string;
19
+ indexJob(id: string): Record<string, import("node:sqlite").SQLOutputValue> | undefined;
20
+ claimIndexJob(owner: OwnerToken, id?: string): AttemptToken | null;
21
+ checkpointIndexAttempt(token: AttemptToken, stage: string): void;
22
+ writeIndexAttemptBatch(token: AttemptToken, fingerprint: string, batch: Parameters<typeof indexing.writeBatch>[3]): void;
23
+ completeIndexAttempt(token: AttemptToken): indexing.GenerationStatus;
24
+ failIndexAttempt(token: AttemptToken, reason: string): void;
25
+ settleIndexAttempt(token: AttemptToken): void;
26
+ private checkIndexStaging;
27
+ indexStatus(id: string): indexing.GenerationStatus;
28
+ indexInputs(id: string, limit?: number): indexing.IndexInput[];
29
+ writeIndexBatch(id: string, fingerprint: string, batch: Parameters<typeof indexing.writeBatch>[3]): void;
30
+ activateIndex(id: string): indexing.GenerationStatus;
31
+ cancelIndex(id: string): void;
32
+ searchHybrid(query: string, options?: Parameters<typeof hybridSearch>[2]): Promise<import("../search/hybrid.js").SearchResult>;
33
+ readAnnotations(itemId: string): {
34
+ annotations: {
35
+ id: string;
36
+ revisionId: string | null;
37
+ anchor: unknown;
38
+ body: string;
39
+ createdAt: string;
40
+ }[];
41
+ readingState: {
42
+ state: unknown;
43
+ updatedAt: string;
44
+ } | null;
45
+ };
46
+ lookupImportReceipt(namespace: string, sourceKey: string, sourceHash: string): {
47
+ itemId: string;
48
+ outcome: string;
49
+ } | null;
50
+ close(): void;
51
+ private transaction;
52
+ get revisionEpoch(): number;
53
+ private bumpEpoch;
54
+ acquireOwner(ownerIncarnation: string): OwnerToken;
55
+ releaseOwner(token: OwnerToken): void;
56
+ ownerSnapshot(): OwnerToken | null;
57
+ ownerAttempts(token: OwnerToken): OwnedAttempt[];
58
+ /** Requires external custody proof for EVERY pending attempt, even after its job committed.
59
+ * IDs are acknowledgements from the custody owner, never evidence inferred from PID/timeouts here. */
60
+ recoverOwner(expected: OwnerToken, provedAttemptIds: readonly string[]): void;
61
+ checkpointAttempt(token: AttemptToken, stage: JobCheckpoint['stage']): void;
62
+ jobCancellationRequested(jobId: string): boolean;
63
+ retryJob(jobId: string, options?: {
64
+ notBefore?: string;
65
+ automatic?: boolean;
66
+ }): void;
67
+ private checkOwner;
68
+ submitSource(input: SourceSubmission): Submission;
69
+ listJobs(): Row[];
70
+ sourceForJob(jobId: string): {
71
+ itemId: string;
72
+ kind: string;
73
+ sourceKey: string;
74
+ locator: string;
75
+ realm: string;
76
+ } | null;
77
+ claimNext(token: OwnerToken): AttemptToken | null;
78
+ claimJob(token: OwnerToken, jobId: string): AttemptToken;
79
+ private checkAttempt;
80
+ requestCancellation(jobId: string): void;
81
+ failAttempt(token: AttemptToken, reason?: string, options?: {
82
+ retryable?: boolean;
83
+ retryAfterMs?: number;
84
+ }): void;
85
+ /** Caller must first settle owned external children. This only releases storage staging pins. */
86
+ settleAttempt(token: AttemptToken): void;
87
+ putBlob(token: AttemptToken, expectedHash: string, expectedBytes: number, source: AsyncIterable<Uint8Array>): Promise<BlobReference>;
88
+ commitRevision(input: CommitRevision): {
89
+ revisionId: string;
90
+ duplicate: boolean;
91
+ };
92
+ list(): {
93
+ itemId: string;
94
+ kind: string;
95
+ title: string;
96
+ revisionId: string | null;
97
+ }[];
98
+ read(itemId: string): ReadableItem | null;
99
+ readBlob(reference: BlobReference): Uint8Array;
100
+ search(query: string, count?: number): {
101
+ itemId: string;
102
+ title: string;
103
+ revisionId: string;
104
+ }[];
105
+ delete(itemId: string): void;
106
+ /** Online DB snapshot only; P12 pairs this with blobs while the returned fence remains active. */
107
+ createBackupSnapshot(): Promise<{
108
+ id: string;
109
+ path: string;
110
+ revisionEpoch: number;
111
+ }>;
112
+ finishBackup(id: string): void;
113
+ /** Hold the SQLite writer fence across synchronous GC inspection and removal. */
114
+ withGcFence<T>(expectedEpoch: number, callback: (references: readonly BlobReference[]) => T): T;
115
+ /** GC must honor both durable staging pins and active backup fences. */
116
+ pendingCleanupCount(): number;
117
+ hasGcFence(): boolean;
118
+ }