@ontos-ai/knowhere-sdk 2.6.1-beta.20261027152313 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-DIONXJWK.mjs → chunk-OCR7IDYL.mjs} +128 -101
- package/dist/index.d.mts +48 -2
- package/dist/index.d.ts +48 -2
- package/dist/index.js +352 -124
- package/dist/index.mjs +188 -15
- package/dist/{sequential-parsed-document-archive-W7HPYIKA.mjs → sequential-parsed-document-archive-AIRFKO52.mjs} +27 -2
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -47,7 +47,7 @@ import {
|
|
|
47
47
|
syncParseResultToParsedDocumentStorage,
|
|
48
48
|
syncRemoteResultArchive,
|
|
49
49
|
validateArchiveSyncLimits
|
|
50
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-OCR7IDYL.mjs";
|
|
51
51
|
|
|
52
52
|
// src/client.ts
|
|
53
53
|
import path2 from "path";
|
|
@@ -1068,6 +1068,12 @@ var Jobs = class extends BaseResource {
|
|
|
1068
1068
|
enrichJobResult(jobResult);
|
|
1069
1069
|
return jobResult;
|
|
1070
1070
|
}
|
|
1071
|
+
/** Renew unfinished enhancement without creating another ingestion. */
|
|
1072
|
+
async retryEnhancement(jobId) {
|
|
1073
|
+
return this.httpClient.post(
|
|
1074
|
+
this.endpoint(`/jobs/${jobId}/enrichment/retry`)
|
|
1075
|
+
);
|
|
1076
|
+
}
|
|
1071
1077
|
/**
|
|
1072
1078
|
* Upload file for a job
|
|
1073
1079
|
*/
|
|
@@ -1764,6 +1770,21 @@ function isMissingFileError2(error) {
|
|
|
1764
1770
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
1765
1771
|
}
|
|
1766
1772
|
|
|
1773
|
+
// src/knowledge/serialize-snapshot-publication.ts
|
|
1774
|
+
var pendingPublications = /* @__PURE__ */ new WeakMap();
|
|
1775
|
+
async function serializeSnapshotPublication(storage, documentId, publish) {
|
|
1776
|
+
const publications = pendingPublications.get(storage) ?? /* @__PURE__ */ new Map();
|
|
1777
|
+
pendingPublications.set(storage, publications);
|
|
1778
|
+
const previous = publications.get(documentId) ?? Promise.resolve();
|
|
1779
|
+
const current = previous.catch(() => void 0).then(publish);
|
|
1780
|
+
publications.set(documentId, current);
|
|
1781
|
+
try {
|
|
1782
|
+
return await current;
|
|
1783
|
+
} finally {
|
|
1784
|
+
if (publications.get(documentId) === current) publications.delete(documentId);
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1767
1788
|
// src/knowledge/knowledge.ts
|
|
1768
1789
|
var DEFAULT_READ_LIMIT = 12;
|
|
1769
1790
|
var MAX_READ_LIMIT = 40;
|
|
@@ -1881,11 +1902,37 @@ var Knowledge = class _Knowledge {
|
|
|
1881
1902
|
return this.importJobResult(params);
|
|
1882
1903
|
}
|
|
1883
1904
|
async syncParsedDocument(params) {
|
|
1905
|
+
const response = await this.performParsedDocumentSync(params);
|
|
1906
|
+
if (response.completed && !response.snapshot) {
|
|
1907
|
+
const storage = this.requireParsedStorageConfig().storage;
|
|
1908
|
+
await serializeSnapshotPublication(storage, response.documentId, async () => {
|
|
1909
|
+
if (params.documentId || params.jobId) {
|
|
1910
|
+
const current = await this.client.documents.listChunks(
|
|
1911
|
+
response.documentId,
|
|
1912
|
+
{ page: 1, pageSize: 1 }
|
|
1913
|
+
);
|
|
1914
|
+
if (params.jobId && current.jobId !== params.jobId) return;
|
|
1915
|
+
if (!params.jobId && current.jobResultId !== response.revisionKey) return;
|
|
1916
|
+
}
|
|
1917
|
+
await storage.writeObject({
|
|
1918
|
+
documentId: response.documentId,
|
|
1919
|
+
revisionKey: "current",
|
|
1920
|
+
path: ".knowhere-sdk/current-snapshot.json",
|
|
1921
|
+
body: Buffer.from(
|
|
1922
|
+
JSON.stringify({ snapshotId: response.revisionKey, jobResultId: response.revisionKey })
|
|
1923
|
+
),
|
|
1924
|
+
contentType: "application/json; charset=utf-8"
|
|
1925
|
+
});
|
|
1926
|
+
});
|
|
1927
|
+
}
|
|
1928
|
+
return response;
|
|
1929
|
+
}
|
|
1930
|
+
async performParsedDocumentSync(params) {
|
|
1884
1931
|
params.signal?.throwIfAborted();
|
|
1885
1932
|
const normalized = normalizeDocumentReference(params);
|
|
1886
1933
|
const parsedStorageConfig = this.requireParsedStorageConfig();
|
|
1887
1934
|
validateArchiveSyncLimits(parsedStorageConfig.limits);
|
|
1888
|
-
if (normalized.documentId) {
|
|
1935
|
+
if (normalized.documentId && !normalized.jobId) {
|
|
1889
1936
|
return this.syncRemoteDocumentToParsedStorage({
|
|
1890
1937
|
documentId: normalized.documentId,
|
|
1891
1938
|
revisionKey: params.revisionKey,
|
|
@@ -1897,6 +1944,25 @@ var Knowledge = class _Knowledge {
|
|
|
1897
1944
|
}
|
|
1898
1945
|
if (normalized.jobId) {
|
|
1899
1946
|
const job = await this.client.jobs.get(normalized.jobId);
|
|
1947
|
+
if (job.snapshots?.length) {
|
|
1948
|
+
return this.syncJobSnapshot({
|
|
1949
|
+
job,
|
|
1950
|
+
documentId: normalized.documentId ?? job.documentId ?? normalized.localDocumentId ?? normalized.jobId,
|
|
1951
|
+
revisionKey: params.revisionKey,
|
|
1952
|
+
parsedStorageConfig,
|
|
1953
|
+
signal: params.signal,
|
|
1954
|
+
retainResultArchive: params.retainResultArchive
|
|
1955
|
+
});
|
|
1956
|
+
}
|
|
1957
|
+
if (normalized.documentId) {
|
|
1958
|
+
return this.syncRemoteDocumentToParsedStorage({
|
|
1959
|
+
documentId: normalized.documentId,
|
|
1960
|
+
revisionKey: params.revisionKey,
|
|
1961
|
+
parsedStorageConfig,
|
|
1962
|
+
signal: params.signal,
|
|
1963
|
+
retainResultArchive: params.retainResultArchive
|
|
1964
|
+
});
|
|
1965
|
+
}
|
|
1900
1966
|
if (!job.isDone || !job.resultUrl)
|
|
1901
1967
|
throw new ValidationError("Completed job result archive is unavailable");
|
|
1902
1968
|
return syncRemoteResultArchive({
|
|
@@ -1928,6 +1994,89 @@ var Knowledge = class _Knowledge {
|
|
|
1928
1994
|
commit: synced.commit
|
|
1929
1995
|
};
|
|
1930
1996
|
}
|
|
1997
|
+
async syncJobSnapshot(params) {
|
|
1998
|
+
const snapshotId = params.revisionKey ?? params.job.currentSnapshotId;
|
|
1999
|
+
const snapshot = params.job.snapshots?.find(
|
|
2000
|
+
(candidate) => candidate.snapshotId === snapshotId
|
|
2001
|
+
);
|
|
2002
|
+
if (!params.job.isDone || !snapshot)
|
|
2003
|
+
throw new ValidationError("Requested immutable parsed snapshot is unavailable");
|
|
2004
|
+
if (snapshot.jobId !== params.job.jobId || snapshot.documentId !== params.documentId)
|
|
2005
|
+
throw new ValidationError(
|
|
2006
|
+
"Parsed snapshot document or job identity differs from the request"
|
|
2007
|
+
);
|
|
2008
|
+
const response = await syncRemoteResultArchive({
|
|
2009
|
+
documentId: params.documentId,
|
|
2010
|
+
revisionKey: snapshot.snapshotId,
|
|
2011
|
+
jobId: snapshot.jobId,
|
|
2012
|
+
snapshot,
|
|
2013
|
+
resultUrl: snapshot.resultUrl,
|
|
2014
|
+
storage: params.parsedStorageConfig.storage,
|
|
2015
|
+
limits: params.parsedStorageConfig.limits,
|
|
2016
|
+
signal: params.signal,
|
|
2017
|
+
retainResultArchive: params.retainResultArchive
|
|
2018
|
+
});
|
|
2019
|
+
if (response.completed && snapshot.snapshotId === params.job.currentSnapshotId) {
|
|
2020
|
+
await serializeSnapshotPublication(
|
|
2021
|
+
params.parsedStorageConfig.storage,
|
|
2022
|
+
params.documentId,
|
|
2023
|
+
async () => {
|
|
2024
|
+
const current = await this.client.documents.listChunks(
|
|
2025
|
+
params.documentId,
|
|
2026
|
+
{ page: 1, pageSize: 1 }
|
|
2027
|
+
);
|
|
2028
|
+
if (current.jobResultId !== snapshot.jobResultId) return;
|
|
2029
|
+
const pointer = Buffer.from(
|
|
2030
|
+
JSON.stringify({
|
|
2031
|
+
snapshotId: snapshot.snapshotId,
|
|
2032
|
+
jobResultId: snapshot.jobResultId
|
|
2033
|
+
})
|
|
2034
|
+
);
|
|
2035
|
+
if (snapshot.stage === "final") {
|
|
2036
|
+
await params.parsedStorageConfig.storage.writeObject({
|
|
2037
|
+
documentId: params.documentId,
|
|
2038
|
+
revisionKey: "current",
|
|
2039
|
+
path: ".knowhere-sdk/final-snapshot.json",
|
|
2040
|
+
body: pointer,
|
|
2041
|
+
contentType: "application/json; charset=utf-8"
|
|
2042
|
+
});
|
|
2043
|
+
}
|
|
2044
|
+
await params.parsedStorageConfig.storage.writeObject({
|
|
2045
|
+
documentId: params.documentId,
|
|
2046
|
+
revisionKey: "current",
|
|
2047
|
+
path: ".knowhere-sdk/current-snapshot.json",
|
|
2048
|
+
body: pointer,
|
|
2049
|
+
contentType: "application/json; charset=utf-8"
|
|
2050
|
+
});
|
|
2051
|
+
}
|
|
2052
|
+
);
|
|
2053
|
+
}
|
|
2054
|
+
return response;
|
|
2055
|
+
}
|
|
2056
|
+
async resolveStoredSnapshotKey(documentId) {
|
|
2057
|
+
const object = await this.parsedStorageConfig?.storage.readObject({
|
|
2058
|
+
documentId,
|
|
2059
|
+
revisionKey: "current",
|
|
2060
|
+
path: ".knowhere-sdk/current-snapshot.json"
|
|
2061
|
+
});
|
|
2062
|
+
if (!object) return void 0;
|
|
2063
|
+
const payload = JSON.parse(Buffer.from(object.body).toString("utf8"));
|
|
2064
|
+
if (typeof payload !== "object" || payload === null || !("snapshotId" in payload))
|
|
2065
|
+
throw new ValidationError("Invalid current parsed snapshot pointer");
|
|
2066
|
+
if (typeof payload.snapshotId !== "string")
|
|
2067
|
+
throw new ValidationError("Invalid current parsed snapshot identity");
|
|
2068
|
+
const finalObject = await this.parsedStorageConfig?.storage.readObject({
|
|
2069
|
+
documentId,
|
|
2070
|
+
revisionKey: "current",
|
|
2071
|
+
path: ".knowhere-sdk/final-snapshot.json"
|
|
2072
|
+
});
|
|
2073
|
+
if (finalObject && "jobResultId" in payload) {
|
|
2074
|
+
const finalPayload = JSON.parse(Buffer.from(finalObject.body).toString("utf8"));
|
|
2075
|
+
if (typeof finalPayload === "object" && finalPayload !== null && "snapshotId" in finalPayload && typeof finalPayload.snapshotId === "string" && "jobResultId" in finalPayload && finalPayload.jobResultId === payload.jobResultId)
|
|
2076
|
+
return finalPayload.snapshotId;
|
|
2077
|
+
}
|
|
2078
|
+
return payload.snapshotId;
|
|
2079
|
+
}
|
|
1931
2080
|
async syncParseResultToConfiguredStorage(result) {
|
|
1932
2081
|
const parsedStorageConfig = this.parsedStorageConfig;
|
|
1933
2082
|
if (!parsedStorageConfig) {
|
|
@@ -2163,7 +2312,7 @@ var Knowledge = class _Knowledge {
|
|
|
2163
2312
|
throw new Error(`Local Knowhere document not found: ${normalized.localDocumentId}`);
|
|
2164
2313
|
}
|
|
2165
2314
|
async readRemoteDocumentChunks(documentId, params) {
|
|
2166
|
-
const explicitRevisionKey = params.revisionKey ?? params.jobId;
|
|
2315
|
+
const explicitRevisionKey = params.revisionKey ?? params.jobId ?? await this.resolveStoredSnapshotKey(documentId);
|
|
2167
2316
|
if (explicitRevisionKey) {
|
|
2168
2317
|
const stored2 = await this.tryReadChunksFromParsedStorage({
|
|
2169
2318
|
documentId,
|
|
@@ -2173,6 +2322,8 @@ var Knowledge = class _Knowledge {
|
|
|
2173
2322
|
if (stored2) {
|
|
2174
2323
|
return stored2;
|
|
2175
2324
|
}
|
|
2325
|
+
if (params.revisionKey && await this.resolveStoredSnapshotKey(documentId))
|
|
2326
|
+
throw new ValidationError("Requested parsed snapshot is not committed locally");
|
|
2176
2327
|
}
|
|
2177
2328
|
if (hasScanReadFilters(params)) {
|
|
2178
2329
|
return this.scanRemoteDocumentChunks(documentId, params);
|
|
@@ -2185,6 +2336,8 @@ var Knowledge = class _Knowledge {
|
|
|
2185
2336
|
includeAssetUrls: true
|
|
2186
2337
|
});
|
|
2187
2338
|
const revisionKey = getRemoteRevisionKey(remotePage);
|
|
2339
|
+
if (params.revisionKey && params.revisionKey !== revisionKey)
|
|
2340
|
+
throw new ValidationError("Requested parsed snapshot revision is not committed locally");
|
|
2188
2341
|
const stored = await this.tryReadChunksFromParsedStorage({
|
|
2189
2342
|
documentId,
|
|
2190
2343
|
revisionKey,
|
|
@@ -2209,7 +2362,7 @@ var Knowledge = class _Knowledge {
|
|
|
2209
2362
|
};
|
|
2210
2363
|
}
|
|
2211
2364
|
async scanRemoteDocumentChunks(documentId, params) {
|
|
2212
|
-
const explicitRevisionKey = params.revisionKey ?? params.jobId;
|
|
2365
|
+
const explicitRevisionKey = params.revisionKey ?? params.jobId ?? await this.resolveStoredSnapshotKey(documentId);
|
|
2213
2366
|
if (explicitRevisionKey) {
|
|
2214
2367
|
const stored2 = await this.tryReadChunksFromParsedStorage({
|
|
2215
2368
|
documentId,
|
|
@@ -2219,6 +2372,8 @@ var Knowledge = class _Knowledge {
|
|
|
2219
2372
|
if (stored2) {
|
|
2220
2373
|
return stored2;
|
|
2221
2374
|
}
|
|
2375
|
+
if (params.revisionKey && await this.resolveStoredSnapshotKey(documentId))
|
|
2376
|
+
throw new ValidationError("Requested parsed snapshot is not committed locally");
|
|
2222
2377
|
}
|
|
2223
2378
|
const limit = clampLimit(params.limit, DEFAULT_READ_LIMIT, MAX_READ_LIMIT);
|
|
2224
2379
|
const limits = getParsedStorageLimits(this.parsedStorageConfig?.limits);
|
|
@@ -2229,6 +2384,8 @@ var Knowledge = class _Knowledge {
|
|
|
2229
2384
|
includeAssetUrls: true
|
|
2230
2385
|
});
|
|
2231
2386
|
const revisionKey = getRemoteRevisionKey(firstPage);
|
|
2387
|
+
if (params.revisionKey && params.revisionKey !== revisionKey)
|
|
2388
|
+
throw new ValidationError("Requested parsed snapshot revision is not committed locally");
|
|
2232
2389
|
const stored = await this.tryReadChunksFromParsedStorage({
|
|
2233
2390
|
documentId,
|
|
2234
2391
|
revisionKey,
|
|
@@ -2271,7 +2428,7 @@ var Knowledge = class _Knowledge {
|
|
|
2271
2428
|
};
|
|
2272
2429
|
}
|
|
2273
2430
|
async grepRemoteDocumentChunks(documentId, params) {
|
|
2274
|
-
const explicitRevisionKey = params.revisionKey ?? params.jobId;
|
|
2431
|
+
const explicitRevisionKey = params.revisionKey ?? params.jobId ?? await this.resolveStoredSnapshotKey(documentId);
|
|
2275
2432
|
if (explicitRevisionKey && !params.continuationCursor) {
|
|
2276
2433
|
const stored2 = await this.tryGrepChunksFromParsedStorage({
|
|
2277
2434
|
documentId,
|
|
@@ -2281,6 +2438,8 @@ var Knowledge = class _Knowledge {
|
|
|
2281
2438
|
if (stored2) {
|
|
2282
2439
|
return stored2;
|
|
2283
2440
|
}
|
|
2441
|
+
if (params.revisionKey && await this.resolveStoredSnapshotKey(documentId))
|
|
2442
|
+
throw new ValidationError("Requested parsed snapshot is not committed locally");
|
|
2284
2443
|
}
|
|
2285
2444
|
const maxResults = clampLimit(params.maxResults, DEFAULT_GREP_LIMIT, MAX_GREP_LIMIT);
|
|
2286
2445
|
const contextChars = params.contextChars ?? DEFAULT_CONTEXT_CHARS;
|
|
@@ -2295,6 +2454,8 @@ var Knowledge = class _Knowledge {
|
|
|
2295
2454
|
includeAssetUrls: true
|
|
2296
2455
|
});
|
|
2297
2456
|
const revisionKey = getRemoteRevisionKey(firstPage);
|
|
2457
|
+
if (params.revisionKey && params.revisionKey !== revisionKey)
|
|
2458
|
+
throw new ValidationError("Requested parsed snapshot revision is not committed locally");
|
|
2298
2459
|
const stored = startPage === 1 ? await this.tryGrepChunksFromParsedStorage({
|
|
2299
2460
|
documentId,
|
|
2300
2461
|
revisionKey,
|
|
@@ -2380,11 +2541,14 @@ var Knowledge = class _Knowledge {
|
|
|
2380
2541
|
}
|
|
2381
2542
|
}
|
|
2382
2543
|
async getRemoteDocumentOutline(documentId, revisionKeyOverride) {
|
|
2383
|
-
|
|
2384
|
-
|
|
2544
|
+
const storedRevisionKey = revisionKeyOverride ?? await this.resolveStoredSnapshotKey(documentId);
|
|
2545
|
+
if (storedRevisionKey) {
|
|
2546
|
+
const stored2 = await this.tryReadOutlineFromParsedStorage(documentId, storedRevisionKey);
|
|
2385
2547
|
if (stored2) {
|
|
2386
2548
|
return stored2;
|
|
2387
2549
|
}
|
|
2550
|
+
if (revisionKeyOverride && await this.resolveStoredSnapshotKey(documentId))
|
|
2551
|
+
throw new ValidationError("Requested parsed snapshot is not committed locally");
|
|
2388
2552
|
}
|
|
2389
2553
|
const limits = getParsedStorageLimits(this.parsedStorageConfig?.limits);
|
|
2390
2554
|
const firstPage = await this.client.documents.listChunks(documentId, {
|
|
@@ -2393,6 +2557,8 @@ var Knowledge = class _Knowledge {
|
|
|
2393
2557
|
includeAssetUrls: true
|
|
2394
2558
|
});
|
|
2395
2559
|
const revisionKey = getRemoteRevisionKey(firstPage);
|
|
2560
|
+
if (revisionKeyOverride && revisionKeyOverride !== revisionKey)
|
|
2561
|
+
throw new ValidationError("Requested parsed snapshot revision is not committed locally");
|
|
2396
2562
|
const stored = await this.tryReadOutlineFromParsedStorage(documentId, revisionKey);
|
|
2397
2563
|
if (stored) {
|
|
2398
2564
|
return stored;
|
|
@@ -2601,11 +2767,7 @@ var Knowledge = class _Knowledge {
|
|
|
2601
2767
|
const scheduler = parsedStorageConfig.scheduler ?? defaultParsedStorageScheduler;
|
|
2602
2768
|
const task = async () => {
|
|
2603
2769
|
try {
|
|
2604
|
-
await this.
|
|
2605
|
-
documentId,
|
|
2606
|
-
revisionKey,
|
|
2607
|
-
parsedStorageConfig
|
|
2608
|
-
});
|
|
2770
|
+
await this.syncParsedDocument({ documentId, revisionKey });
|
|
2609
2771
|
} catch (error) {
|
|
2610
2772
|
const previous = await parsedStorageConfig.storage.readSyncProgress({
|
|
2611
2773
|
documentId,
|
|
@@ -2631,14 +2793,25 @@ var Knowledge = class _Knowledge {
|
|
|
2631
2793
|
includeAssetUrls: true
|
|
2632
2794
|
});
|
|
2633
2795
|
const revisionKey = params.revisionKey ?? getRemoteRevisionKey(firstPage);
|
|
2634
|
-
if (params.revisionKey && getRemoteRevisionKey(firstPage) !== params.revisionKey) {
|
|
2635
|
-
throw new ValidationError("Published document revision changed before parsed snapshot sync");
|
|
2636
|
-
}
|
|
2637
2796
|
if (firstPage.jobId) {
|
|
2638
2797
|
const job = await this.client.jobs.get(firstPage.jobId).catch((error) => {
|
|
2639
2798
|
if (error instanceof NotFoundError) return null;
|
|
2640
2799
|
throw error;
|
|
2641
2800
|
});
|
|
2801
|
+
if (job?.snapshots?.length) {
|
|
2802
|
+
const snapshot = job.snapshots.find(
|
|
2803
|
+
(candidate) => candidate.snapshotId === (params.revisionKey ?? job.currentSnapshotId)
|
|
2804
|
+
);
|
|
2805
|
+
if (snapshot && snapshot.jobResultId !== getRemoteRevisionKey(firstPage))
|
|
2806
|
+
throw new ValidationError(
|
|
2807
|
+
"Parsed snapshot upstream revision differs from the published document"
|
|
2808
|
+
);
|
|
2809
|
+
return this.syncJobSnapshot({ ...params, job });
|
|
2810
|
+
}
|
|
2811
|
+
if (params.revisionKey && getRemoteRevisionKey(firstPage) !== params.revisionKey)
|
|
2812
|
+
throw new ValidationError(
|
|
2813
|
+
"Published document revision changed before parsed snapshot sync"
|
|
2814
|
+
);
|
|
2642
2815
|
if (job?.isDone && job.resultUrl) {
|
|
2643
2816
|
if (job.documentId && job.documentId !== params.documentId)
|
|
2644
2817
|
throw new ValidationError("Parsed job document identity differs from requested document");
|
|
@@ -3,9 +3,10 @@ import {
|
|
|
3
3
|
createDownloadIdentity,
|
|
4
4
|
isSnapshotPath,
|
|
5
5
|
normalizeResultPath
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-OCR7IDYL.mjs";
|
|
7
7
|
|
|
8
8
|
// src/storage/sequential-parsed-document-archive.ts
|
|
9
|
+
import { createHash } from "crypto";
|
|
9
10
|
import { Readable, Transform } from "stream";
|
|
10
11
|
import { pipeline } from "stream/promises";
|
|
11
12
|
import { mkdtemp, open, rm } from "fs/promises";
|
|
@@ -15,7 +16,10 @@ import { crc32 } from "zlib";
|
|
|
15
16
|
import { ZipReader, Reader } from "@zip.js/zip.js";
|
|
16
17
|
import Parse from "unzipper/lib/parse.js";
|
|
17
18
|
async function openSequentialArchive(params, identity, validateResponse) {
|
|
18
|
-
let response = await fetch(params.resultUrl, {
|
|
19
|
+
let response = await fetch(params.resultUrl, {
|
|
20
|
+
signal: params.signal,
|
|
21
|
+
headers: validateResponse ? { Range: "bytes=0-" } : void 0
|
|
22
|
+
});
|
|
19
23
|
if (!response.ok || !response.body)
|
|
20
24
|
throw new Error(`Parsed result download failed (HTTP ${response.status}).`);
|
|
21
25
|
if (validateResponse) response = validateResponse(response);
|
|
@@ -44,9 +48,11 @@ async function openSequentialArchive(params, identity, validateResponse) {
|
|
|
44
48
|
const parser = Parse({ forceStream: true });
|
|
45
49
|
const checksums = /* @__PURE__ */ new Map();
|
|
46
50
|
let archiveSize = 0;
|
|
51
|
+
const archiveHash = createHash("sha256");
|
|
47
52
|
const spool = new Transform({
|
|
48
53
|
transform(chunk, _encoding, callback) {
|
|
49
54
|
archiveSize += chunk.length;
|
|
55
|
+
archiveHash.update(chunk);
|
|
50
56
|
void file.writeFile(chunk).then(
|
|
51
57
|
() => {
|
|
52
58
|
callback(null, chunk);
|
|
@@ -63,6 +69,23 @@ async function openSequentialArchive(params, identity, validateResponse) {
|
|
|
63
69
|
identity,
|
|
64
70
|
downloadIdentity: identity,
|
|
65
71
|
canSkipEntries: false,
|
|
72
|
+
readArchive: () => {
|
|
73
|
+
let position = 0;
|
|
74
|
+
return new ReadableStream({
|
|
75
|
+
async pull(controller) {
|
|
76
|
+
params.signal?.throwIfAborted();
|
|
77
|
+
if (position >= archiveSize) {
|
|
78
|
+
controller.close();
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const body2 = new Uint8Array(Math.min(65536, archiveSize - position));
|
|
82
|
+
const { bytesRead } = await file.read(body2, 0, body2.length, position);
|
|
83
|
+
if (bytesRead !== body2.length) throw new Error("Truncated verified archive spool.");
|
|
84
|
+
position += bytesRead;
|
|
85
|
+
controller.enqueue(body2);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
},
|
|
66
89
|
entries: (async function* () {
|
|
67
90
|
for await (const value of parser) {
|
|
68
91
|
const entry = value;
|
|
@@ -93,6 +116,8 @@ async function openSequentialArchive(params, identity, validateResponse) {
|
|
|
93
116
|
};
|
|
94
117
|
}
|
|
95
118
|
await completed;
|
|
119
|
+
if (params.snapshot && archiveHash.digest("hex") !== params.snapshot.checksum)
|
|
120
|
+
throw new Error("Parsed snapshot archive checksum mismatch for extracted bytes.");
|
|
96
121
|
const reader = new ZipReader(new DiskArchiveReader(file, archiveSize), {
|
|
97
122
|
useWebWorkers: false
|
|
98
123
|
});
|