@hraness/sponge 0.2.5 → 0.3.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 (227) hide show
  1. package/README.md +23 -10
  2. package/bin/sponge.js +8 -7
  3. package/dist/contracts/index.js +24 -6
  4. package/dist/contracts/validate.js +106 -29
  5. package/dist/migrations/008.d.ts +3 -0
  6. package/dist/migrations/008.js +5 -0
  7. package/dist/migrations/009.d.ts +3 -0
  8. package/dist/migrations/009.js +8 -0
  9. package/dist/migrations/010.d.ts +3 -0
  10. package/dist/migrations/010.js +11 -0
  11. package/dist/migrations/index.d.ts +15 -0
  12. package/dist/migrations/index.js +39 -0
  13. package/dist/src/acquisition/capture.js +87 -28
  14. package/dist/src/acquisition/cleanup.d.ts +0 -4
  15. package/dist/src/acquisition/cleanup.js +3 -5
  16. package/dist/src/acquisition/errors.js +17 -2
  17. package/dist/src/acquisition/files.d.ts +0 -1
  18. package/dist/src/acquisition/files.js +14 -11
  19. package/dist/src/acquisition/index.d.ts +2 -3
  20. package/dist/src/acquisition/index.js +1 -2
  21. package/dist/src/acquisition/lock.js +1 -1
  22. package/dist/src/acquisition/normalize.js +57 -18
  23. package/dist/src/acquisition/pins.js +22 -4
  24. package/dist/src/acquisition/process.js +67 -29
  25. package/dist/src/acquisition/runtime.d.ts +5 -7
  26. package/dist/src/acquisition/runtime.js +129 -68
  27. package/dist/src/acquisition/verify-helper.js +10 -3
  28. package/dist/src/annotations/quote.js +40 -12
  29. package/dist/src/annotations/store.d.ts +0 -1
  30. package/dist/src/annotations/store.js +66 -14
  31. package/dist/src/app/article.d.ts +2 -1
  32. package/dist/src/app/article.js +66 -70
  33. package/dist/src/app/bundle-files.d.ts +0 -4
  34. package/dist/src/app/bundle-files.js +11 -14
  35. package/dist/src/app/markdown.js +18 -6
  36. package/dist/src/app/source.d.ts +0 -4
  37. package/dist/src/app/source.js +18 -14
  38. package/dist/src/cli/arguments.d.ts +2 -8
  39. package/dist/src/cli/arguments.js +67 -80
  40. package/dist/src/cli/commands.d.ts +42 -0
  41. package/dist/src/cli/commands.js +795 -0
  42. package/dist/src/cli/config.js +12 -9
  43. package/dist/src/cli/digest.d.ts +1 -1
  44. package/dist/src/cli/digest.js +39 -17
  45. package/dist/src/cli/import.js +25 -4
  46. package/dist/src/cli/indexing.d.ts +2 -0
  47. package/dist/src/cli/indexing.js +26 -9
  48. package/dist/src/cli/main.js +47 -386
  49. package/dist/src/cli/portability.d.ts +0 -2
  50. package/dist/src/cli/portability.js +13 -8
  51. package/dist/src/cli/queue.js +12 -8
  52. package/dist/src/cli/runtimes.d.ts +1 -3
  53. package/dist/src/cli/runtimes.js +13 -6
  54. package/dist/src/cli/terminal.js +1 -1
  55. package/dist/src/cli/worker.d.ts +7 -0
  56. package/dist/src/cli/worker.js +54 -15
  57. package/dist/src/derivations/kinds.d.ts +34 -0
  58. package/dist/src/derivations/kinds.js +14 -0
  59. package/dist/src/derivations/types.d.ts +48 -0
  60. package/dist/src/derivations/types.js +1 -0
  61. package/dist/src/digest/derivation.d.ts +25 -0
  62. package/dist/src/digest/derivation.js +124 -0
  63. package/dist/src/digest/editorial.d.ts +10 -46
  64. package/dist/src/digest/editorial.js +73 -59
  65. package/dist/src/digest/endpoint.js +63 -27
  66. package/dist/src/digest/pipeline.d.ts +53 -32
  67. package/dist/src/digest/pipeline.js +357 -125
  68. package/dist/src/digest/schema.d.ts +44 -17
  69. package/dist/src/digest/schema.js +132 -44
  70. package/dist/src/errors.d.ts +46 -0
  71. package/dist/src/errors.js +117 -0
  72. package/dist/src/identity/query-policy.d.ts +0 -5
  73. package/dist/src/identity/query-policy.js +61 -9
  74. package/dist/src/identity/uri.d.ts +6 -5
  75. package/dist/src/identity/uri.js +37 -18
  76. package/dist/src/identity/visibility.d.ts +11 -1
  77. package/dist/src/identity/visibility.js +81 -17
  78. package/dist/src/importers/apply.js +104 -36
  79. package/dist/src/importers/custody.js +27 -9
  80. package/dist/src/importers/inspect.js +125 -38
  81. package/dist/src/importers/jungle-digest.d.ts +31 -24
  82. package/dist/src/importers/jungle-digest.js +217 -115
  83. package/dist/src/importers/jungle-store.d.ts +20 -11
  84. package/dist/src/importers/jungle-store.js +136 -41
  85. package/dist/src/importers/jungle.d.ts +32 -16
  86. package/dist/src/importers/jungle.js +145 -32
  87. package/dist/src/importers/manifest.js +57 -21
  88. package/dist/src/importers/verify-helper.js +18 -4
  89. package/dist/src/indexing/image.js +29 -10
  90. package/dist/src/indexing/index.d.ts +37 -6
  91. package/dist/src/indexing/index.js +360 -124
  92. package/dist/src/indexing/jobs.js +156 -47
  93. package/dist/src/indexing/prune-run.d.ts +2 -0
  94. package/dist/src/indexing/prune-run.js +69 -26
  95. package/dist/src/indexing/prune.d.ts +12 -3
  96. package/dist/src/indexing/prune.js +85 -35
  97. package/dist/src/indexing/runner.d.ts +2 -1
  98. package/dist/src/indexing/runner.js +83 -40
  99. package/dist/src/indexing/upgrade.d.ts +9 -0
  100. package/dist/src/indexing/upgrade.js +79 -0
  101. package/dist/src/inference/asr/bridge.js +6 -2
  102. package/dist/src/inference/asr/protocol.js +109 -19
  103. package/dist/src/inference/asr/runtime.js +58 -21
  104. package/dist/src/inference/asr/windows.js +9 -5
  105. package/dist/src/inference/embedding/index.d.ts +2 -6
  106. package/dist/src/inference/embedding/index.js +89 -29
  107. package/dist/src/ingest/attempt.d.ts +29 -0
  108. package/dist/src/ingest/attempt.js +55 -0
  109. package/dist/src/media/capture-helper.js +7 -2
  110. package/dist/src/media/capture.d.ts +2 -1
  111. package/dist/src/media/capture.js +124 -43
  112. package/dist/src/media/handler.d.ts +4 -2
  113. package/dist/src/media/handler.js +88 -70
  114. package/dist/src/media/transcribe.js +63 -21
  115. package/dist/src/metadata/article.js +49 -17
  116. package/dist/src/models/artifacts.d.ts +10 -8
  117. package/dist/src/models/artifacts.js +237 -106
  118. package/dist/src/models/catalog.d.ts +2 -5
  119. package/dist/src/models/catalog.js +94 -25
  120. package/dist/src/models/download.js +55 -15
  121. package/dist/src/models/runtime.d.ts +0 -2
  122. package/dist/src/models/runtime.js +69 -33
  123. package/dist/src/pdf/capture-helper.js +3 -1
  124. package/dist/src/pdf/capture.d.ts +2 -1
  125. package/dist/src/pdf/capture.js +95 -27
  126. package/dist/src/pdf/errors.js +12 -1
  127. package/dist/src/pdf/handler.d.ts +2 -1
  128. package/dist/src/pdf/handler.js +70 -71
  129. package/dist/src/pdf/index.d.ts +1 -3
  130. package/dist/src/pdf/index.js +0 -2
  131. package/dist/src/pdf/input.js +12 -7
  132. package/dist/src/pdf/normalize.js +80 -21
  133. package/dist/src/pdf/source-identity.js +3 -2
  134. package/dist/src/pdf/source.js +12 -8
  135. package/dist/src/pdf/verify-helper.js +15 -3
  136. package/dist/src/portability/backup.d.ts +2 -9
  137. package/dist/src/portability/backup.js +108 -22
  138. package/dist/src/portability/database.js +51 -17
  139. package/dist/src/portability/export.js +35 -9
  140. package/dist/src/portability/files.d.ts +1 -4
  141. package/dist/src/portability/files.js +127 -67
  142. package/dist/src/portability/gc.js +65 -22
  143. package/dist/src/publish/component.js +1 -1
  144. package/dist/src/publish/feed.d.ts +2 -2
  145. package/dist/src/publish/feed.js +75 -29
  146. package/dist/src/publish/identity.d.ts +5 -1
  147. package/dist/src/publish/identity.js +31 -11
  148. package/dist/src/publish/index.d.ts +2 -3
  149. package/dist/src/publish/index.js +34 -21
  150. package/dist/src/publish/projection.d.ts +2 -9
  151. package/dist/src/publish/projection.js +21 -14
  152. package/dist/src/search/extension.js +3 -1
  153. package/dist/src/search/hybrid.d.ts +3 -8
  154. package/dist/src/search/hybrid.js +45 -11
  155. package/dist/src/search/lexical.js +18 -4
  156. package/dist/src/search/query.js +56 -25
  157. package/dist/src/search/vector.js +37 -10
  158. package/dist/src/service/launch-agent.d.ts +5 -3
  159. package/dist/src/service/launch-agent.js +272 -83
  160. package/dist/src/service/lifetime.js +47 -14
  161. package/dist/src/service/loop.d.ts +3 -3
  162. package/dist/src/service/loop.js +47 -19
  163. package/dist/src/store/annotations.d.ts +32 -0
  164. package/dist/src/store/annotations.js +44 -0
  165. package/dist/src/store/backups.d.ts +18 -0
  166. package/dist/src/store/backups.js +110 -0
  167. package/dist/src/store/blobs.d.ts +24 -0
  168. package/dist/src/store/blobs.js +139 -0
  169. package/dist/src/store/changes.d.ts +5 -12
  170. package/dist/src/store/changes.js +108 -56
  171. package/dist/src/store/context.d.ts +15 -0
  172. package/dist/src/store/context.js +19 -0
  173. package/dist/src/store/derivations.d.ts +42 -0
  174. package/dist/src/store/derivations.js +104 -0
  175. package/dist/src/store/files.d.ts +0 -2
  176. package/dist/src/store/files.js +19 -24
  177. package/dist/src/store/ids.d.ts +30 -0
  178. package/dist/src/store/ids.js +34 -0
  179. package/dist/src/store/imports.d.ts +26 -0
  180. package/dist/src/store/imports.js +57 -0
  181. package/dist/src/store/index.d.ts +3 -186
  182. package/dist/src/store/index.js +2 -809
  183. package/dist/src/store/lease.d.ts +20 -0
  184. package/dist/src/store/lease.js +62 -0
  185. package/dist/src/store/library.d.ts +75 -0
  186. package/dist/src/store/library.js +174 -0
  187. package/dist/src/store/open.d.ts +7 -0
  188. package/dist/src/store/open.js +183 -0
  189. package/dist/src/store/queue.d.ts +65 -0
  190. package/dist/src/store/queue.js +327 -0
  191. package/dist/src/store/revisions.d.ts +12 -0
  192. package/dist/src/store/revisions.js +189 -0
  193. package/dist/src/store/search-index.d.ts +63 -0
  194. package/dist/src/store/search-index.js +190 -0
  195. package/dist/src/store/sync-ready.d.ts +6 -0
  196. package/dist/src/store/sync-ready.js +121 -0
  197. package/dist/src/store/types.d.ts +1 -5
  198. package/dist/src/store/types.js +1 -8
  199. package/dist/src/util/canonical.d.ts +2 -0
  200. package/dist/src/util/canonical.js +17 -0
  201. package/dist/src/util/exact.d.ts +2 -0
  202. package/dist/src/util/exact.js +9 -0
  203. package/dist/src/util/fsync.d.ts +4 -0
  204. package/dist/src/util/fsync.js +22 -0
  205. package/dist/src/util/hash.d.ts +4 -0
  206. package/dist/src/util/hash.js +8 -0
  207. package/dist/src/worker/basic.d.ts +0 -1
  208. package/dist/src/worker/basic.js +23 -7
  209. package/dist/src/worker/custody.d.ts +4 -1
  210. package/dist/src/worker/custody.js +111 -38
  211. package/dist/src/worker/engine.d.ts +2 -1
  212. package/dist/src/worker/engine.js +42 -20
  213. package/dist/src/worker/identity.js +13 -5
  214. package/dist/src/worker/journal.d.ts +1 -1
  215. package/dist/src/worker/journal.js +54 -24
  216. package/dist/src/worker/lock.d.ts +18 -0
  217. package/dist/src/worker/lock.js +196 -0
  218. package/dist/src/worker/runtime-gc.d.ts +4 -3
  219. package/dist/src/worker/runtime-gc.js +68 -41
  220. package/dist/src/worker/supervisor-child.js +19 -6
  221. package/dist/src/worker/supervisor.js +41 -8
  222. package/native/runtime-manifest.json +4 -4
  223. package/package.json +10 -2
  224. package/dist/src/digest/store.d.ts +0 -57
  225. package/dist/src/digest/store.js +0 -77
  226. package/dist/src/store/foundation.d.ts +0 -7
  227. package/dist/src/store/foundation.js +0 -7
