@ontos-ai/knowhere-sdk 2.1.1 → 2.1.3

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/index.mjs CHANGED
@@ -1527,10 +1527,6 @@ import JSZip2 from "jszip";
1527
1527
  var pageCitationAssetsMetadataKey = "pageAssets";
1528
1528
  var defaultImageContentType = "application/octet-stream";
1529
1529
  var tableContentType = "text/html; charset=utf-8";
1530
- var snapshotManifestKey = "manifest/current.json";
1531
- var snapshotIndexKey = "index.json";
1532
- var defaultSnapshotChunkPageSize = 200;
1533
- var snapshotJsonContentType = "application/json; charset=utf-8";
1534
1530
  async function storeParseResultAssets(result, options) {
1535
1531
  if (!options) {
1536
1532
  return {
@@ -1548,148 +1544,11 @@ async function storeParseResultAssets(result, options) {
1548
1544
  }
1549
1545
  }
1550
1546
  const normalizedResult = Object.keys(assetUrlsByFilePath).length === 0 ? result : rewriteResultAssetUrls(result, assetUrlsByFilePath);
1551
- const snapshot = await storeParsedSnapshot({
1552
- result: normalizedResult,
1553
- assetUrlsByFilePath,
1554
- keyPrefix: normalizedKeyPrefix,
1555
- options
1556
- });
1557
1547
  return {
1558
1548
  result: normalizedResult,
1559
- assetUrlsByFilePath,
1560
- snapshot
1561
- };
1562
- }
1563
- async function storeParsedSnapshot(input) {
1564
- const pageSize = normalizeSnapshotChunkPageSize(input.options.chunkPageSize);
1565
- const totalChunks = input.result.chunks.length;
1566
- const totalPages = Math.max(1, Math.ceil(totalChunks / pageSize));
1567
- const chunkPageReferences = [];
1568
- const chunkPageUrlsByPage = {};
1569
- for (let page = 1; page <= totalPages; page += 1) {
1570
- const pageChunks = input.result.chunks.slice((page - 1) * pageSize, page * pageSize);
1571
- const pageKey = `${input.keyPrefix}/chunks/page-${page}.json`;
1572
- const chunkPage = {
1573
- version: 1,
1574
- jobId: input.result.jobId,
1575
- revisionKey: input.options.revisionKey ?? input.result.jobId,
1576
- documentId: input.result.documentId,
1577
- namespace: input.result.namespace,
1578
- sourceFileName: input.result.manifest.sourceFileName,
1579
- page,
1580
- pageSize,
1581
- total: totalChunks,
1582
- totalPages,
1583
- chunks: pageChunks.map(
1584
- (chunk, index) => toSnapshotChunk(chunk, (page - 1) * pageSize + index + 1)
1585
- )
1586
- };
1587
- const pageUrl = await writeJsonObject({
1588
- key: pageKey,
1589
- value: chunkPage,
1590
- adapter: input.options.adapter
1591
- });
1592
- if (pageUrl) chunkPageUrlsByPage[page] = pageUrl;
1593
- chunkPageReferences.push({
1594
- page,
1595
- pageSize,
1596
- chunkCount: pageChunks.length,
1597
- key: pageKey,
1598
- url: pageUrl
1599
- });
1600
- }
1601
- const manifest = {
1602
- version: 1,
1603
- kind: "knowhere-parsed-result-snapshot",
1604
- jobId: input.result.jobId,
1605
- revisionKey: input.options.revisionKey ?? input.result.jobId,
1606
- documentId: input.result.documentId,
1607
- namespace: input.result.namespace,
1608
- sourceFileName: input.result.manifest.sourceFileName,
1609
- totalChunks,
1610
- typeCounts: countSnapshotChunkTypes(input.result.chunks),
1611
- chunkPageSize: pageSize,
1612
- chunkPages: chunkPageReferences,
1613
- assetUrlsByFilePath: input.assetUrlsByFilePath,
1614
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
1615
- };
1616
- const manifestKey = `${input.keyPrefix}/${snapshotManifestKey}`;
1617
- const indexKey = `${input.keyPrefix}/${snapshotIndexKey}`;
1618
- const manifestUrl = await writeJsonObject({
1619
- key: manifestKey,
1620
- value: manifest,
1621
- adapter: input.options.adapter
1622
- });
1623
- const indexUrl = await writeJsonObject({
1624
- key: indexKey,
1625
- value: manifest,
1626
- adapter: input.options.adapter
1627
- });
1628
- return {
1629
- manifest,
1630
- manifestKey,
1631
- manifestUrl,
1632
- indexKey,
1633
- indexUrl,
1634
- chunkPageUrlsByPage
1635
- };
1636
- }
1637
- function countSnapshotChunkTypes(chunks) {
1638
- return chunks.reduce(
1639
- (counts, chunk) => {
1640
- counts[chunk.type] += 1;
1641
- return counts;
1642
- },
1643
- { text: 0, image: 0, table: 0, page: 0 }
1644
- );
1645
- }
1646
- async function writeJsonObject(input) {
1647
- const result = await input.adapter.writeObject({
1648
- key: input.key,
1649
- body: Buffer.from(JSON.stringify(input.value, null, 2), "utf8"),
1650
- contentType: snapshotJsonContentType,
1651
- metadata: {
1652
- kind: "knowhere-parsed-result-snapshot"
1653
- }
1654
- });
1655
- return result.url ?? await input.adapter.getObjectUrl?.(result.key) ?? void 0;
1656
- }
1657
- function normalizeSnapshotChunkPageSize(value) {
1658
- if (!Number.isInteger(value) || value === void 0) return defaultSnapshotChunkPageSize;
1659
- return Math.min(Math.max(value, 1), 1e3);
1660
- }
1661
- function toSnapshotChunk(chunk, position) {
1662
- const filePath = getSnapshotChunkFilePath(chunk);
1663
- return {
1664
- id: chunk.chunkId,
1665
- chunkId: chunk.chunkId,
1666
- chunkType: chunk.type,
1667
- contentSource: chunk.contentSource,
1668
- content: chunk.content,
1669
- sectionPath: normalizeSnapshotSectionPath(chunk.path),
1670
- sourceChunkPath: chunk.path,
1671
- filePath,
1672
- sortOrder: position,
1673
- metadata: cloneChunkMetadata(chunk.metadata),
1674
- assetUrl: getSnapshotChunkAssetUrl(chunk)
1549
+ assetUrlsByFilePath
1675
1550
  };
1676
1551
  }
1677
- function normalizeSnapshotSectionPath(path4) {
1678
- return path4.length > 0 ? path4 : void 0;
1679
- }
1680
- function getSnapshotChunkFilePath(chunk) {
1681
- if (chunk.type === "image" || chunk.type === "table") {
1682
- return chunk.filePath;
1683
- }
1684
- const filePath = chunk.metadata.filePath;
1685
- return typeof filePath === "string" ? filePath : void 0;
1686
- }
1687
- function getSnapshotChunkAssetUrl(chunk) {
1688
- return chunk.type === "image" || chunk.type === "table" ? chunk.assetUrl : void 0;
1689
- }
1690
- function cloneChunkMetadata(metadata) {
1691
- return { ...metadata };
1692
- }
1693
1552
  async function collectStorageAssets(result, keyPrefix) {
1694
1553
  const resultZip = await loadResultZipForPageCitationAssets(result);
1695
1554
  return [
@@ -1926,108 +1785,212 @@ function isRecord(value) {
1926
1785
  }
1927
1786
 
1928
1787
  // src/storage/parsed-document-storage.ts
1929
- var parsedStorageKeyPrefix = "parsed";
1930
- var manifestStoragePath = "manifest/current.json";
1931
- var indexStoragePath = "index.json";
1932
- var chunkPagePathPattern = /^chunks\/page-(\d+)\.json$/;
1788
+ import JSZip3 from "jszip";
1789
+ var parsedDocumentCommitPath = ".knowhere-sdk/commit.json";
1790
+ var jsonContentType = "application/json; charset=utf-8";
1791
+ var markdownContentType = "text/markdown; charset=utf-8";
1792
+ var csvContentType = "text/csv; charset=utf-8";
1793
+ var htmlContentType = "text/html; charset=utf-8";
1794
+ var binaryContentType = "application/octet-stream";
1933
1795
  async function syncParseResultToParsedDocumentStorage(params) {
1934
1796
  const documentId = params.documentId ?? params.result.documentId ?? params.result.jobId;
1935
1797
  const revisionKey = params.revisionKey ?? params.result.jobId;
1936
- const adapter = createParsedDocumentObjectStorageAdapter({
1937
- storage: params.storage,
1798
+ const objects = await collectResultLayoutObjects(params.result);
1799
+ for (const object of objects) {
1800
+ await params.storage.writeObject({
1801
+ documentId,
1802
+ revisionKey,
1803
+ ...object
1804
+ });
1805
+ }
1806
+ const commit = {
1807
+ version: 1,
1938
1808
  documentId,
1939
- revisionKey
1940
- });
1941
- const stored = await storeParseResultAssets(params.result, {
1942
- adapter,
1943
- keyPrefix: parsedStorageKeyPrefix,
1944
- chunkPageSize: params.chunkPageSize,
1945
- revisionKey
1809
+ revisionKey,
1810
+ source: params.source ?? "resultZip",
1811
+ committedAt: (/* @__PURE__ */ new Date()).toISOString()
1812
+ };
1813
+ await writeParsedDocumentJsonObject(params.storage, {
1814
+ documentId,
1815
+ revisionKey,
1816
+ path: parsedDocumentCommitPath,
1817
+ value: commit
1946
1818
  });
1947
1819
  return {
1948
- result: stored.result,
1949
- snapshot: stored.snapshot,
1820
+ result: params.result,
1950
1821
  documentId,
1951
- revisionKey
1822
+ revisionKey,
1823
+ commit
1952
1824
  };
1953
1825
  }
1954
- function createParsedDocumentObjectStorageAdapter(params) {
1955
- return {
1956
- writeObject: (input) => writeParsedStorageObject(params, input),
1957
- headObject: (key) => headParsedStorageObject(params, key),
1958
- getObjectUrl: (key) => getParsedStorageObjectUrl(params, key)
1959
- };
1826
+ async function readParsedDocumentCommit(params) {
1827
+ const object = await params.storage.readObject({
1828
+ documentId: params.documentId,
1829
+ revisionKey: params.revisionKey,
1830
+ path: parsedDocumentCommitPath
1831
+ });
1832
+ if (!object) {
1833
+ return null;
1834
+ }
1835
+ const commit = readJsonObject(object);
1836
+ return commit.revisionKey === params.revisionKey && commit.documentId === params.documentId ? commit : null;
1960
1837
  }
1961
- async function writeParsedStorageObject(params, input) {
1962
- const storagePath = stripParsedStorageKeyPrefix(input.key);
1963
- if (storagePath === manifestStoragePath) {
1964
- const manifest = JSON.parse(
1965
- Buffer.from(input.body).toString("utf8")
1966
- );
1967
- await params.storage.writeManifest({
1968
- documentId: params.documentId,
1969
- revisionKey: params.revisionKey,
1970
- manifest
1971
- });
1972
- return { key: input.key };
1838
+ function readJsonObject(object) {
1839
+ return JSON.parse(Buffer.from(object.body).toString("utf8"));
1840
+ }
1841
+ async function collectResultLayoutObjects(result) {
1842
+ const objectsByPath = /* @__PURE__ */ new Map();
1843
+ const rawZipObjects = await collectRawZipObjects(result.rawZip);
1844
+ for (const object of rawZipObjects) {
1845
+ objectsByPath.set(object.path, object);
1846
+ }
1847
+ for (const object of collectGeneratedResultObjects(result)) {
1848
+ if (!objectsByPath.has(object.path)) {
1849
+ objectsByPath.set(object.path, object);
1850
+ }
1851
+ }
1852
+ return [...objectsByPath.values()].filter((object) => !isSdkMetadataPath(object.path));
1853
+ }
1854
+ async function collectRawZipObjects(rawZip) {
1855
+ try {
1856
+ const zip = await JSZip3.loadAsync(rawZip);
1857
+ const objects = [];
1858
+ for (const entry of Object.values(zip.files)) {
1859
+ if (entry.dir || entry.name === "result.zip") {
1860
+ continue;
1861
+ }
1862
+ objects.push({
1863
+ path: normalizeResultPath(entry.name),
1864
+ body: new Uint8Array(await entry.async("nodebuffer")),
1865
+ contentType: inferContentTypeFromPath(entry.name)
1866
+ });
1867
+ }
1868
+ return objects;
1869
+ } catch {
1870
+ return [];
1973
1871
  }
1974
- if (storagePath === indexStoragePath) {
1975
- return { key: input.key };
1872
+ }
1873
+ function collectGeneratedResultObjects(result) {
1874
+ const objects = [
1875
+ createJsonObject("manifest.json", result.manifest),
1876
+ createJsonObject("chunks.json", keysToSnake(serializeChunks2(result.chunks)))
1877
+ ];
1878
+ if (result.docNav) {
1879
+ objects.push(createJsonObject("doc_nav.json", result.docNav));
1880
+ }
1881
+ if (result.fullMarkdown) {
1882
+ objects.push(createTextObject("full.md", result.fullMarkdown, markdownContentType));
1883
+ }
1884
+ if (result.chunksSlim) {
1885
+ objects.push(createJsonObject("chunks_slim.json", { chunks: result.chunksSlim }));
1886
+ }
1887
+ if (result.hierarchy) {
1888
+ objects.push(createJsonObject("hierarchy.json", result.hierarchy));
1889
+ }
1890
+ if (result.tocHierarchies) {
1891
+ objects.push(createJsonObject("toc_hierarchies.json", result.tocHierarchies));
1892
+ }
1893
+ if (result.kbCsv) {
1894
+ objects.push(createTextObject("kb.csv", result.kbCsv, csvContentType));
1976
1895
  }
1977
- const chunkPageMatch = storagePath.match(chunkPagePathPattern);
1978
- if (chunkPageMatch) {
1979
- const page = JSON.parse(
1980
- Buffer.from(input.body).toString("utf8")
1896
+ if (result.hierarchyViewHtml) {
1897
+ objects.push(
1898
+ createTextObject("hierarchy_view.html", result.hierarchyViewHtml, htmlContentType)
1981
1899
  );
1982
- await params.storage.writeChunkPage({
1983
- documentId: params.documentId,
1984
- revisionKey: params.revisionKey,
1985
- page
1900
+ }
1901
+ for (const chunk of result.imageChunks) {
1902
+ objects.push({
1903
+ path: normalizeResultPath(chunk.filePath),
1904
+ body: new Uint8Array(chunk.data),
1905
+ contentType: inferContentTypeFromPath(chunk.filePath),
1906
+ metadata: {
1907
+ chunkId: chunk.chunkId,
1908
+ chunkType: chunk.type,
1909
+ sourcePath: chunk.filePath
1910
+ }
1986
1911
  });
1987
- return { key: input.key };
1988
1912
  }
1989
- const stored = await params.storage.writeAsset({
1990
- documentId: params.documentId,
1991
- revisionKey: params.revisionKey,
1992
- sourcePath: storagePath,
1993
- body: input.body,
1994
- contentType: input.contentType,
1995
- metadata: input.metadata
1996
- });
1913
+ for (const chunk of result.tableChunks) {
1914
+ objects.push({
1915
+ path: normalizeResultPath(chunk.filePath),
1916
+ body: Buffer.from(chunk.html, "utf8"),
1917
+ contentType: htmlContentType,
1918
+ metadata: {
1919
+ chunkId: chunk.chunkId,
1920
+ chunkType: chunk.type,
1921
+ sourcePath: chunk.filePath
1922
+ }
1923
+ });
1924
+ }
1925
+ return objects;
1926
+ }
1927
+ function serializeChunks2(chunks) {
1997
1928
  return {
1998
- key: input.key,
1999
- url: stored.url
1929
+ chunks: chunks.map((chunk) => {
1930
+ const rawChunk = {
1931
+ chunkId: chunk.chunkId,
1932
+ type: chunk.type,
1933
+ contentSource: chunk.contentSource,
1934
+ content: chunk.content,
1935
+ path: chunk.path,
1936
+ metadata: chunk.metadata
1937
+ };
1938
+ if (chunk.type === "image" || chunk.type === "table") {
1939
+ return {
1940
+ ...rawChunk,
1941
+ filePath: chunk.filePath,
1942
+ assetUrl: chunk.assetUrl
1943
+ };
1944
+ }
1945
+ return rawChunk;
1946
+ })
2000
1947
  };
2001
1948
  }
2002
- async function headParsedStorageObject(params, key) {
2003
- const storagePath = stripParsedStorageKeyPrefix(key);
2004
- if (storagePath === manifestStoragePath || storagePath === indexStoragePath || chunkPagePathPattern.test(storagePath)) {
2005
- return null;
2006
- }
2007
- const url = await params.storage.getAssetUrl({
1949
+ async function writeParsedDocumentJsonObject(storage, params) {
1950
+ await storage.writeObject({
2008
1951
  documentId: params.documentId,
2009
1952
  revisionKey: params.revisionKey,
2010
- sourcePath: storagePath
1953
+ path: params.path,
1954
+ body: Buffer.from(JSON.stringify(params.value, null, 2), "utf8"),
1955
+ contentType: jsonContentType
2011
1956
  });
2012
- return url ? {
2013
- key,
2014
- url
2015
- } : null;
2016
- }
2017
- async function getParsedStorageObjectUrl(params, key) {
2018
- const storagePath = stripParsedStorageKeyPrefix(key);
2019
- if (storagePath === manifestStoragePath || storagePath === indexStoragePath || chunkPagePathPattern.test(storagePath)) {
2020
- return null;
1957
+ }
1958
+ function createJsonObject(path4, value) {
1959
+ return {
1960
+ path: path4,
1961
+ body: Buffer.from(JSON.stringify(value, null, 2), "utf8"),
1962
+ contentType: jsonContentType
1963
+ };
1964
+ }
1965
+ function createTextObject(path4, value, contentType) {
1966
+ return {
1967
+ path: path4,
1968
+ body: Buffer.from(value, "utf8"),
1969
+ contentType
1970
+ };
1971
+ }
1972
+ function inferContentTypeFromPath(filePath) {
1973
+ const lower = filePath.toLowerCase();
1974
+ if (lower.endsWith(".json")) return jsonContentType;
1975
+ if (lower.endsWith(".md")) return markdownContentType;
1976
+ if (lower.endsWith(".csv")) return csvContentType;
1977
+ if (lower.endsWith(".html") || lower.endsWith(".htm")) return htmlContentType;
1978
+ if (lower.endsWith(".png")) return "image/png";
1979
+ if (lower.endsWith(".jpg") || lower.endsWith(".jpeg")) return "image/jpeg";
1980
+ if (lower.endsWith(".gif")) return "image/gif";
1981
+ if (lower.endsWith(".webp")) return "image/webp";
1982
+ if (lower.endsWith(".svg")) return "image/svg+xml";
1983
+ return binaryContentType;
1984
+ }
1985
+ function normalizeResultPath(value) {
1986
+ const normalized = value.replaceAll("\\", "/").replace(/^\.\/+/, "");
1987
+ if (normalized.length === 0 || normalized.includes("\0") || normalized.startsWith("/") || normalized.split("/").some((part) => part.length === 0 || part === "." || part === "..")) {
1988
+ throw new Error(`Invalid parsed result path: ${value}`);
2021
1989
  }
2022
- return params.storage.getAssetUrl({
2023
- documentId: params.documentId,
2024
- revisionKey: params.revisionKey,
2025
- sourcePath: storagePath
2026
- });
1990
+ return normalized;
2027
1991
  }
2028
- function stripParsedStorageKeyPrefix(key) {
2029
- const prefix = `${parsedStorageKeyPrefix}/`;
2030
- return key.startsWith(prefix) ? key.slice(prefix.length) : key;
1992
+ function isSdkMetadataPath(path4) {
1993
+ return path4 === ".knowhere-sdk" || path4.startsWith(".knowhere-sdk/");
2031
1994
  }
2032
1995
 
2033
1996
  // src/knowledge/local-store.ts
@@ -2262,7 +2225,6 @@ var MAX_GREP_LIMIT = 50;
2262
2225
  var DEFAULT_CONTEXT_CHARS = 80;
2263
2226
  var DEFAULT_REMOTE_SCAN_PAGE_SIZE = 100;
2264
2227
  var DEFAULT_MAX_SYNC_PAGES = 10;
2265
- var DEFAULT_MAX_SYNC_ASSETS = 20;
2266
2228
  var DEFAULT_SYNC_DEADLINE_MS = 8e3;
2267
2229
  var DEFAULT_GREP_MAX_PAGES = 50;
2268
2230
  var DEFAULT_GREP_DEADLINE_MS = 8e3;
@@ -2270,6 +2232,7 @@ var DEFAULT_OUTLINE_MAX_PAGES = 50;
2270
2232
  var DEFAULT_OUTLINE_DEADLINE_MS = 8e3;
2271
2233
  var SAFE_LOCAL_DOCUMENT_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
2272
2234
  var REMOTE_DOCUMENT_ID_PATTERN = /^doc[_-]/;
2235
+ var remoteReconstructionPageDirectory = ".knowhere-sdk/remote-reconstruction/pages";
2273
2236
  var Knowledge = class _Knowledge {
2274
2237
  client;
2275
2238
  store;
@@ -2304,8 +2267,7 @@ var Knowledge = class _Knowledge {
2304
2267
  return {
2305
2268
  document,
2306
2269
  result,
2307
- assetUrlsByFilePath: storedAssets.assetUrlsByFilePath,
2308
- parsedSnapshot: storedAssets.snapshot
2270
+ assetUrlsByFilePath: storedAssets.assetUrlsByFilePath
2309
2271
  };
2310
2272
  }
2311
2273
  /** @deprecated Use parseToLocalCache for local cache imports or the top-level client.parse for server-safe parsing. */
@@ -2350,8 +2312,7 @@ var Knowledge = class _Knowledge {
2350
2312
  const result = syncedStorage.result;
2351
2313
  return {
2352
2314
  result,
2353
- assetUrlsByFilePath: storedAssets.assetUrlsByFilePath,
2354
- parsedSnapshot: syncedStorage.snapshot ?? storedAssets.snapshot
2315
+ assetUrlsByFilePath: storedAssets.assetUrlsByFilePath
2355
2316
  };
2356
2317
  }
2357
2318
  async importJobResult(params) {
@@ -2363,8 +2324,7 @@ var Knowledge = class _Knowledge {
2363
2324
  return {
2364
2325
  document,
2365
2326
  result,
2366
- assetUrlsByFilePath: stored.assetUrlsByFilePath,
2367
- parsedSnapshot: stored.parsedSnapshot
2327
+ assetUrlsByFilePath: stored.assetUrlsByFilePath
2368
2328
  };
2369
2329
  }
2370
2330
  /** @deprecated Use importJobResult for local cache imports or loadJobResult for server-safe loads. */
@@ -2387,14 +2347,13 @@ var Knowledge = class _Knowledge {
2387
2347
  result: loadedResult,
2388
2348
  storage: parsedStorageConfig.storage,
2389
2349
  documentId: loadedResult.documentId ?? normalized.localDocumentId ?? normalized.jobId,
2390
- revisionKey: params.revisionKey ?? normalized.jobId,
2391
- chunkPageSize: parsedStorageConfig.limits?.chunkPageSize
2350
+ revisionKey: params.revisionKey ?? normalized.jobId
2392
2351
  });
2393
2352
  return {
2394
2353
  documentId: synced2.documentId,
2395
2354
  revisionKey: synced2.revisionKey,
2396
2355
  completed: true,
2397
- manifest: synced2.snapshot?.manifest
2356
+ commit: synced2.commit
2398
2357
  };
2399
2358
  }
2400
2359
  if (!normalized.localDocumentId) {
@@ -2405,14 +2364,13 @@ var Knowledge = class _Knowledge {
2405
2364
  result,
2406
2365
  storage: parsedStorageConfig.storage,
2407
2366
  documentId: result.documentId ?? normalized.localDocumentId,
2408
- revisionKey: params.revisionKey ?? result.jobId,
2409
- chunkPageSize: parsedStorageConfig.limits?.chunkPageSize
2367
+ revisionKey: params.revisionKey ?? result.jobId
2410
2368
  });
2411
2369
  return {
2412
2370
  documentId: synced.documentId,
2413
2371
  revisionKey: synced.revisionKey,
2414
2372
  completed: true,
2415
- manifest: synced.snapshot?.manifest
2373
+ commit: synced.commit
2416
2374
  };
2417
2375
  }
2418
2376
  async syncParseResultToConfiguredStorage(result) {
@@ -2422,12 +2380,11 @@ var Knowledge = class _Knowledge {
2422
2380
  }
2423
2381
  const synced = await syncParseResultToParsedDocumentStorage({
2424
2382
  result,
2425
- storage: parsedStorageConfig.storage,
2426
- chunkPageSize: parsedStorageConfig.limits?.chunkPageSize
2383
+ storage: parsedStorageConfig.storage
2427
2384
  });
2428
2385
  return {
2429
2386
  result: synced.result,
2430
- snapshot: synced.snapshot
2387
+ commit: synced.commit
2431
2388
  };
2432
2389
  }
2433
2390
  async parseWithoutClientStorageAdapter(params) {
@@ -2678,10 +2635,7 @@ var Knowledge = class _Knowledge {
2678
2635
  page: pageParams.page,
2679
2636
  pageSize: pageParams.pageSize,
2680
2637
  chunkType: params.chunkType,
2681
- includeAssetUrls: shouldRequestRemoteAssetUrls(
2682
- params.assetUrlPolicy,
2683
- this.parsedStorageConfig
2684
- )
2638
+ includeAssetUrls: true
2685
2639
  });
2686
2640
  const revisionKey = getRemoteRevisionKey(remotePage);
2687
2641
  const stored = await this.tryReadChunksFromParsedStorage({
@@ -2692,12 +2646,7 @@ var Knowledge = class _Knowledge {
2692
2646
  if (stored) {
2693
2647
  return stored;
2694
2648
  }
2695
- const chunks = await this.toRemoteReadChunks({
2696
- documentId,
2697
- revisionKey,
2698
- chunks: remotePage.chunks,
2699
- assetUrlPolicy: params.assetUrlPolicy
2700
- });
2649
+ const chunks = remotePage.chunks.map((chunk) => toRemoteReadChunk(chunk));
2701
2650
  this.scheduleParsedStorageSync(documentId, revisionKey);
2702
2651
  return {
2703
2652
  document: createRemoteKnowledgeDocument({
@@ -2730,10 +2679,7 @@ var Knowledge = class _Knowledge {
2730
2679
  page: 1,
2731
2680
  pageSize: limits.remotePageSize,
2732
2681
  chunkType: params.chunkType,
2733
- includeAssetUrls: shouldRequestRemoteAssetUrls(
2734
- params.assetUrlPolicy,
2735
- this.parsedStorageConfig
2736
- )
2682
+ includeAssetUrls: true
2737
2683
  });
2738
2684
  const revisionKey = getRemoteRevisionKey(firstPage);
2739
2685
  const stored = await this.tryReadChunksFromParsedStorage({
@@ -2760,18 +2706,10 @@ var Knowledge = class _Knowledge {
2760
2706
  page,
2761
2707
  pageSize: limits.remotePageSize,
2762
2708
  chunkType: params.chunkType,
2763
- includeAssetUrls: shouldRequestRemoteAssetUrls(
2764
- params.assetUrlPolicy,
2765
- this.parsedStorageConfig
2766
- )
2709
+ includeAssetUrls: true
2767
2710
  });
2768
2711
  }
2769
- const chunks = await this.toRemoteReadChunks({
2770
- documentId,
2771
- revisionKey,
2772
- chunks: selected.slice(0, limit),
2773
- assetUrlPolicy: params.assetUrlPolicy
2774
- });
2712
+ const chunks = selected.slice(0, limit).map((chunk) => toRemoteReadChunk(chunk));
2775
2713
  this.scheduleParsedStorageSync(documentId, revisionKey);
2776
2714
  return {
2777
2715
  document: createRemoteKnowledgeDocument({
@@ -2807,7 +2745,7 @@ var Knowledge = class _Knowledge {
2807
2745
  page: startPage,
2808
2746
  pageSize: limits.remotePageSize,
2809
2747
  chunkType: params.chunkType,
2810
- includeAssetUrls: false
2748
+ includeAssetUrls: true
2811
2749
  });
2812
2750
  const revisionKey = getRemoteRevisionKey(firstPage);
2813
2751
  const stored = startPage === 1 ? await this.tryGrepChunksFromParsedStorage({
@@ -2904,7 +2842,7 @@ var Knowledge = class _Knowledge {
2904
2842
  page,
2905
2843
  pageSize: limits.remotePageSize,
2906
2844
  chunkType: params.chunkType,
2907
- includeAssetUrls: false
2845
+ includeAssetUrls: true
2908
2846
  });
2909
2847
  }
2910
2848
  }
@@ -2919,7 +2857,7 @@ var Knowledge = class _Knowledge {
2919
2857
  const firstPage = await this.client.documents.listChunks(documentId, {
2920
2858
  page: 1,
2921
2859
  pageSize: limits.remotePageSize,
2922
- includeAssetUrls: false
2860
+ includeAssetUrls: true
2923
2861
  });
2924
2862
  const revisionKey = getRemoteRevisionKey(firstPage);
2925
2863
  const stored = await this.tryReadOutlineFromParsedStorage(documentId, revisionKey);
@@ -2941,7 +2879,7 @@ var Knowledge = class _Knowledge {
2941
2879
  response = await this.client.documents.listChunks(documentId, {
2942
2880
  page,
2943
2881
  pageSize: limits.remotePageSize,
2944
- includeAssetUrls: false
2882
+ includeAssetUrls: true
2945
2883
  });
2946
2884
  }
2947
2885
  const truncated = response.pagination.page < response.pagination.totalPages;
@@ -2967,28 +2905,13 @@ var Knowledge = class _Knowledge {
2967
2905
  };
2968
2906
  }
2969
2907
  async tryReadChunksFromParsedStorage(params) {
2970
- const parsedStorageConfig = this.parsedStorageConfig;
2971
- if (!parsedStorageConfig) {
2972
- return null;
2973
- }
2974
- const manifest = await this.readFreshParsedStorageManifest(
2908
+ const storedResult = await this.readCommittedParsedStorageResult(
2975
2909
  params.documentId,
2976
2910
  params.revisionKey
2977
2911
  );
2978
- if (!manifest) {
2979
- return null;
2980
- }
2912
+ if (!storedResult) return null;
2981
2913
  const pageParams = getReadPageParams(params.params);
2982
- const indexedChunks = await this.readStoredSnapshotChunks({
2983
- documentId: params.documentId,
2984
- revisionKey: params.revisionKey,
2985
- manifest,
2986
- chunkType: params.params.chunkType
2987
- });
2988
- if (!indexedChunks) {
2989
- return null;
2990
- }
2991
- const scopedChunks = indexedChunks.filter((chunk) => matchesReadScope(chunk, params.params));
2914
+ const scopedChunks = storedResult.chunks.filter((chunk) => !params.params.chunkType || chunk.chunkType === params.params.chunkType).filter((chunk) => matchesReadScope(chunk, params.params));
2992
2915
  const selected = hasScanReadFilters(params.params) ? selectReadWindow(
2993
2916
  scopedChunks,
2994
2917
  params.params,
@@ -2997,17 +2920,18 @@ var Knowledge = class _Knowledge {
2997
2920
  (pageParams.page - 1) * pageParams.pageSize,
2998
2921
  pageParams.page * pageParams.pageSize
2999
2922
  );
3000
- const visibleChunks = applyAssetUrlPolicyToReadChunks(
3001
- selected.map(toReadChunk),
3002
- params.params.assetUrlPolicy
3003
- );
2923
+ const visibleChunks = await applyStoredAssetUrlsToReadChunks({
2924
+ storageConfig: this.requireParsedStorageConfig(),
2925
+ documentId: params.documentId,
2926
+ revisionKey: params.revisionKey,
2927
+ chunks: selected.map(toReadChunk)
2928
+ });
3004
2929
  const totalChunks = scopedChunks.length;
3005
2930
  return {
3006
2931
  document: createStoredKnowledgeDocument({
3007
2932
  documentId: params.documentId,
3008
- manifest,
3009
- revisionKey: params.revisionKey,
3010
- typeCounts: countIndexedTypes(indexedChunks)
2933
+ storedResult,
2934
+ revisionKey: params.revisionKey
3011
2935
  }),
3012
2936
  chunks: visibleChunks,
3013
2937
  page: hasScanReadFilters(params.params) ? void 0 : pageParams.page,
@@ -3018,30 +2942,15 @@ var Knowledge = class _Knowledge {
3018
2942
  };
3019
2943
  }
3020
2944
  async tryGrepChunksFromParsedStorage(params) {
3021
- const parsedStorageConfig = this.parsedStorageConfig;
3022
- if (!parsedStorageConfig) {
3023
- return null;
3024
- }
3025
- const manifest = await this.readFreshParsedStorageManifest(
2945
+ const storedResult = await this.readCommittedParsedStorageResult(
3026
2946
  params.documentId,
3027
2947
  params.revisionKey
3028
2948
  );
3029
- if (!manifest) {
3030
- return null;
3031
- }
3032
- const indexedChunks = await this.readStoredSnapshotChunks({
3033
- documentId: params.documentId,
3034
- revisionKey: params.revisionKey,
3035
- manifest,
3036
- chunkType: params.params.chunkType
3037
- });
3038
- if (!indexedChunks) {
3039
- return null;
3040
- }
2949
+ if (!storedResult) return null;
3041
2950
  const maxResults = clampLimit(params.params.maxResults, DEFAULT_GREP_LIMIT, MAX_GREP_LIMIT);
3042
2951
  const contextChars = params.params.contextChars ?? DEFAULT_CONTEXT_CHARS;
3043
2952
  const matcher = createMatcher(params.params);
3044
- const scopedChunks = indexedChunks.filter((chunk) => matchesGrepScope(chunk, params.params));
2953
+ const scopedChunks = storedResult.chunks.filter((chunk) => !params.params.chunkType || chunk.chunkType === params.params.chunkType).filter((chunk) => matchesGrepScope(chunk, params.params));
3045
2954
  const matches = [];
3046
2955
  let scannedChunks = 0;
3047
2956
  for (const chunk of scopedChunks) {
@@ -3062,9 +2971,8 @@ var Knowledge = class _Knowledge {
3062
2971
  return {
3063
2972
  document: createStoredKnowledgeDocument({
3064
2973
  documentId: params.documentId,
3065
- manifest,
3066
- revisionKey: params.revisionKey,
3067
- typeCounts: countIndexedTypes(indexedChunks)
2974
+ storedResult,
2975
+ revisionKey: params.revisionKey
3068
2976
  }),
3069
2977
  matches,
3070
2978
  scannedChunks,
@@ -3076,9 +2984,8 @@ var Knowledge = class _Knowledge {
3076
2984
  return {
3077
2985
  document: createStoredKnowledgeDocument({
3078
2986
  documentId: params.documentId,
3079
- manifest,
3080
- revisionKey: params.revisionKey,
3081
- typeCounts: countIndexedTypes(indexedChunks)
2987
+ storedResult,
2988
+ revisionKey: params.revisionKey
3082
2989
  }),
3083
2990
  matches,
3084
2991
  scannedChunks,
@@ -3086,98 +2993,82 @@ var Knowledge = class _Knowledge {
3086
2993
  };
3087
2994
  }
3088
2995
  async tryReadOutlineFromParsedStorage(documentId, revisionKey) {
3089
- const manifest = await this.readFreshParsedStorageManifest(documentId, revisionKey);
3090
- if (!manifest) {
3091
- return null;
3092
- }
3093
- const indexedChunks = await this.readStoredSnapshotChunks({
3094
- documentId,
3095
- revisionKey,
3096
- manifest
3097
- });
3098
- if (!indexedChunks) {
3099
- return null;
3100
- }
3101
- const sections = buildFlatSectionsFromIndexedChunks(indexedChunks);
3102
- const typeCounts = countIndexedTypes(indexedChunks);
2996
+ const storedResult = await this.readCommittedParsedStorageResult(documentId, revisionKey);
2997
+ if (!storedResult) return null;
2998
+ const sections = storedResult.docNav?.sections && storedResult.docNav.sections.length > 0 ? flattenSections(
2999
+ storedResult.docNav.sections.map(
3000
+ (section) => toKnowledgeSection(
3001
+ section,
3002
+ storedResult.chunks,
3003
+ storedResult.manifest.sourceFileName
3004
+ )
3005
+ )
3006
+ ) : buildFlatSectionsFromIndexedChunks(storedResult.chunks);
3103
3007
  return {
3104
3008
  document: createStoredKnowledgeDocument({
3105
3009
  documentId,
3106
- manifest,
3107
- revisionKey,
3108
- typeCounts
3010
+ storedResult,
3011
+ revisionKey
3109
3012
  }),
3110
- totalChunks: manifest.totalChunks,
3111
- typeCounts,
3013
+ totalChunks: storedResult.chunks.length,
3014
+ typeCounts: storedResult.typeCounts,
3112
3015
  sections,
3113
- sectionTree: nestSections(sections),
3016
+ sectionTree: storedResult.docNav?.sections && storedResult.docNav.sections.length > 0 ? storedResult.docNav.sections.map(
3017
+ (section) => toKnowledgeSection(
3018
+ section,
3019
+ storedResult.chunks,
3020
+ storedResult.manifest.sourceFileName
3021
+ )
3022
+ ) : nestSections(sections),
3114
3023
  truncated: false
3115
3024
  };
3116
3025
  }
3117
- async readFreshParsedStorageManifest(documentId, revisionKey) {
3026
+ async readCommittedParsedStorageResult(documentId, revisionKey) {
3118
3027
  const parsedStorageConfig = this.parsedStorageConfig;
3119
3028
  if (!parsedStorageConfig) {
3120
3029
  return null;
3121
3030
  }
3122
- const manifest = await parsedStorageConfig.storage.readManifest({
3031
+ const commit = await readParsedDocumentCommit({
3032
+ storage: parsedStorageConfig.storage,
3123
3033
  documentId,
3124
3034
  revisionKey
3125
3035
  });
3126
- if (!manifest || !isFreshManifest(manifest, revisionKey)) {
3036
+ if (!commit) {
3127
3037
  return null;
3128
3038
  }
3129
- return manifest;
3130
- }
3131
- async readStoredSnapshotChunks(params) {
3132
- const parsedStorageConfig = this.parsedStorageConfig;
3133
- if (!parsedStorageConfig) {
3039
+ const [manifestObject, chunksObject, docNavObject] = await Promise.all([
3040
+ parsedStorageConfig.storage.readObject({
3041
+ documentId,
3042
+ revisionKey,
3043
+ path: "manifest.json"
3044
+ }),
3045
+ parsedStorageConfig.storage.readObject({
3046
+ documentId,
3047
+ revisionKey,
3048
+ path: "chunks.json"
3049
+ }),
3050
+ parsedStorageConfig.storage.readObject({
3051
+ documentId,
3052
+ revisionKey,
3053
+ path: "doc_nav.json"
3054
+ })
3055
+ ]);
3056
+ if (!manifestObject || !chunksObject) {
3134
3057
  return null;
3135
3058
  }
3136
- const chunks = [];
3137
- for (const pageReference of params.manifest.chunkPages) {
3138
- const page = await parsedStorageConfig.storage.readChunkPage({
3139
- documentId: params.documentId,
3140
- revisionKey: params.revisionKey,
3141
- page: pageReference.page,
3142
- chunkType: params.chunkType
3143
- });
3144
- if (!page) {
3145
- return null;
3146
- }
3147
- chunks.push(
3148
- ...page.chunks.filter((chunk) => !params.chunkType || chunk.chunkType === params.chunkType).map(toIndexedSnapshotChunk)
3149
- );
3150
- }
3151
- return chunks.sort((left, right) => left.position - right.position);
3152
- }
3153
- async toRemoteReadChunks(params) {
3154
- const readChunks = params.chunks.map((chunk) => toRemoteReadChunk(chunk));
3155
- if (params.assetUrlPolicy === "durable") {
3156
- return this.hardenReadChunkAssetUrls({
3157
- documentId: params.documentId,
3158
- revisionKey: params.revisionKey,
3159
- chunks: readChunks
3160
- });
3161
- }
3162
- return applyAssetUrlPolicyToReadChunks(readChunks, params.assetUrlPolicy);
3163
- }
3164
- async hardenReadChunkAssetUrls(params) {
3165
- const parsedStorageConfig = this.parsedStorageConfig;
3166
- if (!parsedStorageConfig) {
3167
- return applyAssetUrlPolicyToReadChunks(params.chunks, "none");
3168
- }
3169
- const hardenedChunks = [];
3170
- for (const chunk of params.chunks) {
3171
- hardenedChunks.push(
3172
- await hardenReadChunkAssetUrls({
3173
- storageConfig: parsedStorageConfig,
3174
- documentId: params.documentId,
3175
- revisionKey: params.revisionKey,
3176
- chunk
3177
- })
3178
- );
3179
- }
3180
- return hardenedChunks;
3059
+ const manifest = readJsonObject(manifestObject);
3060
+ const chunks = parseStoredResultChunks({
3061
+ payload: readJsonObject(chunksObject),
3062
+ sourceFileName: manifest.sourceFileName
3063
+ });
3064
+ const docNav = docNavObject ? readJsonObject(docNavObject) : void 0;
3065
+ return {
3066
+ commit,
3067
+ manifest,
3068
+ chunks,
3069
+ docNav: docNav?.sections ? { sections: docNav.sections } : void 0,
3070
+ typeCounts: countIndexedTypes(chunks)
3071
+ };
3181
3072
  }
3182
3073
  scheduleParsedStorageSync(documentId, revisionKey) {
3183
3074
  const parsedStorageConfig = this.parsedStorageConfig;
@@ -3197,7 +3088,6 @@ var Knowledge = class _Knowledge {
3197
3088
  documentId,
3198
3089
  revisionKey,
3199
3090
  nextChunkPage: 1,
3200
- nextAssetIndex: 0,
3201
3091
  status: "failed",
3202
3092
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3203
3093
  error: error instanceof Error ? error.message : String(error)
@@ -3207,28 +3097,63 @@ var Knowledge = class _Knowledge {
3207
3097
  void Promise.resolve(scheduler.schedule(task)).catch(() => void 0);
3208
3098
  }
3209
3099
  async syncRemoteDocumentToParsedStorage(params) {
3210
- const limits = getParsedStorageLimits(params.parsedStorageConfig.limits);
3211
- const existingProgress = params.revisionKey ? await params.parsedStorageConfig.storage.readSyncProgress({
3212
- documentId: params.documentId,
3213
- revisionKey: params.revisionKey
3214
- }) : null;
3215
- let nextPage = existingProgress?.status === "running" ? existingProgress.nextChunkPage : 1;
3216
- let response = await this.client.documents.listChunks(params.documentId, {
3217
- page: nextPage,
3218
- pageSize: limits.remotePageSize,
3100
+ const firstPage = await this.client.documents.listChunks(params.documentId, {
3101
+ page: 1,
3102
+ pageSize: 1,
3219
3103
  includeAssetUrls: true
3220
3104
  });
3221
- const revisionKey = params.revisionKey ?? getRemoteRevisionKey(response);
3222
- if (params.revisionKey && getRemoteRevisionKey(response) !== params.revisionKey) {
3223
- response = await this.client.documents.listChunks(params.documentId, {
3224
- page: 1,
3225
- pageSize: limits.remotePageSize,
3226
- includeAssetUrls: true
3105
+ const revisionKey = params.revisionKey ?? getRemoteRevisionKey(firstPage);
3106
+ if (params.revisionKey && getRemoteRevisionKey(firstPage) !== params.revisionKey) {
3107
+ return this.syncRemoteDocumentToParsedStorage({
3108
+ documentId: params.documentId,
3109
+ parsedStorageConfig: params.parsedStorageConfig
3227
3110
  });
3228
- nextPage = 1;
3229
3111
  }
3230
- const totalPages = response.pagination.totalPages;
3231
- const chunkPages = [];
3112
+ if (firstPage.jobId) {
3113
+ try {
3114
+ const loadedResult = await this.client.jobs.load(firstPage.jobId);
3115
+ const synced = await syncParseResultToParsedDocumentStorage({
3116
+ result: loadedResult,
3117
+ storage: params.parsedStorageConfig.storage,
3118
+ documentId: params.documentId,
3119
+ revisionKey,
3120
+ source: "resultZip"
3121
+ });
3122
+ await params.parsedStorageConfig.storage.writeSyncProgress({
3123
+ documentId: params.documentId,
3124
+ revisionKey,
3125
+ status: "completed",
3126
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
3127
+ });
3128
+ return {
3129
+ documentId: synced.documentId,
3130
+ revisionKey: synced.revisionKey,
3131
+ completed: true,
3132
+ commit: synced.commit
3133
+ };
3134
+ } catch {
3135
+ }
3136
+ }
3137
+ return this.syncRemoteDocumentChunksToParsedStorage({
3138
+ documentId: params.documentId,
3139
+ revisionKey,
3140
+ firstPage,
3141
+ parsedStorageConfig: params.parsedStorageConfig
3142
+ });
3143
+ }
3144
+ async syncRemoteDocumentChunksToParsedStorage(params) {
3145
+ const limits = getParsedStorageLimits(params.parsedStorageConfig.limits);
3146
+ const existingProgress = await params.parsedStorageConfig.storage.readSyncProgress({
3147
+ documentId: params.documentId,
3148
+ revisionKey: params.revisionKey
3149
+ });
3150
+ let nextPage = existingProgress?.status === "running" ? existingProgress.nextChunkPage ?? 1 : 1;
3151
+ let response = nextPage === 1 && params.firstPage.pagination.pageSize === limits.remotePageSize ? params.firstPage : await this.client.documents.listChunks(params.documentId, {
3152
+ page: nextPage,
3153
+ pageSize: limits.remotePageSize,
3154
+ includeAssetUrls: true
3155
+ });
3156
+ const totalPages = response.pagination.totalPages;
3232
3157
  let syncedPages = 0;
3233
3158
  const startedAt = Date.now();
3234
3159
  while (nextPage <= totalPages) {
@@ -3239,65 +3164,88 @@ var Knowledge = class _Knowledge {
3239
3164
  includeAssetUrls: true
3240
3165
  });
3241
3166
  }
3242
- const readChunks = await this.hardenReadChunkAssetUrls({
3167
+ await params.parsedStorageConfig.storage.writeObject({
3243
3168
  documentId: params.documentId,
3244
- revisionKey,
3245
- chunks: response.chunks.map(toRemoteReadChunk)
3246
- });
3247
- const page = toSnapshotChunkPageFromReadChunks({
3248
- response,
3249
- revisionKey,
3250
- chunks: readChunks
3251
- });
3252
- await params.parsedStorageConfig.storage.writeChunkPage({
3253
- documentId: params.documentId,
3254
- revisionKey,
3255
- page
3169
+ revisionKey: params.revisionKey,
3170
+ path: getRemoteReconstructionPagePath(response.pagination.page),
3171
+ body: Buffer.from(JSON.stringify({ chunks: response.chunks }), "utf8"),
3172
+ contentType: "application/json; charset=utf-8"
3256
3173
  });
3257
- chunkPages.push(page);
3258
3174
  nextPage += 1;
3259
3175
  syncedPages += 1;
3260
3176
  await params.parsedStorageConfig.storage.writeSyncProgress({
3261
3177
  documentId: params.documentId,
3262
- revisionKey,
3178
+ revisionKey: params.revisionKey,
3263
3179
  nextChunkPage: nextPage,
3264
- nextAssetIndex: 0,
3265
3180
  status: "running",
3266
3181
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
3267
3182
  });
3268
3183
  if (syncedPages >= limits.maxPagesPerSync || Date.now() - startedAt >= limits.syncDeadlineMs) {
3269
3184
  return {
3270
3185
  documentId: params.documentId,
3271
- revisionKey,
3186
+ revisionKey: params.revisionKey,
3272
3187
  completed: false
3273
3188
  };
3274
3189
  }
3275
3190
  }
3276
- const manifest = createRemoteSnapshotManifest({
3277
- response,
3278
- revisionKey,
3279
- chunkPages
3191
+ const chunks = await this.readRemoteReconstructionChunks({
3192
+ documentId: params.documentId,
3193
+ revisionKey: params.revisionKey,
3194
+ totalPages,
3195
+ parsedStorageConfig: params.parsedStorageConfig
3280
3196
  });
3281
- await params.parsedStorageConfig.storage.writeManifest({
3197
+ if (!chunks) {
3198
+ return {
3199
+ documentId: params.documentId,
3200
+ revisionKey: params.revisionKey,
3201
+ completed: false
3202
+ };
3203
+ }
3204
+ const synced = await syncParseResultToParsedDocumentStorage({
3205
+ result: createMinimalParseResultFromRemoteChunks({
3206
+ documentId: params.documentId,
3207
+ revisionKey: params.revisionKey,
3208
+ response,
3209
+ chunks
3210
+ }),
3211
+ storage: params.parsedStorageConfig.storage,
3282
3212
  documentId: params.documentId,
3283
- revisionKey,
3284
- manifest
3213
+ revisionKey: params.revisionKey,
3214
+ source: "remoteReconstruction"
3285
3215
  });
3286
3216
  await params.parsedStorageConfig.storage.writeSyncProgress({
3287
3217
  documentId: params.documentId,
3288
- revisionKey,
3218
+ revisionKey: params.revisionKey,
3289
3219
  nextChunkPage: totalPages + 1,
3290
- nextAssetIndex: 0,
3291
3220
  status: "completed",
3292
3221
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
3293
3222
  });
3294
3223
  return {
3295
3224
  documentId: params.documentId,
3296
- revisionKey,
3225
+ revisionKey: params.revisionKey,
3297
3226
  completed: true,
3298
- manifest
3227
+ commit: synced.commit
3299
3228
  };
3300
3229
  }
3230
+ async readRemoteReconstructionChunks(params) {
3231
+ const chunks = [];
3232
+ for (let page = 1; page <= params.totalPages; page += 1) {
3233
+ const object = await params.parsedStorageConfig.storage.readObject({
3234
+ documentId: params.documentId,
3235
+ revisionKey: params.revisionKey,
3236
+ path: getRemoteReconstructionPagePath(page)
3237
+ });
3238
+ if (!object) {
3239
+ return null;
3240
+ }
3241
+ const payload = readJsonObject(object);
3242
+ if (!isDocumentChunkArray(payload.chunks)) {
3243
+ return null;
3244
+ }
3245
+ chunks.push(...payload.chunks);
3246
+ }
3247
+ return chunks;
3248
+ }
3301
3249
  requireParsedStorageConfig() {
3302
3250
  if (!this.parsedStorageConfig) {
3303
3251
  throw new ValidationError("parsed document storage is not configured");
@@ -3311,7 +3259,8 @@ var Knowledge = class _Knowledge {
3311
3259
  async getPublishedDocumentJobId(documentId) {
3312
3260
  const response = await this.client.documents.listChunks(documentId, {
3313
3261
  page: 1,
3314
- pageSize: 1
3262
+ pageSize: 1,
3263
+ includeAssetUrls: true
3315
3264
  });
3316
3265
  if (!response.jobId) {
3317
3266
  throw new Error(
@@ -3344,14 +3293,12 @@ var defaultParsedStorageScheduler = {
3344
3293
  };
3345
3294
  function getParsedStorageLimits(limits) {
3346
3295
  return {
3347
- chunkPageSize: clampLimit(limits?.chunkPageSize, DEFAULT_REMOTE_SCAN_PAGE_SIZE, MAX_PAGE_SIZE),
3348
3296
  remotePageSize: clampLimit(
3349
3297
  limits?.remotePageSize,
3350
3298
  DEFAULT_REMOTE_SCAN_PAGE_SIZE,
3351
3299
  MAX_PAGE_SIZE
3352
3300
  ),
3353
3301
  maxPagesPerSync: clampLimit(limits?.maxPagesPerSync, DEFAULT_MAX_SYNC_PAGES, 1e3),
3354
- maxAssetsPerSync: clampLimit(limits?.maxAssetsPerSync, DEFAULT_MAX_SYNC_ASSETS, 1e3),
3355
3302
  syncDeadlineMs: clampLimit(limits?.syncDeadlineMs, DEFAULT_SYNC_DEADLINE_MS, 6e4),
3356
3303
  grepMaxPages: clampLimit(limits?.grepMaxPages, DEFAULT_GREP_MAX_PAGES, 1e3),
3357
3304
  grepDeadlineMs: clampLimit(limits?.grepDeadlineMs, DEFAULT_GREP_DEADLINE_MS, 6e4),
@@ -3360,13 +3307,13 @@ function getParsedStorageLimits(limits) {
3360
3307
  };
3361
3308
  }
3362
3309
  function validateReadParams(params) {
3363
- const usesPagedDisplay = params.page !== void 0 || params.pageSize !== void 0 || params.assetUrlPolicy !== void 0;
3310
+ const usesPagedDisplay = params.page !== void 0 || params.pageSize !== void 0;
3364
3311
  if (!usesPagedDisplay) {
3365
3312
  return;
3366
3313
  }
3367
3314
  if (params.sectionPath !== void 0 || params.startChunk !== void 0 || params.endChunk !== void 0 || params.chunkId !== void 0) {
3368
3315
  throw new ValidationError(
3369
- "page, pageSize, and assetUrlPolicy cannot be combined with sectionPath, startChunk, endChunk, or chunkId"
3316
+ "page and pageSize cannot be combined with sectionPath, startChunk, endChunk, or chunkId"
3370
3317
  );
3371
3318
  }
3372
3319
  }
@@ -3379,9 +3326,6 @@ function getReadPageParams(params) {
3379
3326
  pageSize: clampLimit(params.pageSize ?? params.limit, DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE)
3380
3327
  };
3381
3328
  }
3382
- function shouldRequestRemoteAssetUrls(assetUrlPolicy, parsedStorageConfig) {
3383
- return assetUrlPolicy === "durable" && parsedStorageConfig !== void 0;
3384
- }
3385
3329
  function getRemoteRevisionKey(response) {
3386
3330
  const revisionKey = response.jobResultId ?? response.jobId;
3387
3331
  if (!revisionKey) {
@@ -3391,6 +3335,9 @@ function getRemoteRevisionKey(response) {
3391
3335
  }
3392
3336
  return revisionKey;
3393
3337
  }
3338
+ function getRemoteReconstructionPagePath(page) {
3339
+ return `${remoteReconstructionPageDirectory}/page-${page}.json`;
3340
+ }
3394
3341
  function createRemoteKnowledgeDocument(params) {
3395
3342
  return {
3396
3343
  localDocumentId: params.documentId,
@@ -3405,23 +3352,103 @@ function createRemoteKnowledgeDocument(params) {
3405
3352
  updatedAt: /* @__PURE__ */ new Date(0)
3406
3353
  };
3407
3354
  }
3355
+ function createMinimalParseResultFromRemoteChunks(params) {
3356
+ const chunks = params.chunks.map(toMinimalChunkFromRemoteChunk);
3357
+ const typeCounts = countRemoteChunkTypes(params.chunks);
3358
+ return {
3359
+ manifest: {
3360
+ version: "2.0",
3361
+ jobId: params.response.jobId ?? params.revisionKey,
3362
+ sourceFileName: params.documentId,
3363
+ statistics: {
3364
+ totalChunks: chunks.length,
3365
+ textChunks: typeCounts.text,
3366
+ imageChunks: typeCounts.image,
3367
+ tableChunks: typeCounts.table,
3368
+ pageChunks: typeCounts.page
3369
+ }
3370
+ },
3371
+ chunks,
3372
+ rawZip: Buffer.from(""),
3373
+ namespace: params.response.namespace,
3374
+ documentId: params.documentId,
3375
+ textChunks: chunks.filter(
3376
+ (chunk) => chunk.type === "text"
3377
+ ),
3378
+ imageChunks: chunks.filter(
3379
+ (chunk) => chunk.type === "image"
3380
+ ),
3381
+ tableChunks: chunks.filter(
3382
+ (chunk) => chunk.type === "table"
3383
+ ),
3384
+ pageChunks: chunks.filter(
3385
+ (chunk) => chunk.type === "page"
3386
+ ),
3387
+ jobId: params.response.jobId ?? params.revisionKey,
3388
+ statistics: {
3389
+ totalChunks: chunks.length,
3390
+ textChunks: typeCounts.text,
3391
+ imageChunks: typeCounts.image,
3392
+ tableChunks: typeCounts.table,
3393
+ pageChunks: typeCounts.page
3394
+ },
3395
+ getChunk: (chunkId) => chunks.find((chunk) => chunk.chunkId === chunkId),
3396
+ save: () => Promise.reject(new Error("Minimal remote reconstruction cannot be saved directly."))
3397
+ };
3398
+ }
3399
+ function toMinimalChunkFromRemoteChunk(chunk) {
3400
+ const baseChunk = {
3401
+ chunkId: chunk.chunkId,
3402
+ contentSource: chunk.contentSource ?? void 0,
3403
+ content: chunk.content ?? "",
3404
+ path: chunk.sourceChunkPath ?? chunk.sectionPath ?? "",
3405
+ metadata: cloneMetadata(chunk.metadata)
3406
+ };
3407
+ if (chunk.chunkType === "image") {
3408
+ return {
3409
+ ...baseChunk,
3410
+ type: "image",
3411
+ filePath: chunk.filePath ?? "",
3412
+ assetUrl: chunk.assetUrl ?? void 0,
3413
+ data: Buffer.alloc(0),
3414
+ format: inferContentTypeFromPath2(chunk.filePath ?? "").replace("image/", ""),
3415
+ save: () => Promise.resolve(chunk.filePath ?? "")
3416
+ };
3417
+ }
3418
+ if (chunk.chunkType === "table") {
3419
+ return {
3420
+ ...baseChunk,
3421
+ type: "table",
3422
+ filePath: chunk.filePath ?? "",
3423
+ assetUrl: chunk.assetUrl ?? void 0,
3424
+ html: chunk.content ?? "",
3425
+ save: () => Promise.resolve(chunk.filePath ?? "")
3426
+ };
3427
+ }
3428
+ if (chunk.chunkType === "page") {
3429
+ return {
3430
+ ...baseChunk,
3431
+ type: "page"
3432
+ };
3433
+ }
3434
+ return {
3435
+ ...baseChunk,
3436
+ type: "text"
3437
+ };
3438
+ }
3408
3439
  function createStoredKnowledgeDocument(params) {
3409
3440
  return {
3410
3441
  localDocumentId: params.documentId,
3411
- jobId: params.manifest.jobId || params.revisionKey,
3412
- documentId: params.manifest.documentId ?? params.documentId,
3413
- namespace: params.manifest.namespace,
3414
- sourceFileName: params.manifest.sourceFileName,
3415
- chunkCount: params.manifest.totalChunks,
3416
- typeCounts: params.typeCounts,
3442
+ jobId: params.storedResult.manifest.jobId || params.revisionKey,
3443
+ documentId: params.documentId,
3444
+ sourceFileName: params.storedResult.manifest.sourceFileName,
3445
+ chunkCount: params.storedResult.chunks.length,
3446
+ typeCounts: params.storedResult.typeCounts,
3417
3447
  resultDirectoryPath: `parsed-storage:${params.documentId}`,
3418
- createdAt: new Date(params.manifest.createdAt),
3419
- updatedAt: new Date(params.manifest.createdAt)
3448
+ createdAt: new Date(params.storedResult.commit.committedAt),
3449
+ updatedAt: new Date(params.storedResult.commit.committedAt)
3420
3450
  };
3421
3451
  }
3422
- function isFreshManifest(manifest, revisionKey) {
3423
- return (manifest.revisionKey ?? manifest.jobId) === revisionKey;
3424
- }
3425
3452
  function toRemoteReadChunk(chunk) {
3426
3453
  const metadata = cloneMetadata(chunk.metadata);
3427
3454
  return {
@@ -3450,22 +3477,60 @@ function toIndexedRemoteChunk(chunk) {
3450
3477
  const readChunk = toRemoteReadChunk(chunk);
3451
3478
  return toIndexedReadChunk(readChunk);
3452
3479
  }
3453
- function toIndexedSnapshotChunk(chunk) {
3454
- return toIndexedReadChunk({
3455
- position: chunk.sortOrder,
3456
- chunkId: chunk.chunkId,
3457
- chunkType: chunk.chunkType,
3458
- contentSource: chunk.contentSource,
3459
- content: chunk.content,
3460
- readableContent: chunk.chunkType === "page" && typeof chunk.metadata.summary === "string" && chunk.metadata.summary.trim().length > 0 ? chunk.metadata.summary : chunk.content,
3461
- sectionPath: chunk.sectionPath ?? "",
3462
- sourceChunkPath: chunk.sourceChunkPath,
3463
- filePath: chunk.filePath,
3464
- assetUrl: chunk.assetUrl,
3465
- pageNumbers: getChunkPageNumbers(chunk.metadata),
3466
- metadata: cloneMetadata(chunk.metadata)
3480
+ function parseStoredResultChunks(params) {
3481
+ const rawChunks = extractStoredChunkRecords(params.payload);
3482
+ return rawChunks.map((record, index) => {
3483
+ const metadata = readRecordMetadata(record);
3484
+ const chunkType = readRecordString(record, "type", "chunkType", "chunk_type");
3485
+ const content = readRecordString(record, "content") ?? "";
3486
+ const sourceChunkPath = readRecordString(record, "path", "sourceChunkPath", "source_chunk_path") ?? "";
3487
+ const chunk = {
3488
+ position: index + 1,
3489
+ chunkId: readRecordString(record, "chunkId", "chunk_id") ?? "",
3490
+ chunkType: isKnowledgeChunkType(chunkType) ? chunkType : "text",
3491
+ contentSource: readRecordString(record, "contentSource", "content_source"),
3492
+ content,
3493
+ readableContent: chunkType === "page" && typeof metadata.summary === "string" && metadata.summary.trim().length > 0 ? metadata.summary : content,
3494
+ sectionPath: normalizeSectionPath(sourceChunkPath, params.sourceFileName),
3495
+ sourceChunkPath,
3496
+ filePath: readRecordString(record, "filePath", "file_path") ?? (typeof metadata.filePath === "string" ? metadata.filePath : void 0),
3497
+ assetUrl: readRecordString(record, "assetUrl", "asset_url"),
3498
+ pageNumbers: getChunkPageNumbers(metadata),
3499
+ metadata
3500
+ };
3501
+ return toIndexedReadChunk(chunk);
3467
3502
  });
3468
3503
  }
3504
+ function extractStoredChunkRecords(payload) {
3505
+ if (Array.isArray(payload)) {
3506
+ return payload.filter(isRecord2);
3507
+ }
3508
+ if (isRecord2(payload) && Array.isArray(payload.chunks)) {
3509
+ return payload.chunks.filter(isRecord2);
3510
+ }
3511
+ return [];
3512
+ }
3513
+ function readRecordString(record, ...keys) {
3514
+ for (const key of keys) {
3515
+ const value = record[key];
3516
+ if (typeof value === "string") return value;
3517
+ }
3518
+ return void 0;
3519
+ }
3520
+ function readRecordNumber(record, ...keys) {
3521
+ for (const key of keys) {
3522
+ const value = record[key];
3523
+ if (typeof value === "number") return value;
3524
+ }
3525
+ return void 0;
3526
+ }
3527
+ function readRecordMetadata(record) {
3528
+ const metadata = record.metadata;
3529
+ return isRecord2(metadata) ? keysToCamel(metadata) : {};
3530
+ }
3531
+ function isKnowledgeChunkType(value) {
3532
+ return value === "text" || value === "image" || value === "table" || value === "page";
3533
+ }
3469
3534
  function toIndexedReadChunk(chunk) {
3470
3535
  return {
3471
3536
  source: createSyntheticChunk(chunk),
@@ -3519,204 +3584,105 @@ function getNextChunkPosition(chunks, selected) {
3519
3584
  }
3520
3585
  return chunks[chunks.indexOf(lastSelected) + 1]?.position;
3521
3586
  }
3522
- function applyAssetUrlPolicyToReadChunks(chunks, assetUrlPolicy) {
3523
- if (assetUrlPolicy !== "none") {
3524
- return chunks.map((chunk) => ({
3525
- ...chunk,
3526
- metadata: cloneMetadata(chunk.metadata)
3527
- }));
3528
- }
3529
- return chunks.map((chunk) => ({
3530
- ...chunk,
3531
- assetUrl: void 0,
3532
- metadata: removeAssetUrlsFromMetadata(chunk.metadata)
3533
- }));
3587
+ async function applyStoredAssetUrlsToReadChunks(params) {
3588
+ return Promise.all(
3589
+ params.chunks.map(
3590
+ (chunk) => applyStoredAssetUrlsToReadChunk({
3591
+ ...params,
3592
+ chunk
3593
+ })
3594
+ )
3595
+ );
3534
3596
  }
3535
- async function hardenReadChunkAssetUrls(params) {
3597
+ async function applyStoredAssetUrlsToReadChunk(params) {
3536
3598
  const metadata = cloneMetadata(params.chunk.metadata);
3537
- const assetUrl = await hardenPrimaryAssetUrl(params, metadata);
3538
- const pageAssets = await hardenPageAssetUrls(params, metadata);
3539
- if (pageAssets) {
3540
- metadata.pageAssets = pageAssets;
3541
- }
3542
- return {
3543
- ...params.chunk,
3544
- assetUrl,
3545
- metadata
3546
- };
3547
- }
3548
- async function hardenPrimaryAssetUrl(params, metadata) {
3549
- if (!params.chunk.assetUrl || !params.chunk.filePath) {
3550
- return void 0;
3551
- }
3552
- return writeDurableAssetUrl({
3599
+ const storedAssetUrl = await getStoredObjectUrl({
3553
3600
  storageConfig: params.storageConfig,
3554
3601
  documentId: params.documentId,
3555
3602
  revisionKey: params.revisionKey,
3556
- sourcePath: params.chunk.filePath,
3557
- sourceUrl: params.chunk.assetUrl,
3558
- fallbackContentType: inferContentTypeFromPath(params.chunk.filePath),
3559
- metadata: {
3560
- chunkId: params.chunk.chunkId,
3561
- chunkType: params.chunk.chunkType,
3562
- sourcePath: params.chunk.filePath,
3563
- ...stringifyFlatMetadata(metadata)
3564
- }
3603
+ path: params.chunk.filePath
3565
3604
  });
3566
- }
3567
- async function hardenPageAssetUrls(params, metadata) {
3568
- const pageAssets = toUnknownArray(metadata.pageAssets);
3569
- if (!pageAssets) {
3570
- return void 0;
3571
- }
3572
- const hardenedAssets = [];
3573
- for (const pageAsset of pageAssets) {
3574
- if (!isRecord2(pageAsset)) {
3575
- hardenedAssets.push(pageAsset);
3576
- continue;
3577
- }
3578
- const artifactRef = pageAsset.artifactRef;
3579
- const sourceUrl = pageAsset.assetUrl;
3580
- if (typeof artifactRef !== "string" || typeof sourceUrl !== "string") {
3581
- hardenedAssets.push(removeAssetUrlField(pageAsset));
3582
- continue;
3583
- }
3584
- const durableUrl = await writeDurableAssetUrl({
3585
- storageConfig: params.storageConfig,
3586
- documentId: params.documentId,
3587
- revisionKey: params.revisionKey,
3588
- sourcePath: artifactRef,
3589
- sourceUrl,
3590
- fallbackContentType: typeof pageAsset.contentType === "string" ? pageAsset.contentType : inferContentTypeFromPath(artifactRef),
3591
- metadata: {
3592
- chunkId: params.chunk.chunkId,
3593
- chunkType: params.chunk.chunkType,
3594
- sourcePath: artifactRef
3595
- }
3596
- });
3597
- const rest = removeAssetUrlField(pageAsset);
3598
- hardenedAssets.push(durableUrl ? { ...rest, assetUrl: durableUrl } : rest);
3599
- }
3600
- return hardenedAssets;
3601
- }
3602
- async function writeDurableAssetUrl(params) {
3603
- const existingUrl = await params.storageConfig.storage.getAssetUrl({
3605
+ const pageAssets = await applyStoredPageAssetUrls({
3606
+ storageConfig: params.storageConfig,
3604
3607
  documentId: params.documentId,
3605
3608
  revisionKey: params.revisionKey,
3606
- sourcePath: params.sourcePath
3609
+ metadata
3607
3610
  });
3608
- if (existingUrl) {
3609
- return existingUrl;
3610
- }
3611
- try {
3612
- const fetched = await fetchAsset(params.sourceUrl, params.fallbackContentType);
3613
- const written = await params.storageConfig.storage.writeAsset({
3614
- documentId: params.documentId,
3615
- revisionKey: params.revisionKey,
3616
- sourcePath: params.sourcePath,
3617
- body: fetched.body,
3618
- contentType: fetched.contentType,
3619
- metadata: params.metadata
3620
- });
3621
- return written.url ?? await params.storageConfig.storage.getAssetUrl({
3622
- documentId: params.documentId,
3623
- revisionKey: params.revisionKey,
3624
- sourcePath: params.sourcePath
3625
- }) ?? void 0;
3626
- } catch {
3627
- return void 0;
3628
- }
3629
- }
3630
- async function fetchAsset(sourceUrl, fallbackContentType) {
3631
- const response = await fetch(sourceUrl);
3632
- if (!response.ok) {
3633
- throw new Error(`Unable to fetch parsed asset: ${response.status}`);
3611
+ if (pageAssets) {
3612
+ metadata.pageAssets = pageAssets;
3613
+ delete metadata.page_assets;
3634
3614
  }
3635
3615
  return {
3636
- body: new Uint8Array(await response.arrayBuffer()),
3637
- contentType: response.headers.get("content-type") ?? fallbackContentType
3616
+ ...params.chunk,
3617
+ assetUrl: storedAssetUrl ?? params.chunk.assetUrl,
3618
+ metadata
3638
3619
  };
3639
3620
  }
3640
- function removeAssetUrlsFromMetadata(metadata) {
3641
- const cloned = cloneMetadata(metadata);
3642
- const pageAssets = toUnknownArray(cloned.pageAssets);
3621
+ async function applyStoredPageAssetUrls(params) {
3622
+ const pageAssets = getStoredPageAssets(params.metadata);
3643
3623
  if (!pageAssets) {
3644
- return cloned;
3624
+ return void 0;
3645
3625
  }
3646
- cloned.pageAssets = pageAssets.map((pageAsset) => {
3647
- if (!isRecord2(pageAsset)) {
3626
+ return Promise.all(
3627
+ pageAssets.map(async (pageAsset) => {
3628
+ if (!isRecord2(pageAsset)) {
3629
+ return pageAsset;
3630
+ }
3631
+ const artifactRef = readRecordString(pageAsset, "artifactRef", "artifact_ref");
3632
+ if (typeof artifactRef !== "string") {
3633
+ return pageAsset;
3634
+ }
3635
+ const storedAssetUrl = await getStoredObjectUrl({
3636
+ storageConfig: params.storageConfig,
3637
+ documentId: params.documentId,
3638
+ revisionKey: params.revisionKey,
3639
+ path: artifactRef
3640
+ });
3641
+ if (storedAssetUrl) {
3642
+ return {
3643
+ ...pageAsset,
3644
+ artifactRef,
3645
+ assetUrl: storedAssetUrl
3646
+ };
3647
+ }
3648
3648
  return pageAsset;
3649
- }
3650
- return removeAssetUrlField(pageAsset);
3651
- });
3652
- return cloned;
3653
- }
3654
- function removeAssetUrlField(value) {
3655
- const cloned = { ...value };
3656
- delete cloned.assetUrl;
3657
- return cloned;
3658
- }
3659
- function toSnapshotChunkPageFromReadChunks(params) {
3660
- return {
3661
- version: 1,
3662
- jobId: params.response.jobId ?? params.revisionKey,
3663
- revisionKey: params.revisionKey,
3664
- documentId: params.response.documentId,
3665
- namespace: params.response.namespace,
3666
- sourceFileName: params.response.documentId,
3667
- page: params.response.pagination.page,
3668
- pageSize: params.response.pagination.pageSize,
3669
- total: params.response.pagination.total,
3670
- totalPages: params.response.pagination.totalPages,
3671
- chunks: params.chunks.map(toSnapshotChunkFromReadChunk)
3672
- };
3649
+ })
3650
+ );
3673
3651
  }
3674
- function toSnapshotChunkFromReadChunk(chunk) {
3652
+ function getStoredPageAssets(metadata) {
3653
+ const pageAssets = toUnknownArray(metadata.pageAssets) ?? toUnknownArray(metadata.page_assets) ?? void 0;
3654
+ return pageAssets?.map(normalizeStoredPageAsset);
3655
+ }
3656
+ function normalizeStoredPageAsset(pageAsset) {
3657
+ if (!isRecord2(pageAsset)) {
3658
+ return pageAsset;
3659
+ }
3660
+ const normalizedPageAsset = { ...pageAsset };
3661
+ delete normalizedPageAsset.page_num;
3662
+ delete normalizedPageAsset.artifact_ref;
3663
+ delete normalizedPageAsset.asset_url;
3664
+ delete normalizedPageAsset.content_type;
3665
+ const pageNum = readRecordNumber(pageAsset, "pageNum", "page_num");
3666
+ const artifactRef = readRecordString(pageAsset, "artifactRef", "artifact_ref");
3667
+ const assetUrl = readRecordString(pageAsset, "assetUrl", "asset_url");
3668
+ const contentType = readRecordString(pageAsset, "contentType", "content_type");
3675
3669
  return {
3676
- id: chunk.chunkId,
3677
- chunkId: chunk.chunkId,
3678
- chunkType: chunk.chunkType,
3679
- contentSource: chunk.contentSource,
3680
- content: chunk.content,
3681
- sectionPath: chunk.sectionPath,
3682
- sourceChunkPath: chunk.sourceChunkPath,
3683
- filePath: chunk.filePath,
3684
- sortOrder: chunk.position,
3685
- metadata: cloneMetadata(chunk.metadata),
3686
- assetUrl: chunk.assetUrl
3670
+ ...normalizedPageAsset,
3671
+ ...pageNum === void 0 ? {} : { pageNum },
3672
+ ...artifactRef === void 0 ? {} : { artifactRef },
3673
+ ...assetUrl === void 0 ? {} : { assetUrl },
3674
+ ...contentType === void 0 ? {} : { contentType }
3687
3675
  };
3688
3676
  }
3689
- function createRemoteSnapshotManifest(params) {
3690
- return {
3691
- version: 1,
3692
- kind: "knowhere-parsed-result-snapshot",
3693
- jobId: params.response.jobId ?? params.revisionKey,
3677
+ async function getStoredObjectUrl(params) {
3678
+ if (!params.path) {
3679
+ return void 0;
3680
+ }
3681
+ return await params.storageConfig.storage.getObjectUrl?.({
3682
+ documentId: params.documentId,
3694
3683
  revisionKey: params.revisionKey,
3695
- documentId: params.response.documentId,
3696
- namespace: params.response.namespace,
3697
- sourceFileName: params.response.documentId,
3698
- totalChunks: params.response.pagination.total,
3699
- typeCounts: countSnapshotPagesTypes(params.chunkPages),
3700
- chunkPageSize: params.response.pagination.pageSize,
3701
- chunkPages: Array.from({ length: params.response.pagination.totalPages }, (_, index) => ({
3702
- page: index + 1,
3703
- pageSize: params.response.pagination.pageSize,
3704
- chunkCount: index + 1 === params.response.pagination.totalPages ? params.response.pagination.total - params.response.pagination.pageSize * (params.response.pagination.totalPages - 1) : params.response.pagination.pageSize,
3705
- key: `parsed/chunks/page-${index + 1}.json`
3706
- })),
3707
- assetUrlsByFilePath: {},
3708
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
3709
- };
3710
- }
3711
- function countSnapshotPagesTypes(pages) {
3712
- return pages.flatMap((page) => page.chunks).reduce(
3713
- (counts, chunk) => {
3714
- const chunkType = chunk.chunkType;
3715
- counts[chunkType] += 1;
3716
- return counts;
3717
- },
3718
- { text: 0, image: 0, table: 0, page: 0 }
3719
- );
3684
+ path: params.path
3685
+ }) ?? void 0;
3720
3686
  }
3721
3687
  function countRemoteChunkTypes(chunks) {
3722
3688
  return chunks.reduce(
@@ -3794,22 +3760,10 @@ function isOptionalNonNegativeInteger(value) {
3794
3760
  function cloneMetadata(metadata) {
3795
3761
  return { ...metadata };
3796
3762
  }
3797
- function stringifyFlatMetadata(metadata) {
3798
- const entries = Object.entries(metadata).flatMap(([key, value]) => {
3799
- if (typeof value === "string") {
3800
- return [[key, value]];
3801
- }
3802
- if (typeof value === "number" || typeof value === "boolean") {
3803
- return [[key, String(value)]];
3804
- }
3805
- return [];
3806
- });
3807
- return Object.fromEntries(entries);
3808
- }
3809
3763
  function toUnknownArray(value) {
3810
3764
  return Array.isArray(value) ? value : null;
3811
3765
  }
3812
- function inferContentTypeFromPath(filePath) {
3766
+ function inferContentTypeFromPath2(filePath) {
3813
3767
  const extension = filePath.split(".").at(-1)?.toLowerCase();
3814
3768
  if (extension === "png") return "image/png";
3815
3769
  if (extension === "jpg" || extension === "jpeg") return "image/jpeg";
@@ -3819,6 +3773,9 @@ function inferContentTypeFromPath(filePath) {
3819
3773
  function isRecord2(value) {
3820
3774
  return typeof value === "object" && value !== null && !Array.isArray(value);
3821
3775
  }
3776
+ function isDocumentChunkArray(value) {
3777
+ return Array.isArray(value) && value.every(isRecord2);
3778
+ }
3822
3779
  function indexChunks(result) {
3823
3780
  return result.chunks.map((chunk, index) => {
3824
3781
  const filePath = getChunkFilePath2(chunk);
@@ -4264,51 +4221,59 @@ var Knowhere = class {
4264
4221
  import { createHash as createHash3 } from "crypto";
4265
4222
  import { promises as fs4 } from "fs";
4266
4223
  import path3 from "path";
4224
+ var syncProgressPath = ".knowhere-sdk/sync-progress.json";
4267
4225
  var DiskParsedDocumentStorage = class {
4268
4226
  rootDirectory;
4269
4227
  constructor(rootDirectory) {
4270
4228
  this.rootDirectory = rootDirectory;
4271
4229
  }
4272
- async readManifest(params) {
4273
- return this.readOptionalJson(
4274
- this.getManifestPath(params.documentId, params.revisionKey)
4275
- );
4276
- }
4277
- async writeManifest(params) {
4278
- await this.writeJson(
4279
- this.getManifestPath(params.documentId, params.revisionKey),
4280
- params.manifest
4281
- );
4282
- }
4283
- async readChunkPage(params) {
4284
- return this.readOptionalJson(
4285
- this.getChunkPagePath(params.documentId, params.revisionKey, params.page)
4286
- );
4287
- }
4288
- async writeChunkPage(params) {
4289
- await this.writeJson(
4290
- this.getChunkPagePath(params.documentId, params.revisionKey, params.page.page),
4291
- params.page
4292
- );
4230
+ async readObject(params) {
4231
+ const objectPath = this.getObjectPath(params);
4232
+ try {
4233
+ const body = await fs4.readFile(objectPath);
4234
+ const metadata = await this.readObjectMetadata(objectPath);
4235
+ return {
4236
+ ...params,
4237
+ body,
4238
+ contentType: metadata?.contentType,
4239
+ contentLength: body.byteLength,
4240
+ metadata: metadata?.metadata,
4241
+ url: toFileUrl(objectPath)
4242
+ };
4243
+ } catch (error) {
4244
+ if (isMissingFileError3(error)) {
4245
+ return null;
4246
+ }
4247
+ throw error;
4248
+ }
4293
4249
  }
4294
- async writeAsset(params) {
4295
- const assetPath = this.getAssetPath(params.documentId, params.revisionKey, params.sourcePath);
4296
- await fs4.mkdir(path3.dirname(assetPath), { recursive: true });
4297
- await fs4.writeFile(assetPath, params.body);
4298
- await this.writeJson(`${assetPath}.metadata.json`, {
4250
+ async writeObject(params) {
4251
+ const objectPath = this.getObjectPath(params);
4252
+ await fs4.mkdir(path3.dirname(objectPath), { recursive: true });
4253
+ await fs4.writeFile(objectPath, params.body);
4254
+ await this.writeObjectMetadata(objectPath, {
4299
4255
  contentType: params.contentType,
4300
- metadata: params.metadata ?? {}
4256
+ metadata: params.metadata
4301
4257
  });
4302
4258
  return {
4303
- sourcePath: params.sourcePath,
4304
- url: toFileUrl(assetPath)
4259
+ documentId: params.documentId,
4260
+ revisionKey: params.revisionKey,
4261
+ path: params.path,
4262
+ url: toFileUrl(objectPath)
4305
4263
  };
4306
4264
  }
4307
- async getAssetUrl(params) {
4308
- const assetPath = this.getAssetPath(params.documentId, params.revisionKey, params.sourcePath);
4265
+ async headObject(params) {
4266
+ const objectPath = this.getObjectPath(params);
4309
4267
  try {
4310
- await fs4.access(assetPath);
4311
- return toFileUrl(assetPath);
4268
+ const stat = await fs4.stat(objectPath);
4269
+ const metadata = await this.readObjectMetadata(objectPath);
4270
+ return {
4271
+ ...params,
4272
+ contentType: metadata?.contentType,
4273
+ contentLength: stat.size,
4274
+ metadata: metadata?.metadata,
4275
+ url: toFileUrl(objectPath)
4276
+ };
4312
4277
  } catch (error) {
4313
4278
  if (isMissingFileError3(error)) {
4314
4279
  return null;
@@ -4316,53 +4281,54 @@ var DiskParsedDocumentStorage = class {
4316
4281
  throw error;
4317
4282
  }
4318
4283
  }
4319
- async readSyncProgress(params) {
4320
- return this.readOptionalJson(
4321
- this.getProgressPath(params.documentId, params.revisionKey)
4322
- );
4323
- }
4324
- async writeSyncProgress(params) {
4325
- await this.writeJson(this.getProgressPath(params.documentId, params.revisionKey), params);
4284
+ async getObjectUrl(params) {
4285
+ const head = await this.headObject(params);
4286
+ return head?.url ?? null;
4326
4287
  }
4327
- getManifestPath(documentId, revisionKey) {
4328
- return path3.join(
4329
- this.getRevisionDirectory(documentId, revisionKey),
4330
- "manifest",
4331
- "current.json"
4332
- );
4288
+ async deletePrefix(params) {
4289
+ await fs4.rm(this.getRevisionDirectory(params.documentId, params.revisionKey), {
4290
+ recursive: true,
4291
+ force: true
4292
+ });
4333
4293
  }
4334
- getChunkPagePath(documentId, revisionKey, page) {
4335
- return path3.join(
4336
- this.getRevisionDirectory(documentId, revisionKey),
4337
- "chunks",
4338
- `page-${page}.json`
4339
- );
4294
+ async readSyncProgress(params) {
4295
+ return this.readOptionalJson({
4296
+ ...params,
4297
+ path: syncProgressPath
4298
+ });
4340
4299
  }
4341
- getProgressPath(documentId, revisionKey) {
4342
- return path3.join(this.getRevisionDirectory(documentId, revisionKey), "sync-progress.json");
4300
+ async writeSyncProgress(params) {
4301
+ await this.writeObject({
4302
+ documentId: params.documentId,
4303
+ revisionKey: params.revisionKey,
4304
+ path: syncProgressPath,
4305
+ body: Buffer.from(JSON.stringify(params, null, 2), "utf8"),
4306
+ contentType: "application/json; charset=utf-8"
4307
+ });
4343
4308
  }
4344
- getAssetPath(documentId, revisionKey, sourcePath) {
4345
- const normalizedSourcePath = normalizeRelativeStoragePath(sourcePath);
4346
- const assetPath = path3.resolve(
4347
- this.getRevisionDirectory(documentId, revisionKey),
4348
- "assets",
4349
- normalizedSourcePath
4350
- );
4351
- const assetsDirectory = path3.resolve(
4352
- this.getRevisionDirectory(documentId, revisionKey),
4353
- "assets"
4354
- );
4355
- if (!isPathInsideDirectory2(assetPath, assetsDirectory)) {
4356
- throw new Error(`Parsed asset path resolves outside storage: ${sourcePath}`);
4309
+ getObjectPath(params) {
4310
+ const revisionDirectory = this.getRevisionDirectory(params.documentId, params.revisionKey);
4311
+ const objectPath = path3.resolve(revisionDirectory, normalizeRelativeStoragePath(params.path));
4312
+ if (!isPathInsideDirectory2(objectPath, revisionDirectory)) {
4313
+ throw new Error(`Parsed document object path resolves outside storage: ${params.path}`);
4357
4314
  }
4358
- return assetPath;
4315
+ return objectPath;
4359
4316
  }
4360
4317
  getRevisionDirectory(documentId, revisionKey) {
4361
4318
  return path3.join(this.rootDirectory, hashPathPart(documentId), hashPathPart(revisionKey));
4362
4319
  }
4363
- async readOptionalJson(filePath) {
4320
+ async readOptionalJson(params) {
4321
+ const object = await this.readObject(params);
4322
+ if (!object) {
4323
+ return null;
4324
+ }
4325
+ return JSON.parse(Buffer.from(object.body).toString("utf8"));
4326
+ }
4327
+ async readObjectMetadata(filePath) {
4364
4328
  try {
4365
- return JSON.parse(await fs4.readFile(filePath, "utf8"));
4329
+ return JSON.parse(
4330
+ await fs4.readFile(getMetadataPath(filePath), "utf8")
4331
+ );
4366
4332
  } catch (error) {
4367
4333
  if (isMissingFileError3(error)) {
4368
4334
  return null;
@@ -4370,16 +4336,22 @@ var DiskParsedDocumentStorage = class {
4370
4336
  throw error;
4371
4337
  }
4372
4338
  }
4373
- async writeJson(filePath, value) {
4374
- await fs4.mkdir(path3.dirname(filePath), { recursive: true });
4375
- await fs4.writeFile(filePath, JSON.stringify(value, null, 2), {
4339
+ async writeObjectMetadata(filePath, metadata) {
4340
+ await fs4.writeFile(getMetadataPath(filePath), JSON.stringify(metadata, null, 2), {
4376
4341
  encoding: "utf8",
4377
4342
  flag: "w"
4378
4343
  });
4379
4344
  }
4380
4345
  };
4346
+ function getMetadataPath(filePath) {
4347
+ return `${filePath}.metadata.json`;
4348
+ }
4381
4349
  function hashPathPart(value) {
4382
- return createHash3("sha256").update(value).digest("hex").slice(0, 24);
4350
+ const normalized = value.trim();
4351
+ if (normalized.length === 0) {
4352
+ throw new Error("Parsed document storage path part must be a non-empty value.");
4353
+ }
4354
+ return createHash3("sha256").update(normalized).digest("hex").slice(0, 24);
4383
4355
  }
4384
4356
  function normalizeRelativeStoragePath(value) {
4385
4357
  const normalized = value.replaceAll("\\", "/").replace(/^\.\/+/, "");