@@ -4,10 +4,11 @@ import { fileURLToPath } from 'node:url';
4
4
  import { limits } from '../../contracts/index.js';
5
5
  import { privateRoot, physicalBytes } from './files.js';
6
6
  import { runOwned, isolatedEnvironment } from './process.js';
7
- import { inspectCaptureRuntime, CaptureSetupError } from './runtime.js';
8
- import { settleCaptureRoot, CaptureCleanupError } from './cleanup.js';
7
+ import { inspectCaptureRuntime } from './runtime.js';
8
+ import { settleCaptureRoot } from './cleanup.js';
9
9
  import { failure, upstreamFailure } from './errors.js';
10
10
  import { normalizeBundle, object } from './normalize.js';
11
+ import { SpongeError, publicCode, codeOf } from '../errors.js';
11
12
  export async function captureArticle(request) {
12
13
  const { requestId, signal } = request;
13
14
  if (!/^[a-zA-Z0-9_-]{1,128}$/.test(requestId))
@@ -28,7 +29,7 @@ export async function captureArticle(request) {
28
29
  runtime = await inspectCaptureRuntime(request.runtime.root, request.runtime.pins);
29
30
  }
30
31
  catch (error) {
31
- return failure(requestId, error instanceof CaptureSetupError ? error.code : 'runtime-missing', 'setup');
32
+ return failure(requestId, publicCode(error, 'runtime-missing'), 'setup');
32
33
  }
33
34
  let base;
34
35
  try {
@@ -43,7 +44,24 @@ export async function captureArticle(request) {
43
44
  const deadline = request.deadlineMs ?? limits.captureDeadlineMs;
44
45
  if (!Number.isSafeInteger(deadline) || deadline < 100 || deadline > limits.captureDeadlineMs)
45
46
  return failure(requestId, 'invalid-input');
46
- const args = [runtime.ghostget, 'clip', request.sourceUrl, 'article', '--media', 'images', '--timeout-ms', String(deadline), '--max-html-bytes', String(limits.markdownBytes), '--max-asset-bytes', String(limits.imageBytes), '--max-total-asset-bytes', String(500 * 1024 ** 2), '--quiet', '--json'];
47
+ const args = [
48
+ runtime.ghostget,
49
+ 'clip',
50
+ request.sourceUrl,
51
+ 'article',
52
+ '--media',
53
+ 'images',
54
+ '--timeout-ms',
55
+ String(deadline),
56
+ '--max-html-bytes',
57
+ String(limits.markdownBytes),
58
+ '--max-asset-bytes',
59
+ String(limits.imageBytes),
60
+ '--max-total-asset-bytes',
61
+ String(500 * 1024 ** 2),
62
+ '--quiet',
63
+ '--json',
64
+ ];
47
65
  if (request.allowPrivateNetwork)
48
66
  args.push('--allow-private-network');
49
67
  let selectedState;
@@ -74,27 +92,40 @@ export async function captureArticle(request) {
74
92
  if (signal?.aborted)
75
93
  abort();
76
94
  let cleanup = 'settled', keep = false, quota = false, checking = false;
77
- const monitor = setInterval(async () => { if (checking)
78
- return; checking = true; try {
79
- if (await physicalBytes(root) > limits.stagingBytes) {
95
+ const monitor = setInterval(async () => {
96
+ if (checking)
97
+ return;
98
+ checking = true;
99
+ try {
100
+ if ((await physicalBytes(root)) > limits.stagingBytes) {
101
+ quota = true;
102
+ controller.abort();
103
+ }
104
+ }
105
+ catch {
80
106
  quota = true;
81
107
  controller.abort();
82
108
  }
83
- }
84
- catch {
85
- quota = true;
86
- controller.abort();
87
- }
88
- finally {
89
- checking = false;
90
- } }, 100);
109
+ finally {
110
+ checking = false;
111
+ }
112
+ }, 100);
91
113
  const started = Date.now();
92
114
  try {
93
115
  await mkdir(home, { mode: 0o700 });
94
116
  await mkdir(output, { mode: 0o700 });
95
- await writeFile(join(root, 'ownership.json'), JSON.stringify({ schemaVersion: 1, requestId, state: 'acquiring' }), { mode: 0o600 });
117
+ await writeFile(join(root, 'ownership.json'), JSON.stringify({ schemaVersion: 1, requestId, state: 'acquiring' }), {
118
+ mode: 0o600,
119
+ });
96
120
  cleanup = 'pending';
97
- const result = await (request.runProcess ?? runOwned)(runtime.bun, args, { cwd: root, env, signal: controller.signal, deadlineMs: deadline, maxOutputBytes: limits.metadataBytes, graceMs: 5000 });
121
+ const result = await (request.runProcess ?? runOwned)(runtime.bun, args, {
122
+ cwd: root,
123
+ env,
124
+ signal: controller.signal,
125
+ deadlineMs: deadline,
126
+ maxOutputBytes: limits.metadataBytes,
127
+ graceMs: 5000,
128
+ });
98
129
  cleanup = result.cleanup;
99
130
  // Ghostget reports escaped browser custody separately from generic descendants.
100
131
  let summary;
@@ -109,9 +140,13 @@ export async function captureArticle(request) {
109
140
  cleanup = 'pending';
110
141
  if (cleanup === 'settled' && request.connection?.kind === 'cdp') {
111
142
  cleanup = 'pending';
112
- const census = await (request.runProcess ?? runOwned)('/bin/ps', ['-axo', 'command'], { env, deadlineMs: 3000, maxOutputBytes: 4 * 1024 ** 2 });
143
+ const census = await (request.runProcess ?? runOwned)('/bin/ps', ['-axo', 'command'], {
144
+ env,
145
+ deadlineMs: 3000,
146
+ maxOutputBytes: 4 * 1024 ** 2,
147
+ });
113
148
  cleanup = census.cleanup;
114
- if (census.code !== 0 || census.stopped || census.stdout.split('\n').some(line => line.includes(root)))
149
+ if (census.code !== 0 || census.stopped || census.stdout.split('\n').some((line) => line.includes(root)))
115
150
  cleanup = 'pending';
116
151
  }
117
152
  if (cleanup !== 'settled')
@@ -123,11 +158,19 @@ export async function captureArticle(request) {
123
158
  if (result.code !== 0 || object(summary).ok !== true)
124
159
  return upstream;
125
160
  const outputDirectory = object(summary).outputDirectory;
126
- if (typeof outputDirectory !== 'string' || !outputDirectory.startsWith(output + '/') || await realpath(outputDirectory) !== outputDirectory)
161
+ if (typeof outputDirectory !== 'string' ||
162
+ !outputDirectory.startsWith(output + '/') ||
163
+ (await realpath(outputDirectory)) !== outputDirectory)
127
164
  return failure(requestId, 'integrity', 'verification');
128
165
  const helper = fileURLToPath(new URL(import.meta.url.endsWith('.ts') ? './verify-helper.ts' : './verify-helper.js', import.meta.url));
129
166
  cleanup = 'pending';
130
- const checked = await (request.runProcess ?? runOwned)(runtime.bun, [helper, runtime.root, outputDirectory], { cwd: root, env, signal: controller.signal, deadlineMs: Math.max(1, deadline - (Date.now() - started)), maxOutputBytes: limits.helperFrameBytes });
167
+ const checked = await (request.runProcess ?? runOwned)(runtime.bun, [helper, runtime.root, outputDirectory], {
168
+ cwd: root,
169
+ env,
170
+ signal: controller.signal,
171
+ deadlineMs: Math.max(1, deadline - (Date.now() - started)),
172
+ maxOutputBytes: limits.helperFrameBytes,
173
+ });
131
174
  cleanup = checked.cleanup;
132
175
  if (cleanup !== 'settled')
133
176
  return failure(requestId, 'cleanup-required', 'cleanup');
@@ -135,26 +178,42 @@ export async function captureArticle(request) {
135
178
  return failure(requestId, checked.stopped);
136
179
  if (checked.code !== 0)
137
180
  return failure(requestId, 'integrity', 'verification');
138
- const capture = await normalizeBundle({ bundleRoot: outputDirectory, inspection: JSON.parse(checked.stdout), summary, requestId, sourceUrl: request.sourceUrl, wordcellVersion: runtime.pins.wordcell.version });
181
+ const capture = await normalizeBundle({
182
+ bundleRoot: outputDirectory,
183
+ inspection: JSON.parse(checked.stdout),
184
+ summary,
185
+ requestId,
186
+ sourceUrl: request.sourceUrl,
187
+ wordcellVersion: runtime.pins.wordcell.version,
188
+ });
139
189
  if (controller.signal.aborted)
140
190
  return failure(requestId, quota ? 'limit-exceeded' : 'cancelled');
141
- await writeFile(join(root, 'ownership.json'), JSON.stringify({ schemaVersion: 1, requestId, state: 'verified' }), { mode: 0o600 });
191
+ await writeFile(join(root, 'ownership.json'), JSON.stringify({ schemaVersion: 1, requestId, state: 'verified' }), {
192
+ mode: 0o600,
193
+ });
142
194
  keep = true;
143
- return { ok: true, capture, bundleRoot: outputDirectory, dispose: async () => { if (await settleCaptureRoot(root, requestId) === 'pending')
144
- throw new CaptureCleanupError(); } };
195
+ return {
196
+ ok: true,
197
+ capture,
198
+ bundleRoot: outputDirectory,
199
+ dispose: async () => {
200
+ if ((await settleCaptureRoot(root, requestId)) === 'pending')
201
+ throw new SpongeError('cleanup-required');
202
+ },
203
+ };
145
204
  }
146
205
  catch (error) {
147
206
  if (cleanup !== 'settled')
148
207
  return failure(requestId, 'cleanup-required', 'cleanup');
149
- const code = (error instanceof Error && ['integrity', 'limit-exceeded', 'schema-newer'].includes(error.message) ? error.message : 'unclassified');
208
+ const raw = codeOf(error), code = raw === 'integrity' || raw === 'limit-exceeded' || raw === 'schema-newer' ? raw : 'unclassified';
150
209
  return failure(requestId, code, 'verification');
151
210
  }
152
211
  finally {
153
212
  clearInterval(monitor);
154
213
  while (checking)
155
- await new Promise(r => setTimeout(r, 5));
214
+ await new Promise((r) => setTimeout(r, 5));
156
215
  signal?.removeEventListener('abort', abort);
157
- if (!keep && cleanup === 'settled' && await settleCaptureRoot(root, requestId) === 'pending')
216
+ if (!keep && cleanup === 'settled' && (await settleCaptureRoot(root, requestId)) === 'pending')
158
217
  return failure(requestId, 'cleanup-required', 'cleanup');
159
218
  }
160
219
  }
@@ -1,6 +1,2 @@
1
- export declare class CaptureCleanupError extends Error {
2
- readonly code = "cleanup-required";
3
- constructor();
4
- }
5
1
  /** Cleanup failure retains ownership evidence and must not settle the queue attempt. */
6
2
  export declare function settleCaptureRoot(root: string, requestId: string): Promise<'settled' | 'pending'>;
@@ -1,9 +1,5 @@
1
1
  import { rm, writeFile } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
- export class CaptureCleanupError extends Error {
4
- code = 'cleanup-required';
5
- constructor() { super('cleanup-required'); }
6
- }
7
3
  /** Cleanup failure retains ownership evidence and must not settle the queue attempt. */
8
4
  export async function settleCaptureRoot(root, requestId) {
9
5
  try {
@@ -14,7 +10,9 @@ export async function settleCaptureRoot(root, requestId) {
14
10
  try {
15
11
  await writeFile(join(root, 'ownership.json'), JSON.stringify({ schemaVersion: 1, requestId, state: 'cleanup-required' }), { mode: 0o600 });
16
12
  }
17
- catch { /* Existing ownership record remains when directory access itself failed. */ }
13
+ catch {
14
+ /* Existing ownership record remains when directory access itself failed. */
15
+ }
18
16
  return 'pending';
19
17
  }
20
18
  }
@@ -1,4 +1,15 @@
1
- const mappings = { 'unknown': 'unclassified', 'permission-required': 'grant-permission', 'auth-required': 'repair-auth', 'invalid-input': 'invalid-input', 'cancelled': 'cancelled', 'timeout': 'unavailable', 'transient': 'unavailable', 'unsupported': 'unsupported', 'cleanup-pending': 'cleanup-required', 'rate-limited': 'rate-limited' };
1
+ const mappings = {
2
+ unknown: 'unclassified',
3
+ 'permission-required': 'grant-permission',
4
+ 'auth-required': 'repair-auth',
5
+ 'invalid-input': 'invalid-input',
6
+ cancelled: 'cancelled',
7
+ timeout: 'unavailable',
8
+ transient: 'unavailable',
9
+ unsupported: 'unsupported',
10
+ 'cleanup-pending': 'cleanup-required',
11
+ 'rate-limited': 'rate-limited',
12
+ };
2
13
  export const failure = (requestId, code, phase = 'acquisition', retryable = false) => ({ schemaVersion: 1, requestId, ok: false, code, phase, retryable });
3
14
  export function upstreamFailure(value, requestId) {
4
15
  const fallback = failure(requestId, 'unclassified');
@@ -11,7 +22,11 @@ export function upstreamFailure(value, requestId) {
11
22
  if (!raw || typeof raw !== 'object' || Array.isArray(raw))
12
23
  return fallback;
13
24
  const typed = raw;
14
- if (Object.keys(typed).some(k => !['schemaVersion', 'code', 'retryable'].includes(k)) || typed.schemaVersion !== 1 || typeof typed.code !== 'string' || !Object.hasOwn(mappings, typed.code) || typeof typed.retryable !== 'boolean')
25
+ if (Object.keys(typed).some((k) => !['schemaVersion', 'code', 'retryable'].includes(k)) ||
26
+ typed.schemaVersion !== 1 ||
27
+ typeof typed.code !== 'string' ||
28
+ !Object.hasOwn(mappings, typed.code) ||
29
+ typeof typed.retryable !== 'boolean')
15
30
  return fallback;
16
31
  const code = mappings[typed.code];
17
32
  if (typed.retryable && !['timeout', 'transient', 'rate-limited'].includes(typed.code))
@@ -1,4 +1,3 @@
1
- export declare const hash: (bytes: Uint8Array | string) => string;
2
1
  export declare function privateRoot(path: string): Promise<string>;
3
2
  export declare function readConfined(root: string, name: string, maxBytes: number): Promise<Buffer>;
4
3
  export declare function physicalBytes(root: string): Promise<number>;
@@ -1,31 +1,34 @@
1
1
  import { constants } from 'node:fs';
2
2
  import { open, lstat, realpath, readdir } from 'node:fs/promises';
3
3
  import { resolve, relative, isAbsolute, join } from 'node:path';
4
- import { createHash } from 'node:crypto';
5
- export const hash = (bytes) => createHash('sha256').update(bytes).digest('hex');
4
+ import { SpongeError } from '../errors.js';
6
5
  export async function privateRoot(path) {
7
6
  if (!isAbsolute(path))
8
- throw Error('invalid-input');
7
+ throw new SpongeError('invalid-input');
9
8
  const canonical = await realpath(path), stat = await lstat(path);
10
- if (canonical !== path || !stat.isDirectory() || stat.isSymbolicLink() || stat.uid !== process.getuid?.() || (stat.mode & 0o077) !== 0)
11
- throw Error('invalid-input');
9
+ if (canonical !== path ||
10
+ !stat.isDirectory() ||
11
+ stat.isSymbolicLink() ||
12
+ stat.uid !== process.getuid?.() ||
13
+ (stat.mode & 0o077) !== 0)
14
+ throw new SpongeError('invalid-input');
12
15
  return canonical;
13
16
  }
14
17
  export async function readConfined(root, name, maxBytes) {
15
- if (!name || isAbsolute(name) || name.includes('\\') || name.split('/').some(p => !p || p === '.' || p === '..'))
16
- throw Error('integrity');
18
+ if (!name || isAbsolute(name) || name.includes('\\') || name.split('/').some((p) => !p || p === '.' || p === '..'))
19
+ throw new SpongeError('integrity');
17
20
  const path = resolve(root, name);
18
- if (relative(root, path).startsWith('..') || await realpath(path) !== path)
19
- throw Error('integrity');
21
+ if (relative(root, path).startsWith('..') || (await realpath(path)) !== path)
22
+ throw new SpongeError('integrity');
20
23
  const file = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
21
24
  try {
22
25
  const stat = await file.stat();
23
26
  if (!stat.isFile() || stat.size > maxBytes)
24
- throw Error('limit-exceeded');
27
+ throw new SpongeError('limit-exceeded');
25
28
  const data = Buffer.alloc(stat.size + 1);
26
29
  const { bytesRead } = await file.read(data, 0, data.length, 0);
27
30
  if (bytesRead !== stat.size)
28
- throw Error('integrity');
31
+ throw new SpongeError('integrity');
29
32
  return data.subarray(0, bytesRead);
30
33
  }
31
34
  finally {
@@ -1,6 +1,5 @@
1
1
  export { captureArticle } from './capture.js';
2
2
  export type { CaptureConnection, CaptureRequest, CaptureOutcome } from './capture.js';
3
- export { provisionCapture, inspectCaptureRuntime, captureSetupPlan, CaptureSetupError } from './runtime.js';
4
- export type { CaptureRuntime, CapturePins, SetupPlan } from './runtime.js';
3
+ export { provisionCapture, inspectCaptureRuntime, captureSetupPlan } from './runtime.js';
4
+ export type { CaptureRuntime } from './runtime.js';
5
5
  export { defaultCapturePins } from './pins.js';
6
- export { CaptureCleanupError } from './cleanup.js';
@@ -1,4 +1,3 @@
1
1
  export { captureArticle } from './capture.js';
2
- export { provisionCapture, inspectCaptureRuntime, captureSetupPlan, CaptureSetupError } from './runtime.js';
2
+ export { provisionCapture, inspectCaptureRuntime, captureSetupPlan } from './runtime.js';
3
3
  export { defaultCapturePins } from './pins.js';
4
- export { CaptureCleanupError } from './cleanup.js';