@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.js CHANGED
@@ -1590,10 +1590,6 @@ var import_jszip2 = __toESM(require("jszip"));
1590
1590
  var pageCitationAssetsMetadataKey = "pageAssets";
1591
1591
  var defaultImageContentType = "application/octet-stream";
1592
1592
  var tableContentType = "text/html; charset=utf-8";
1593
- var snapshotManifestKey = "manifest/current.json";
1594
- var snapshotIndexKey = "index.json";
1595
- var defaultSnapshotChunkPageSize = 200;
1596
- var snapshotJsonContentType = "application/json; charset=utf-8";
1597
1593
  async function storeParseResultAssets(result, options) {
1598
1594
  if (!options) {
1599
1595
  return {
@@ -1611,148 +1607,11 @@ async function storeParseResultAssets(result, options) {
1611
1607
  }
1612
1608
  }
1613
1609
  const normalizedResult = Object.keys(assetUrlsByFilePath).length === 0 ? result : rewriteResultAssetUrls(result, assetUrlsByFilePath);
1614
- const snapshot = await storeParsedSnapshot({
1615
- result: normalizedResult,
1616
- assetUrlsByFilePath,
1617
- keyPrefix: normalizedKeyPrefix,
1618
- options
1619
- });
1620
1610
  return {
1621
1611
  result: normalizedResult,
1622
- assetUrlsByFilePath,
1623
- snapshot
1624
- };
1625
- }
1626
- async function storeParsedSnapshot(input) {
1627
- const pageSize = normalizeSnapshotChunkPageSize(input.options.chunkPageSize);
1628
- const totalChunks = input.result.chunks.length;
1629
- const totalPages = Math.max(1, Math.ceil(totalChunks / pageSize));
1630
- const chunkPageReferences = [];
1631
- const chunkPageUrlsByPage = {};
1632
- for (let page = 1; page <= totalPages; page += 1) {
1633
- const pageChunks = input.result.chunks.slice((page - 1) * pageSize, page * pageSize);
1634
- const pageKey = `${input.keyPrefix}/chunks/page-${page}.json`;
1635
- const chunkPage = {
1636
- version: 1,
1637
- jobId: input.result.jobId,
1638
- revisionKey: input.options.revisionKey ?? input.result.jobId,
1639
- documentId: input.result.documentId,
1640
- namespace: input.result.namespace,
1641
- sourceFileName: input.result.manifest.sourceFileName,
1642
- page,
1643
- pageSize,
1644
- total: totalChunks,
1645
- totalPages,
1646
- chunks: pageChunks.map(
1647
- (chunk, index) => toSnapshotChunk(chunk, (page - 1) * pageSize + index + 1)
1648
- )
1649
- };
1650
- const pageUrl = await writeJsonObject({
1651
- key: pageKey,
1652
- value: chunkPage,
1653
- adapter: input.options.adapter
1654
- });
1655
- if (pageUrl) chunkPageUrlsByPage[page] = pageUrl;
1656
- chunkPageReferences.push({
1657
- page,
1658
- pageSize,
1659
- chunkCount: pageChunks.length,
1660
- key: pageKey,
1661
- url: pageUrl
1662
- });
1663
- }
1664
- const manifest = {
1665
- version: 1,
1666
- kind: "knowhere-parsed-result-snapshot",
1667
- jobId: input.result.jobId,
1668
- revisionKey: input.options.revisionKey ?? input.result.jobId,
1669
- documentId: input.result.documentId,
1670
- namespace: input.result.namespace,
1671
- sourceFileName: input.result.manifest.sourceFileName,
1672
- totalChunks,
1673
- typeCounts: countSnapshotChunkTypes(input.result.chunks),
1674
- chunkPageSize: pageSize,
1675
- chunkPages: chunkPageReferences,
1676
- assetUrlsByFilePath: input.assetUrlsByFilePath,
1677
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
1678
- };
1679
- const manifestKey = `${input.keyPrefix}/${snapshotManifestKey}`;
1680
- const indexKey = `${input.keyPrefix}/${snapshotIndexKey}`;
1681
- const manifestUrl = await writeJsonObject({
1682
- key: manifestKey,
1683
- value: manifest,
1684
- adapter: input.options.adapter
1685
- });
1686
- const indexUrl = await writeJsonObject({
1687
- key: indexKey,
1688
- value: manifest,
1689
- adapter: input.options.adapter
1690
- });
1691
- return {
1692
- manifest,
1693
- manifestKey,
1694
- manifestUrl,
1695
- indexKey,
1696
- indexUrl,
1697
- chunkPageUrlsByPage
1698
- };
1699
- }
1700
- function countSnapshotChunkTypes(chunks) {
1701
- return chunks.reduce(
1702
- (counts, chunk) => {
1703
- counts[chunk.type] += 1;
1704
- return counts;
1705
- },
1706
- { text: 0, image: 0, table: 0, page: 0 }
1707
- );
1708
- }
1709
- async function writeJsonObject(input) {
1710
- const result = await input.adapter.writeObject({
1711
- key: input.key,
1712
- body: Buffer.from(JSON.stringify(input.value, null, 2), "utf8"),
1713
- contentType: snapshotJsonContentType,
1714
- metadata: {
1715
- kind: "knowhere-parsed-result-snapshot"
1716
- }
1717
- });
1718
- return result.url ?? await input.adapter.getObjectUrl?.(result.key) ?? void 0;
1719
- }
1720
- function normalizeSnapshotChunkPageSize(value) {
1721
- if (!Number.isInteger(value) || value === void 0) return defaultSnapshotChunkPageSize;
1722
- return Math.min(Math.max(value, 1), 1e3);
1723
- }
1724
- function toSnapshotChunk(chunk, position) {
1725
- const filePath = getSnapshotChunkFilePath(chunk);
1726
- return {
1727
- id: chunk.chunkId,
1728
- chunkId: chunk.chunkId,
1729
- chunkType: chunk.type,
1730
- contentSource: chunk.contentSource,
1731
- content: chunk.content,
1732
- sectionPath: normalizeSnapshotSectionPath(chunk.path),
1733
- sourceChunkPath: chunk.path,
1734
- filePath,
1735
- sortOrder: position,
1736
- metadata: cloneChunkMetadata(chunk.metadata),
1737
- assetUrl: getSnapshotChunkAssetUrl(chunk)
1612
+ assetUrlsByFilePath
1738
1613
  };
1739
1614
  }
1740
- function normalizeSnapshotSectionPath(path4) {
1741
- return path4.length > 0 ? path4 : void 0;
1742
- }
1743
- function getSnapshotChunkFilePath(chunk) {
1744
- if (chunk.type === "image" || chunk.type === "table") {
1745
- return chunk.filePath;
1746
- }
1747
- const filePath = chunk.metadata.filePath;
1748
- return typeof filePath === "string" ? filePath : void 0;
1749
- }
1750
- function getSnapshotChunkAssetUrl(chunk) {
1751
- return chunk.type === "image" || chunk.type === "table" ? chunk.assetUrl : void 0;
1752
- }
1753
- function cloneChunkMetadata(metadata) {
1754
- return { ...metadata };
1755
- }
1756
1615
  async function collectStorageAssets(result, keyPrefix) {
1757
1616
  const resultZip = await loadResultZipForPageCitationAssets(result);
1758
1617
  return [
@@ -1989,108 +1848,212 @@ function isRecord(value) {
1989
1848
  }
1990
1849
 
1991
1850
  // src/storage/parsed-document-storage.ts
1992
- var parsedStorageKeyPrefix = "parsed";
1993
- var manifestStoragePath = "manifest/current.json";
1994
- var indexStoragePath = "index.json";
1995
- var chunkPagePathPattern = /^chunks\/page-(\d+)\.json$/;
1851
+ var import_jszip3 = __toESM(require("jszip"));
1852
+ var parsedDocumentCommitPath = ".knowhere-sdk/commit.json";
1853
+ var jsonContentType = "application/json; charset=utf-8";
1854
+ var markdownContentType = "text/markdown; charset=utf-8";
1855
+ var csvContentType = "text/csv; charset=utf-8";
1856
+ var htmlContentType = "text/html; charset=utf-8";
1857
+ var binaryContentType = "application/octet-stream";
1996
1858
  async function syncParseResultToParsedDocumentStorage(params) {
1997
1859
  const documentId = params.documentId ?? params.result.documentId ?? params.result.jobId;
1998
1860
  const revisionKey = params.revisionKey ?? params.result.jobId;
1999
- const adapter = createParsedDocumentObjectStorageAdapter({
2000
- storage: params.storage,
1861
+ const objects = await collectResultLayoutObjects(params.result);
1862
+ for (const object of objects) {
1863
+ await params.storage.writeObject({
1864
+ documentId,
1865
+ revisionKey,
1866
+ ...object
1867
+ });
1868
+ }
1869
+ const commit = {
1870
+ version: 1,
2001
1871
  documentId,
2002
- revisionKey
2003
- });
2004
- const stored = await storeParseResultAssets(params.result, {
2005
- adapter,
2006
- keyPrefix: parsedStorageKeyPrefix,
2007
- chunkPageSize: params.chunkPageSize,
2008
- revisionKey
1872
+ revisionKey,
1873
+ source: params.source ?? "resultZip",
1874
+ committedAt: (/* @__PURE__ */ new Date()).toISOString()
1875
+ };
1876
+ await writeParsedDocumentJsonObject(params.storage, {
1877
+ documentId,
1878
+ revisionKey,
1879
+ path: parsedDocumentCommitPath,
1880
+ value: commit
2009
1881
  });
2010
1882
  return {
2011
- result: stored.result,
2012
- snapshot: stored.snapshot,
1883
+ result: params.result,
2013
1884
  documentId,
2014
- revisionKey
1885
+ revisionKey,
1886
+ commit
2015
1887
  };
2016
1888
  }
2017
- function createParsedDocumentObjectStorageAdapter(params) {
2018
- return {
2019
- writeObject: (input) => writeParsedStorageObject(params, input),
2020
- headObject: (key) => headParsedStorageObject(params, key),
2021
- getObjectUrl: (key) => getParsedStorageObjectUrl(params, key)
2022
- };
1889
+ async function readParsedDocumentCommit(params) {
1890
+ const object = await params.storage.readObject({
1891
+ documentId: params.documentId,
1892
+ revisionKey: params.revisionKey,
1893
+ path: parsedDocumentCommitPath
1894
+ });
1895
+ if (!object) {
1896
+ return null;
1897
+ }
1898
+ const commit = readJsonObject(object);
1899
+ return commit.revisionKey === params.revisionKey && commit.documentId === params.documentId ? commit : null;
2023
1900
  }
2024
- async function writeParsedStorageObject(params, input) {
2025
- const storagePath = stripParsedStorageKeyPrefix(input.key);
2026
- if (storagePath === manifestStoragePath) {
2027
- const manifest = JSON.parse(
2028
- Buffer.from(input.body).toString("utf8")
2029
- );
2030
- await params.storage.writeManifest({
2031
- documentId: params.documentId,
2032
- revisionKey: params.revisionKey,
2033
- manifest
2034
- });
2035
- return { key: input.key };
1901
+ function readJsonObject(object) {
1902
+ return JSON.parse(Buffer.from(object.body).toString("utf8"));
1903
+ }
1904
+ async function collectResultLayoutObjects(result) {
1905
+ const objectsByPath = /* @__PURE__ */ new Map();
1906
+ const rawZipObjects = await collectRawZipObjects(result.rawZip);
1907
+ for (const object of rawZipObjects) {
1908
+ objectsByPath.set(object.path, object);
1909
+ }
1910
+ for (const object of collectGeneratedResultObjects(result)) {
1911
+ if (!objectsByPath.has(object.path)) {
1912
+ objectsByPath.set(object.path, object);
1913
+ }
1914
+ }
1915
+ return [...objectsByPath.values()].filter((object) => !isSdkMetadataPath(object.path));
1916
+ }
1917
+ async function collectRawZipObjects(rawZip) {
1918
+ try {
1919
+ const zip = await import_jszip3.default.loadAsync(rawZip);
1920
+ const objects = [];
1921
+ for (const entry of Object.values(zip.files)) {
1922
+ if (entry.dir || entry.name === "result.zip") {
1923
+ continue;
1924
+ }
1925
+ objects.push({
1926
+ path: normalizeResultPath(entry.name),
1927
+ body: new Uint8Array(await entry.async("nodebuffer")),
1928
+ contentType: inferContentTypeFromPath(entry.name)
1929
+ });
1930
+ }
1931
+ return objects;
1932
+ } catch {
1933
+ return [];
2036
1934
  }
2037
- if (storagePath === indexStoragePath) {
2038
- return { key: input.key };
1935
+ }
1936
+ function collectGeneratedResultObjects(result) {
1937
+ const objects = [
1938
+ createJsonObject("manifest.json", result.manifest),
1939
+ createJsonObject("chunks.json", keysToSnake(serializeChunks2(result.chunks)))
1940
+ ];
1941
+ if (result.docNav) {
1942
+ objects.push(createJsonObject("doc_nav.json", result.docNav));
1943
+ }
1944
+ if (result.fullMarkdown) {
1945
+ objects.push(createTextObject("full.md", result.fullMarkdown, markdownContentType));
1946
+ }
1947
+ if (result.chunksSlim) {
1948
+ objects.push(createJsonObject("chunks_slim.json", { chunks: result.chunksSlim }));
1949
+ }
1950
+ if (result.hierarchy) {
1951
+ objects.push(createJsonObject("hierarchy.json", result.hierarchy));
1952
+ }
1953
+ if (result.tocHierarchies) {
1954
+ objects.push(createJsonObject("toc_hierarchies.json", result.tocHierarchies));
1955
+ }
1956
+ if (result.kbCsv) {
1957
+ objects.push(createTextObject("kb.csv", result.kbCsv, csvContentType));
2039
1958
  }
2040
- const chunkPageMatch = storagePath.match(chunkPagePathPattern);
2041
- if (chunkPageMatch) {
2042
- const page = JSON.parse(
2043
- Buffer.from(input.body).toString("utf8")
1959
+ if (result.hierarchyViewHtml) {
1960
+ objects.push(
1961
+ createTextObject("hierarchy_view.html", result.hierarchyViewHtml, htmlContentType)
2044
1962
  );
2045
- await params.storage.writeChunkPage({
2046
- documentId: params.documentId,
2047
- revisionKey: params.revisionKey,
2048
- page
1963
+ }
1964
+ for (const chunk of result.imageChunks) {
1965
+ objects.push({
1966
+ path: normalizeResultPath(chunk.filePath),
1967
+ body: new Uint8Array(chunk.data),
1968
+ contentType: inferContentTypeFromPath(chunk.filePath),
1969
+ metadata: {
1970
+ chunkId: chunk.chunkId,
1971
+ chunkType: chunk.type,
1972
+ sourcePath: chunk.filePath
1973
+ }
2049
1974
  });
2050
- return { key: input.key };
2051
1975
  }
2052
- const stored = await params.storage.writeAsset({
2053
- documentId: params.documentId,
2054
- revisionKey: params.revisionKey,
2055
- sourcePath: storagePath,
2056
- body: input.body,
2057
- contentType: input.contentType,
2058
- metadata: input.metadata
2059
- });
1976
+ for (const chunk of result.tableChunks) {
1977
+ objects.push({
1978
+ path: normalizeResultPath(chunk.filePath),
1979
+ body: Buffer.from(chunk.html, "utf8"),
1980
+ contentType: htmlContentType,
1981
+ metadata: {
1982
+ chunkId: chunk.chunkId,
1983
+ chunkType: chunk.type,
1984
+ sourcePath: chunk.filePath
1985
+ }
1986
+ });
1987
+ }
1988
+ return objects;
1989
+ }
1990
+ function serializeChunks2(chunks) {
2060
1991
  return {
2061
- key: input.key,
2062
- url: stored.url
1992
+ chunks: chunks.map((chunk) => {
1993
+ const rawChunk = {
1994
+ chunkId: chunk.chunkId,
1995
+ type: chunk.type,
1996
+ contentSource: chunk.contentSource,
1997
+ content: chunk.content,
1998
+ path: chunk.path,
1999
+ metadata: chunk.metadata
2000
+ };
2001
+ if (chunk.type === "image" || chunk.type === "table") {
2002
+ return {
2003
+ ...rawChunk,
2004
+ filePath: chunk.filePath,
2005
+ assetUrl: chunk.assetUrl
2006
+ };
2007
+ }
2008
+ return rawChunk;
2009
+ })
2063
2010
  };
2064
2011
  }
2065
- async function headParsedStorageObject(params, key) {
2066
- const storagePath = stripParsedStorageKeyPrefix(key);
2067
- if (storagePath === manifestStoragePath || storagePath === indexStoragePath || chunkPagePathPattern.test(storagePath)) {
2068
- return null;
2069
- }
2070
- const url = await params.storage.getAssetUrl({
2012
+ async function writeParsedDocumentJsonObject(storage, params) {
2013
+ await storage.writeObject({
2071
2014
  documentId: params.documentId,
2072
2015
  revisionKey: params.revisionKey,
2073
- sourcePath: storagePath
2016
+ path: params.path,
2017
+ body: Buffer.from(JSON.stringify(params.value, null, 2), "utf8"),
2018
+ contentType: jsonContentType
2074
2019
  });
2075
- return url ? {
2076
- key,
2077
- url
2078
- } : null;
2079
- }
2080
- async function getParsedStorageObjectUrl(params, key) {
2081
- const storagePath = stripParsedStorageKeyPrefix(key);
2082
- if (storagePath === manifestStoragePath || storagePath === indexStoragePath || chunkPagePathPattern.test(storagePath)) {
2083
- return null;
2020
+ }
2021
+ function createJsonObject(path4, value) {
2022
+ return {
2023
+ path: path4,
2024
+ body: Buffer.from(JSON.stringify(value, null, 2), "utf8"),
2025
+ contentType: jsonContentType
2026
+ };
2027
+ }
2028
+ function createTextObject(path4, value, contentType) {
2029
+ return {
2030
+ path: path4,
2031
+ body: Buffer.from(value, "utf8"),
2032
+ contentType
2033
+ };
2034
+ }
2035
+ function inferContentTypeFromPath(filePath) {
2036
+ const lower = filePath.toLowerCase();
2037
+ if (lower.endsWith(".json")) return jsonContentType;
2038
+ if (lower.endsWith(".md")) return markdownContentType;
2039
+ if (lower.endsWith(".csv")) return csvContentType;
2040
+ if (lower.endsWith(".html") || lower.endsWith(".htm")) return htmlContentType;
2041
+ if (lower.endsWith(".png")) return "image/png";
2042
+ if (lower.endsWith(".jpg") || lower.endsWith(".jpeg")) return "image/jpeg";
2043
+ if (lower.endsWith(".gif")) return "image/gif";
2044
+ if (lower.endsWith(".webp")) return "image/webp";
2045
+ if (lower.endsWith(".svg")) return "image/svg+xml";
2046
+ return binaryContentType;
2047
+ }
2048
+ function normalizeResultPath(value) {
2049
+ const normalized = value.replaceAll("\\", "/").replace(/^\.\/+/, "");
2050
+ if (normalized.length === 0 || normalized.includes("\0") || normalized.startsWith("/") || normalized.split("/").some((part) => part.length === 0 || part === "." || part === "..")) {
2051
+ throw new Error(`Invalid parsed result path: ${value}`);
2084
2052
  }
2085
- return params.storage.getAssetUrl({
2086
- documentId: params.documentId,
2087
- revisionKey: params.revisionKey,
2088
- sourcePath: storagePath
2089
- });
2053
+ return normalized;
2090
2054
  }
2091
- function stripParsedStorageKeyPrefix(key) {
2092
- const prefix = `${parsedStorageKeyPrefix}/`;
2093
- return key.startsWith(prefix) ? key.slice(prefix.length) : key;
2055
+ function isSdkMetadataPath(path4) {
2056
+ return path4 === ".knowhere-sdk" || path4.startsWith(".knowhere-sdk/");
2094
2057
  }
2095
2058
 
2096
2059
  // src/knowledge/local-store.ts
@@ -2325,7 +2288,6 @@ var MAX_GREP_LIMIT = 50;
2325
2288
  var DEFAULT_CONTEXT_CHARS = 80;
2326
2289
  var DEFAULT_REMOTE_SCAN_PAGE_SIZE = 100;
2327
2290
  var DEFAULT_MAX_SYNC_PAGES = 10;
2328
- var DEFAULT_MAX_SYNC_ASSETS = 20;
2329
2291
  var DEFAULT_SYNC_DEADLINE_MS = 8e3;
2330
2292
  var DEFAULT_GREP_MAX_PAGES = 50;
2331
2293
  var DEFAULT_GREP_DEADLINE_MS = 8e3;
@@ -2333,6 +2295,7 @@ var DEFAULT_OUTLINE_MAX_PAGES = 50;
2333
2295
  var DEFAULT_OUTLINE_DEADLINE_MS = 8e3;
2334
2296
  var SAFE_LOCAL_DOCUMENT_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
2335
2297
  var REMOTE_DOCUMENT_ID_PATTERN = /^doc[_-]/;
2298
+ var remoteReconstructionPageDirectory = ".knowhere-sdk/remote-reconstruction/pages";
2336
2299
  var Knowledge = class _Knowledge {
2337
2300
  client;
2338
2301
  store;
@@ -2367,8 +2330,7 @@ var Knowledge = class _Knowledge {
2367
2330
  return {
2368
2331
  document,
2369
2332
  result,
2370
- assetUrlsByFilePath: storedAssets.assetUrlsByFilePath,
2371
- parsedSnapshot: storedAssets.snapshot
2333
+ assetUrlsByFilePath: storedAssets.assetUrlsByFilePath
2372
2334
  };
2373
2335
  }
2374
2336
  /** @deprecated Use parseToLocalCache for local cache imports or the top-level client.parse for server-safe parsing. */
@@ -2413,8 +2375,7 @@ var Knowledge = class _Knowledge {
2413
2375
  const result = syncedStorage.result;
2414
2376
  return {
2415
2377
  result,
2416
- assetUrlsByFilePath: storedAssets.assetUrlsByFilePath,
2417
- parsedSnapshot: syncedStorage.snapshot ?? storedAssets.snapshot
2378
+ assetUrlsByFilePath: storedAssets.assetUrlsByFilePath
2418
2379
  };
2419
2380
  }
2420
2381
  async importJobResult(params) {
@@ -2426,8 +2387,7 @@ var Knowledge = class _Knowledge {
2426
2387
  return {
2427
2388
  document,
2428
2389
  result,
2429
- assetUrlsByFilePath: stored.assetUrlsByFilePath,
2430
- parsedSnapshot: stored.parsedSnapshot
2390
+ assetUrlsByFilePath: stored.assetUrlsByFilePath
2431
2391
  };
2432
2392
  }
2433
2393
  /** @deprecated Use importJobResult for local cache imports or loadJobResult for server-safe loads. */
@@ -2450,14 +2410,13 @@ var Knowledge = class _Knowledge {
2450
2410
  result: loadedResult,
2451
2411
  storage: parsedStorageConfig.storage,
2452
2412
  documentId: loadedResult.documentId ?? normalized.localDocumentId ?? normalized.jobId,
2453
- revisionKey: params.revisionKey ?? normalized.jobId,
2454
- chunkPageSize: parsedStorageConfig.limits?.chunkPageSize
2413
+ revisionKey: params.revisionKey ?? normalized.jobId
2455
2414
  });
2456
2415
  return {
2457
2416
  documentId: synced2.documentId,
2458
2417
  revisionKey: synced2.revisionKey,
2459
2418
  completed: true,
2460
- manifest: synced2.snapshot?.manifest
2419
+ commit: synced2.commit
2461
2420
  };
2462
2421
  }
2463
2422
  if (!normalized.localDocumentId) {
@@ -2468,14 +2427,13 @@ var Knowledge = class _Knowledge {
2468
2427
  result,
2469
2428
  storage: parsedStorageConfig.storage,
2470
2429
  documentId: result.documentId ?? normalized.localDocumentId,
2471
- revisionKey: params.revisionKey ?? result.jobId,
2472
- chunkPageSize: parsedStorageConfig.limits?.chunkPageSize
2430
+ revisionKey: params.revisionKey ?? result.jobId
2473
2431
  });
2474
2432
  return {
2475
2433
  documentId: synced.documentId,
2476
2434
  revisionKey: synced.revisionKey,
2477
2435
  completed: true,
2478
- manifest: synced.snapshot?.manifest
2436
+ commit: synced.commit
2479
2437
  };
2480
2438
  }
2481
2439
  async syncParseResultToConfiguredStorage(result) {
@@ -2485,12 +2443,11 @@ var Knowledge = class _Knowledge {
2485
2443
  }
2486
2444
  const synced = await syncParseResultToParsedDocumentStorage({
2487
2445
  result,
2488
- storage: parsedStorageConfig.storage,
2489
- chunkPageSize: parsedStorageConfig.limits?.chunkPageSize
2446
+ storage: parsedStorageConfig.storage
2490
2447
  });
2491
2448
  return {
2492
2449
  result: synced.result,
2493
- snapshot: synced.snapshot
2450
+ commit: synced.commit
2494
2451
  };
2495
2452
  }
2496
2453
  async parseWithoutClientStorageAdapter(params) {
@@ -2741,10 +2698,7 @@ var Knowledge = class _Knowledge {
2741
2698
  page: pageParams.page,
2742
2699
  pageSize: pageParams.pageSize,
2743
2700
  chunkType: params.chunkType,
2744
- includeAssetUrls: shouldRequestRemoteAssetUrls(
2745
- params.assetUrlPolicy,
2746
- this.parsedStorageConfig
2747
- )
2701
+ includeAssetUrls: true
2748
2702
  });
2749
2703
  const revisionKey = getRemoteRevisionKey(remotePage);
2750
2704
  const stored = await this.tryReadChunksFromParsedStorage({
@@ -2755,12 +2709,7 @@ var Knowledge = class _Knowledge {
2755
2709
  if (stored) {
2756
2710
  return stored;
2757
2711
  }
2758
- const chunks = await this.toRemoteReadChunks({
2759
- documentId,
2760
- revisionKey,
2761
- chunks: remotePage.chunks,
2762
- assetUrlPolicy: params.assetUrlPolicy
2763
- });
2712
+ const chunks = remotePage.chunks.map((chunk) => toRemoteReadChunk(chunk));
2764
2713
  this.scheduleParsedStorageSync(documentId, revisionKey);
2765
2714
  return {
2766
2715
  document: createRemoteKnowledgeDocument({
@@ -2793,10 +2742,7 @@ var Knowledge = class _Knowledge {
2793
2742
  page: 1,
2794
2743
  pageSize: limits.remotePageSize,
2795
2744
  chunkType: params.chunkType,
2796
- includeAssetUrls: shouldRequestRemoteAssetUrls(
2797
- params.assetUrlPolicy,
2798
- this.parsedStorageConfig
2799
- )
2745
+ includeAssetUrls: true
2800
2746
  });
2801
2747
  const revisionKey = getRemoteRevisionKey(firstPage);
2802
2748
  const stored = await this.tryReadChunksFromParsedStorage({
@@ -2823,18 +2769,10 @@ var Knowledge = class _Knowledge {
2823
2769
  page,
2824
2770
  pageSize: limits.remotePageSize,
2825
2771
  chunkType: params.chunkType,
2826
- includeAssetUrls: shouldRequestRemoteAssetUrls(
2827
- params.assetUrlPolicy,
2828
- this.parsedStorageConfig
2829
- )
2772
+ includeAssetUrls: true
2830
2773
  });
2831
2774
  }
2832
- const chunks = await this.toRemoteReadChunks({
2833
- documentId,
2834
- revisionKey,
2835
- chunks: selected.slice(0, limit),
2836
- assetUrlPolicy: params.assetUrlPolicy
2837
- });
2775
+ const chunks = selected.slice(0, limit).map((chunk) => toRemoteReadChunk(chunk));
2838
2776
  this.scheduleParsedStorageSync(documentId, revisionKey);
2839
2777
  return {
2840
2778
  document: createRemoteKnowledgeDocument({
@@ -2870,7 +2808,7 @@ var Knowledge = class _Knowledge {
2870
2808
  page: startPage,
2871
2809
  pageSize: limits.remotePageSize,
2872
2810
  chunkType: params.chunkType,
2873
- includeAssetUrls: false
2811
+ includeAssetUrls: true
2874
2812
  });
2875
2813
  const revisionKey = getRemoteRevisionKey(firstPage);
2876
2814
  const stored = startPage === 1 ? await this.tryGrepChunksFromParsedStorage({
@@ -2967,7 +2905,7 @@ var Knowledge = class _Knowledge {
2967
2905
  page,
2968
2906
  pageSize: limits.remotePageSize,
2969
2907
  chunkType: params.chunkType,
2970
- includeAssetUrls: false
2908
+ includeAssetUrls: true
2971
2909
  });
2972
2910
  }
2973
2911
  }
@@ -2982,7 +2920,7 @@ var Knowledge = class _Knowledge {
2982
2920
  const firstPage = await this.client.documents.listChunks(documentId, {
2983
2921
  page: 1,
2984
2922
  pageSize: limits.remotePageSize,
2985
- includeAssetUrls: false
2923
+ includeAssetUrls: true
2986
2924
  });
2987
2925
  const revisionKey = getRemoteRevisionKey(firstPage);
2988
2926
  const stored = await this.tryReadOutlineFromParsedStorage(documentId, revisionKey);
@@ -3004,7 +2942,7 @@ var Knowledge = class _Knowledge {
3004
2942
  response = await this.client.documents.listChunks(documentId, {
3005
2943
  page,
3006
2944
  pageSize: limits.remotePageSize,
3007
- includeAssetUrls: false
2945
+ includeAssetUrls: true
3008
2946
  });
3009
2947
  }
3010
2948
  const truncated = response.pagination.page < response.pagination.totalPages;
@@ -3030,28 +2968,13 @@ var Knowledge = class _Knowledge {
3030
2968
  };
3031
2969
  }
3032
2970
  async tryReadChunksFromParsedStorage(params) {
3033
- const parsedStorageConfig = this.parsedStorageConfig;
3034
- if (!parsedStorageConfig) {
3035
- return null;
3036
- }
3037
- const manifest = await this.readFreshParsedStorageManifest(
2971
+ const storedResult = await this.readCommittedParsedStorageResult(
3038
2972
  params.documentId,
3039
2973
  params.revisionKey
3040
2974
  );
3041
- if (!manifest) {
3042
- return null;
3043
- }
2975
+ if (!storedResult) return null;
3044
2976
  const pageParams = getReadPageParams(params.params);
3045
- const indexedChunks = await this.readStoredSnapshotChunks({
3046
- documentId: params.documentId,
3047
- revisionKey: params.revisionKey,
3048
- manifest,
3049
- chunkType: params.params.chunkType
3050
- });
3051
- if (!indexedChunks) {
3052
- return null;
3053
- }
3054
- const scopedChunks = indexedChunks.filter((chunk) => matchesReadScope(chunk, params.params));
2977
+ const scopedChunks = storedResult.chunks.filter((chunk) => !params.params.chunkType || chunk.chunkType === params.params.chunkType).filter((chunk) => matchesReadScope(chunk, params.params));
3055
2978
  const selected = hasScanReadFilters(params.params) ? selectReadWindow(
3056
2979
  scopedChunks,
3057
2980
  params.params,
@@ -3060,17 +2983,18 @@ var Knowledge = class _Knowledge {
3060
2983
  (pageParams.page - 1) * pageParams.pageSize,
3061
2984
  pageParams.page * pageParams.pageSize
3062
2985
  );
3063
- const visibleChunks = applyAssetUrlPolicyToReadChunks(
3064
- selected.map(toReadChunk),
3065
- params.params.assetUrlPolicy
3066
- );
2986
+ const visibleChunks = await applyStoredAssetUrlsToReadChunks({
2987
+ storageConfig: this.requireParsedStorageConfig(),
2988
+ documentId: params.documentId,
2989
+ revisionKey: params.revisionKey,
2990
+ chunks: selected.map(toReadChunk)
2991
+ });
3067
2992
  const totalChunks = scopedChunks.length;
3068
2993
  return {
3069
2994
  document: createStoredKnowledgeDocument({
3070
2995
  documentId: params.documentId,
3071
- manifest,
3072
- revisionKey: params.revisionKey,
3073
- typeCounts: countIndexedTypes(indexedChunks)
2996
+ storedResult,
2997
+ revisionKey: params.revisionKey
3074
2998
  }),
3075
2999
  chunks: visibleChunks,
3076
3000
  page: hasScanReadFilters(params.params) ? void 0 : pageParams.page,
@@ -3081,30 +3005,15 @@ var Knowledge = class _Knowledge {
3081
3005
  };
3082
3006
  }
3083
3007
  async tryGrepChunksFromParsedStorage(params) {
3084
- const parsedStorageConfig = this.parsedStorageConfig;
3085
- if (!parsedStorageConfig) {
3086
- return null;
3087
- }
3088
- const manifest = await this.readFreshParsedStorageManifest(
3008
+ const storedResult = await this.readCommittedParsedStorageResult(
3089
3009
  params.documentId,
3090
3010
  params.revisionKey
3091
3011
  );
3092
- if (!manifest) {
3093
- return null;
3094
- }
3095
- const indexedChunks = await this.readStoredSnapshotChunks({
3096
- documentId: params.documentId,
3097
- revisionKey: params.revisionKey,
3098
- manifest,
3099
- chunkType: params.params.chunkType
3100
- });
3101
- if (!indexedChunks) {
3102
- return null;
3103
- }
3012
+ if (!storedResult) return null;
3104
3013
  const maxResults = clampLimit(params.params.maxResults, DEFAULT_GREP_LIMIT, MAX_GREP_LIMIT);
3105
3014
  const contextChars = params.params.contextChars ?? DEFAULT_CONTEXT_CHARS;
3106
3015
  const matcher = createMatcher(params.params);
3107
- const scopedChunks = indexedChunks.filter((chunk) => matchesGrepScope(chunk, params.params));
3016
+ const scopedChunks = storedResult.chunks.filter((chunk) => !params.params.chunkType || chunk.chunkType === params.params.chunkType).filter((chunk) => matchesGrepScope(chunk, params.params));
3108
3017
  const matches = [];
3109
3018
  let scannedChunks = 0;
3110
3019
  for (const chunk of scopedChunks) {
@@ -3125,9 +3034,8 @@ var Knowledge = class _Knowledge {
3125
3034
  return {
3126
3035
  document: createStoredKnowledgeDocument({
3127
3036
  documentId: params.documentId,
3128
- manifest,
3129
- revisionKey: params.revisionKey,
3130
- typeCounts: countIndexedTypes(indexedChunks)
3037
+ storedResult,
3038
+ revisionKey: params.revisionKey
3131
3039
  }),
3132
3040
  matches,
3133
3041
  scannedChunks,
@@ -3139,9 +3047,8 @@ var Knowledge = class _Knowledge {
3139
3047
  return {
3140
3048
  document: createStoredKnowledgeDocument({
3141
3049
  documentId: params.documentId,
3142
- manifest,
3143
- revisionKey: params.revisionKey,
3144
- typeCounts: countIndexedTypes(indexedChunks)
3050
+ storedResult,
3051
+ revisionKey: params.revisionKey
3145
3052
  }),
3146
3053
  matches,
3147
3054
  scannedChunks,
@@ -3149,98 +3056,82 @@ var Knowledge = class _Knowledge {
3149
3056
  };
3150
3057
  }
3151
3058
  async tryReadOutlineFromParsedStorage(documentId, revisionKey) {
3152
- const manifest = await this.readFreshParsedStorageManifest(documentId, revisionKey);
3153
- if (!manifest) {
3154
- return null;
3155
- }
3156
- const indexedChunks = await this.readStoredSnapshotChunks({
3157
- documentId,
3158
- revisionKey,
3159
- manifest
3160
- });
3161
- if (!indexedChunks) {
3162
- return null;
3163
- }
3164
- const sections = buildFlatSectionsFromIndexedChunks(indexedChunks);
3165
- const typeCounts = countIndexedTypes(indexedChunks);
3059
+ const storedResult = await this.readCommittedParsedStorageResult(documentId, revisionKey);
3060
+ if (!storedResult) return null;
3061
+ const sections = storedResult.docNav?.sections && storedResult.docNav.sections.length > 0 ? flattenSections(
3062
+ storedResult.docNav.sections.map(
3063
+ (section) => toKnowledgeSection(
3064
+ section,
3065
+ storedResult.chunks,
3066
+ storedResult.manifest.sourceFileName
3067
+ )
3068
+ )
3069
+ ) : buildFlatSectionsFromIndexedChunks(storedResult.chunks);
3166
3070
  return {
3167
3071
  document: createStoredKnowledgeDocument({
3168
3072
  documentId,
3169
- manifest,
3170
- revisionKey,
3171
- typeCounts
3073
+ storedResult,
3074
+ revisionKey
3172
3075
  }),
3173
- totalChunks: manifest.totalChunks,
3174
- typeCounts,
3076
+ totalChunks: storedResult.chunks.length,
3077
+ typeCounts: storedResult.typeCounts,
3175
3078
  sections,
3176
- sectionTree: nestSections(sections),
3079
+ sectionTree: storedResult.docNav?.sections && storedResult.docNav.sections.length > 0 ? storedResult.docNav.sections.map(
3080
+ (section) => toKnowledgeSection(
3081
+ section,
3082
+ storedResult.chunks,
3083
+ storedResult.manifest.sourceFileName
3084
+ )
3085
+ ) : nestSections(sections),
3177
3086
  truncated: false
3178
3087
  };
3179
3088
  }
3180
- async readFreshParsedStorageManifest(documentId, revisionKey) {
3089
+ async readCommittedParsedStorageResult(documentId, revisionKey) {
3181
3090
  const parsedStorageConfig = this.parsedStorageConfig;
3182
3091
  if (!parsedStorageConfig) {
3183
3092
  return null;
3184
3093
  }
3185
- const manifest = await parsedStorageConfig.storage.readManifest({
3094
+ const commit = await readParsedDocumentCommit({
3095
+ storage: parsedStorageConfig.storage,
3186
3096
  documentId,
3187
3097
  revisionKey
3188
3098
  });
3189
- if (!manifest || !isFreshManifest(manifest, revisionKey)) {
3099
+ if (!commit) {
3190
3100
  return null;
3191
3101
  }
3192
- return manifest;
3193
- }
3194
- async readStoredSnapshotChunks(params) {
3195
- const parsedStorageConfig = this.parsedStorageConfig;
3196
- if (!parsedStorageConfig) {
3102
+ const [manifestObject, chunksObject, docNavObject] = await Promise.all([
3103
+ parsedStorageConfig.storage.readObject({
3104
+ documentId,
3105
+ revisionKey,
3106
+ path: "manifest.json"
3107
+ }),
3108
+ parsedStorageConfig.storage.readObject({
3109
+ documentId,
3110
+ revisionKey,
3111
+ path: "chunks.json"
3112
+ }),
3113
+ parsedStorageConfig.storage.readObject({
3114
+ documentId,
3115
+ revisionKey,
3116
+ path: "doc_nav.json"
3117
+ })
3118
+ ]);
3119
+ if (!manifestObject || !chunksObject) {
3197
3120
  return null;
3198
3121
  }
3199
- const chunks = [];
3200
- for (const pageReference of params.manifest.chunkPages) {
3201
- const page = await parsedStorageConfig.storage.readChunkPage({
3202
- documentId: params.documentId,
3203
- revisionKey: params.revisionKey,
3204
- page: pageReference.page,
3205
- chunkType: params.chunkType
3206
- });
3207
- if (!page) {
3208
- return null;
3209
- }
3210
- chunks.push(
3211
- ...page.chunks.filter((chunk) => !params.chunkType || chunk.chunkType === params.chunkType).map(toIndexedSnapshotChunk)
3212
- );
3213
- }
3214
- return chunks.sort((left, right) => left.position - right.position);
3215
- }
3216
- async toRemoteReadChunks(params) {
3217
- const readChunks = params.chunks.map((chunk) => toRemoteReadChunk(chunk));
3218
- if (params.assetUrlPolicy === "durable") {
3219
- return this.hardenReadChunkAssetUrls({
3220
- documentId: params.documentId,
3221
- revisionKey: params.revisionKey,
3222
- chunks: readChunks
3223
- });
3224
- }
3225
- return applyAssetUrlPolicyToReadChunks(readChunks, params.assetUrlPolicy);
3226
- }
3227
- async hardenReadChunkAssetUrls(params) {
3228
- const parsedStorageConfig = this.parsedStorageConfig;
3229
- if (!parsedStorageConfig) {
3230
- return applyAssetUrlPolicyToReadChunks(params.chunks, "none");
3231
- }
3232
- const hardenedChunks = [];
3233
- for (const chunk of params.chunks) {
3234
- hardenedChunks.push(
3235
- await hardenReadChunkAssetUrls({
3236
- storageConfig: parsedStorageConfig,
3237
- documentId: params.documentId,
3238
- revisionKey: params.revisionKey,
3239
- chunk
3240
- })
3241
- );
3242
- }
3243
- return hardenedChunks;
3122
+ const manifest = readJsonObject(manifestObject);
3123
+ const chunks = parseStoredResultChunks({
3124
+ payload: readJsonObject(chunksObject),
3125
+ sourceFileName: manifest.sourceFileName
3126
+ });
3127
+ const docNav = docNavObject ? readJsonObject(docNavObject) : void 0;
3128
+ return {
3129
+ commit,
3130
+ manifest,
3131
+ chunks,
3132
+ docNav: docNav?.sections ? { sections: docNav.sections } : void 0,
3133
+ typeCounts: countIndexedTypes(chunks)
3134
+ };
3244
3135
  }
3245
3136
  scheduleParsedStorageSync(documentId, revisionKey) {
3246
3137
  const parsedStorageConfig = this.parsedStorageConfig;
@@ -3260,7 +3151,6 @@ var Knowledge = class _Knowledge {
3260
3151
  documentId,
3261
3152
  revisionKey,
3262
3153
  nextChunkPage: 1,
3263
- nextAssetIndex: 0,
3264
3154
  status: "failed",
3265
3155
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3266
3156
  error: error instanceof Error ? error.message : String(error)
@@ -3270,28 +3160,63 @@ var Knowledge = class _Knowledge {
3270
3160
  void Promise.resolve(scheduler.schedule(task)).catch(() => void 0);
3271
3161
  }
3272
3162
  async syncRemoteDocumentToParsedStorage(params) {
3273
- const limits = getParsedStorageLimits(params.parsedStorageConfig.limits);
3274
- const existingProgress = params.revisionKey ? await params.parsedStorageConfig.storage.readSyncProgress({
3275
- documentId: params.documentId,
3276
- revisionKey: params.revisionKey
3277
- }) : null;
3278
- let nextPage = existingProgress?.status === "running" ? existingProgress.nextChunkPage : 1;
3279
- let response = await this.client.documents.listChunks(params.documentId, {
3280
- page: nextPage,
3281
- pageSize: limits.remotePageSize,
3163
+ const firstPage = await this.client.documents.listChunks(params.documentId, {
3164
+ page: 1,
3165
+ pageSize: 1,
3282
3166
  includeAssetUrls: true
3283
3167
  });
3284
- const revisionKey = params.revisionKey ?? getRemoteRevisionKey(response);
3285
- if (params.revisionKey && getRemoteRevisionKey(response) !== params.revisionKey) {
3286
- response = await this.client.documents.listChunks(params.documentId, {
3287
- page: 1,
3288
- pageSize: limits.remotePageSize,
3289
- includeAssetUrls: true
3168
+ const revisionKey = params.revisionKey ?? getRemoteRevisionKey(firstPage);
3169
+ if (params.revisionKey && getRemoteRevisionKey(firstPage) !== params.revisionKey) {
3170
+ return this.syncRemoteDocumentToParsedStorage({
3171
+ documentId: params.documentId,
3172
+ parsedStorageConfig: params.parsedStorageConfig
3290
3173
  });
3291
- nextPage = 1;
3292
3174
  }
3293
- const totalPages = response.pagination.totalPages;
3294
- const chunkPages = [];
3175
+ if (firstPage.jobId) {
3176
+ try {
3177
+ const loadedResult = await this.client.jobs.load(firstPage.jobId);
3178
+ const synced = await syncParseResultToParsedDocumentStorage({
3179
+ result: loadedResult,
3180
+ storage: params.parsedStorageConfig.storage,
3181
+ documentId: params.documentId,
3182
+ revisionKey,
3183
+ source: "resultZip"
3184
+ });
3185
+ await params.parsedStorageConfig.storage.writeSyncProgress({
3186
+ documentId: params.documentId,
3187
+ revisionKey,
3188
+ status: "completed",
3189
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
3190
+ });
3191
+ return {
3192
+ documentId: synced.documentId,
3193
+ revisionKey: synced.revisionKey,
3194
+ completed: true,
3195
+ commit: synced.commit
3196
+ };
3197
+ } catch {
3198
+ }
3199
+ }
3200
+ return this.syncRemoteDocumentChunksToParsedStorage({
3201
+ documentId: params.documentId,
3202
+ revisionKey,
3203
+ firstPage,
3204
+ parsedStorageConfig: params.parsedStorageConfig
3205
+ });
3206
+ }
3207
+ async syncRemoteDocumentChunksToParsedStorage(params) {
3208
+ const limits = getParsedStorageLimits(params.parsedStorageConfig.limits);
3209
+ const existingProgress = await params.parsedStorageConfig.storage.readSyncProgress({
3210
+ documentId: params.documentId,
3211
+ revisionKey: params.revisionKey
3212
+ });
3213
+ let nextPage = existingProgress?.status === "running" ? existingProgress.nextChunkPage ?? 1 : 1;
3214
+ let response = nextPage === 1 && params.firstPage.pagination.pageSize === limits.remotePageSize ? params.firstPage : await this.client.documents.listChunks(params.documentId, {
3215
+ page: nextPage,
3216
+ pageSize: limits.remotePageSize,
3217
+ includeAssetUrls: true
3218
+ });
3219
+ const totalPages = response.pagination.totalPages;
3295
3220
  let syncedPages = 0;
3296
3221
  const startedAt = Date.now();
3297
3222
  while (nextPage <= totalPages) {
@@ -3302,65 +3227,88 @@ var Knowledge = class _Knowledge {
3302
3227
  includeAssetUrls: true
3303
3228
  });
3304
3229
  }
3305
- const readChunks = await this.hardenReadChunkAssetUrls({
3230
+ await params.parsedStorageConfig.storage.writeObject({
3306
3231
  documentId: params.documentId,
3307
- revisionKey,
3308
- chunks: response.chunks.map(toRemoteReadChunk)
3309
- });
3310
- const page = toSnapshotChunkPageFromReadChunks({
3311
- response,
3312
- revisionKey,
3313
- chunks: readChunks
3314
- });
3315
- await params.parsedStorageConfig.storage.writeChunkPage({
3316
- documentId: params.documentId,
3317
- revisionKey,
3318
- page
3232
+ revisionKey: params.revisionKey,
3233
+ path: getRemoteReconstructionPagePath(response.pagination.page),
3234
+ body: Buffer.from(JSON.stringify({ chunks: response.chunks }), "utf8"),
3235
+ contentType: "application/json; charset=utf-8"
3319
3236
  });
3320
- chunkPages.push(page);
3321
3237
  nextPage += 1;
3322
3238
  syncedPages += 1;
3323
3239
  await params.parsedStorageConfig.storage.writeSyncProgress({
3324
3240
  documentId: params.documentId,
3325
- revisionKey,
3241
+ revisionKey: params.revisionKey,
3326
3242
  nextChunkPage: nextPage,
3327
- nextAssetIndex: 0,
3328
3243
  status: "running",
3329
3244
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
3330
3245
  });
3331
3246
  if (syncedPages >= limits.maxPagesPerSync || Date.now() - startedAt >= limits.syncDeadlineMs) {
3332
3247
  return {
3333
3248
  documentId: params.documentId,
3334
- revisionKey,
3249
+ revisionKey: params.revisionKey,
3335
3250
  completed: false
3336
3251
  };
3337
3252
  }
3338
3253
  }
3339
- const manifest = createRemoteSnapshotManifest({
3340
- response,
3341
- revisionKey,
3342
- chunkPages
3254
+ const chunks = await this.readRemoteReconstructionChunks({
3255
+ documentId: params.documentId,
3256
+ revisionKey: params.revisionKey,
3257
+ totalPages,
3258
+ parsedStorageConfig: params.parsedStorageConfig
3343
3259
  });
3344
- await params.parsedStorageConfig.storage.writeManifest({
3260
+ if (!chunks) {
3261
+ return {
3262
+ documentId: params.documentId,
3263
+ revisionKey: params.revisionKey,
3264
+ completed: false
3265
+ };
3266
+ }
3267
+ const synced = await syncParseResultToParsedDocumentStorage({
3268
+ result: createMinimalParseResultFromRemoteChunks({
3269
+ documentId: params.documentId,
3270
+ revisionKey: params.revisionKey,
3271
+ response,
3272
+ chunks
3273
+ }),
3274
+ storage: params.parsedStorageConfig.storage,
3345
3275
  documentId: params.documentId,
3346
- revisionKey,
3347
- manifest
3276
+ revisionKey: params.revisionKey,
3277
+ source: "remoteReconstruction"
3348
3278
  });
3349
3279
  await params.parsedStorageConfig.storage.writeSyncProgress({
3350
3280
  documentId: params.documentId,
3351
- revisionKey,
3281
+ revisionKey: params.revisionKey,
3352
3282
  nextChunkPage: totalPages + 1,
3353
- nextAssetIndex: 0,
3354
3283
  status: "completed",
3355
3284
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
3356
3285
  });
3357
3286
  return {
3358
3287
  documentId: params.documentId,
3359
- revisionKey,
3288
+ revisionKey: params.revisionKey,
3360
3289
  completed: true,
3361
- manifest
3290
+ commit: synced.commit
3362
3291
  };
3363
3292
  }
3293
+ async readRemoteReconstructionChunks(params) {
3294
+ const chunks = [];
3295
+ for (let page = 1; page <= params.totalPages; page += 1) {
3296
+ const object = await params.parsedStorageConfig.storage.readObject({
3297
+ documentId: params.documentId,
3298
+ revisionKey: params.revisionKey,
3299
+ path: getRemoteReconstructionPagePath(page)
3300
+ });
3301
+ if (!object) {
3302
+ return null;
3303
+ }
3304
+ const payload = readJsonObject(object);
3305
+ if (!isDocumentChunkArray(payload.chunks)) {
3306
+ return null;
3307
+ }
3308
+ chunks.push(...payload.chunks);
3309
+ }
3310
+ return chunks;
3311
+ }
3364
3312
  requireParsedStorageConfig() {
3365
3313
  if (!this.parsedStorageConfig) {
3366
3314
  throw new ValidationError("parsed document storage is not configured");
@@ -3374,7 +3322,8 @@ var Knowledge = class _Knowledge {
3374
3322
  async getPublishedDocumentJobId(documentId) {
3375
3323
  const response = await this.client.documents.listChunks(documentId, {
3376
3324
  page: 1,
3377
- pageSize: 1
3325
+ pageSize: 1,
3326
+ includeAssetUrls: true
3378
3327
  });
3379
3328
  if (!response.jobId) {
3380
3329
  throw new Error(
@@ -3407,14 +3356,12 @@ var defaultParsedStorageScheduler = {
3407
3356
  };
3408
3357
  function getParsedStorageLimits(limits) {
3409
3358
  return {
3410
- chunkPageSize: clampLimit(limits?.chunkPageSize, DEFAULT_REMOTE_SCAN_PAGE_SIZE, MAX_PAGE_SIZE),
3411
3359
  remotePageSize: clampLimit(
3412
3360
  limits?.remotePageSize,
3413
3361
  DEFAULT_REMOTE_SCAN_PAGE_SIZE,
3414
3362
  MAX_PAGE_SIZE
3415
3363
  ),
3416
3364
  maxPagesPerSync: clampLimit(limits?.maxPagesPerSync, DEFAULT_MAX_SYNC_PAGES, 1e3),
3417
- maxAssetsPerSync: clampLimit(limits?.maxAssetsPerSync, DEFAULT_MAX_SYNC_ASSETS, 1e3),
3418
3365
  syncDeadlineMs: clampLimit(limits?.syncDeadlineMs, DEFAULT_SYNC_DEADLINE_MS, 6e4),
3419
3366
  grepMaxPages: clampLimit(limits?.grepMaxPages, DEFAULT_GREP_MAX_PAGES, 1e3),
3420
3367
  grepDeadlineMs: clampLimit(limits?.grepDeadlineMs, DEFAULT_GREP_DEADLINE_MS, 6e4),
@@ -3423,13 +3370,13 @@ function getParsedStorageLimits(limits) {
3423
3370
  };
3424
3371
  }
3425
3372
  function validateReadParams(params) {
3426
- const usesPagedDisplay = params.page !== void 0 || params.pageSize !== void 0 || params.assetUrlPolicy !== void 0;
3373
+ const usesPagedDisplay = params.page !== void 0 || params.pageSize !== void 0;
3427
3374
  if (!usesPagedDisplay) {
3428
3375
  return;
3429
3376
  }
3430
3377
  if (params.sectionPath !== void 0 || params.startChunk !== void 0 || params.endChunk !== void 0 || params.chunkId !== void 0) {
3431
3378
  throw new ValidationError(
3432
- "page, pageSize, and assetUrlPolicy cannot be combined with sectionPath, startChunk, endChunk, or chunkId"
3379
+ "page and pageSize cannot be combined with sectionPath, startChunk, endChunk, or chunkId"
3433
3380
  );
3434
3381
  }
3435
3382
  }
@@ -3442,9 +3389,6 @@ function getReadPageParams(params) {
3442
3389
  pageSize: clampLimit(params.pageSize ?? params.limit, DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE)
3443
3390
  };
3444
3391
  }
3445
- function shouldRequestRemoteAssetUrls(assetUrlPolicy, parsedStorageConfig) {
3446
- return assetUrlPolicy === "durable" && parsedStorageConfig !== void 0;
3447
- }
3448
3392
  function getRemoteRevisionKey(response) {
3449
3393
  const revisionKey = response.jobResultId ?? response.jobId;
3450
3394
  if (!revisionKey) {
@@ -3454,6 +3398,9 @@ function getRemoteRevisionKey(response) {
3454
3398
  }
3455
3399
  return revisionKey;
3456
3400
  }
3401
+ function getRemoteReconstructionPagePath(page) {
3402
+ return `${remoteReconstructionPageDirectory}/page-${page}.json`;
3403
+ }
3457
3404
  function createRemoteKnowledgeDocument(params) {
3458
3405
  return {
3459
3406
  localDocumentId: params.documentId,
@@ -3468,23 +3415,103 @@ function createRemoteKnowledgeDocument(params) {
3468
3415
  updatedAt: /* @__PURE__ */ new Date(0)
3469
3416
  };
3470
3417
  }
3418
+ function createMinimalParseResultFromRemoteChunks(params) {
3419
+ const chunks = params.chunks.map(toMinimalChunkFromRemoteChunk);
3420
+ const typeCounts = countRemoteChunkTypes(params.chunks);
3421
+ return {
3422
+ manifest: {
3423
+ version: "2.0",
3424
+ jobId: params.response.jobId ?? params.revisionKey,
3425
+ sourceFileName: params.documentId,
3426
+ statistics: {
3427
+ totalChunks: chunks.length,
3428
+ textChunks: typeCounts.text,
3429
+ imageChunks: typeCounts.image,
3430
+ tableChunks: typeCounts.table,
3431
+ pageChunks: typeCounts.page
3432
+ }
3433
+ },
3434
+ chunks,
3435
+ rawZip: Buffer.from(""),
3436
+ namespace: params.response.namespace,
3437
+ documentId: params.documentId,
3438
+ textChunks: chunks.filter(
3439
+ (chunk) => chunk.type === "text"
3440
+ ),
3441
+ imageChunks: chunks.filter(
3442
+ (chunk) => chunk.type === "image"
3443
+ ),
3444
+ tableChunks: chunks.filter(
3445
+ (chunk) => chunk.type === "table"
3446
+ ),
3447
+ pageChunks: chunks.filter(
3448
+ (chunk) => chunk.type === "page"
3449
+ ),
3450
+ jobId: params.response.jobId ?? params.revisionKey,
3451
+ statistics: {
3452
+ totalChunks: chunks.length,
3453
+ textChunks: typeCounts.text,
3454
+ imageChunks: typeCounts.image,
3455
+ tableChunks: typeCounts.table,
3456
+ pageChunks: typeCounts.page
3457
+ },
3458
+ getChunk: (chunkId) => chunks.find((chunk) => chunk.chunkId === chunkId),
3459
+ save: () => Promise.reject(new Error("Minimal remote reconstruction cannot be saved directly."))
3460
+ };
3461
+ }
3462
+ function toMinimalChunkFromRemoteChunk(chunk) {
3463
+ const baseChunk = {
3464
+ chunkId: chunk.chunkId,
3465
+ contentSource: chunk.contentSource ?? void 0,
3466
+ content: chunk.content ?? "",
3467
+ path: chunk.sourceChunkPath ?? chunk.sectionPath ?? "",
3468
+ metadata: cloneMetadata(chunk.metadata)
3469
+ };
3470
+ if (chunk.chunkType === "image") {
3471
+ return {
3472
+ ...baseChunk,
3473
+ type: "image",
3474
+ filePath: chunk.filePath ?? "",
3475
+ assetUrl: chunk.assetUrl ?? void 0,
3476
+ data: Buffer.alloc(0),
3477
+ format: inferContentTypeFromPath2(chunk.filePath ?? "").replace("image/", ""),
3478
+ save: () => Promise.resolve(chunk.filePath ?? "")
3479
+ };
3480
+ }
3481
+ if (chunk.chunkType === "table") {
3482
+ return {
3483
+ ...baseChunk,
3484
+ type: "table",
3485
+ filePath: chunk.filePath ?? "",
3486
+ assetUrl: chunk.assetUrl ?? void 0,
3487
+ html: chunk.content ?? "",
3488
+ save: () => Promise.resolve(chunk.filePath ?? "")
3489
+ };
3490
+ }
3491
+ if (chunk.chunkType === "page") {
3492
+ return {
3493
+ ...baseChunk,
3494
+ type: "page"
3495
+ };
3496
+ }
3497
+ return {
3498
+ ...baseChunk,
3499
+ type: "text"
3500
+ };
3501
+ }
3471
3502
  function createStoredKnowledgeDocument(params) {
3472
3503
  return {
3473
3504
  localDocumentId: params.documentId,
3474
- jobId: params.manifest.jobId || params.revisionKey,
3475
- documentId: params.manifest.documentId ?? params.documentId,
3476
- namespace: params.manifest.namespace,
3477
- sourceFileName: params.manifest.sourceFileName,
3478
- chunkCount: params.manifest.totalChunks,
3479
- typeCounts: params.typeCounts,
3505
+ jobId: params.storedResult.manifest.jobId || params.revisionKey,
3506
+ documentId: params.documentId,
3507
+ sourceFileName: params.storedResult.manifest.sourceFileName,
3508
+ chunkCount: params.storedResult.chunks.length,
3509
+ typeCounts: params.storedResult.typeCounts,
3480
3510
  resultDirectoryPath: `parsed-storage:${params.documentId}`,
3481
- createdAt: new Date(params.manifest.createdAt),
3482
- updatedAt: new Date(params.manifest.createdAt)
3511
+ createdAt: new Date(params.storedResult.commit.committedAt),
3512
+ updatedAt: new Date(params.storedResult.commit.committedAt)
3483
3513
  };
3484
3514
  }
3485
- function isFreshManifest(manifest, revisionKey) {
3486
- return (manifest.revisionKey ?? manifest.jobId) === revisionKey;
3487
- }
3488
3515
  function toRemoteReadChunk(chunk) {
3489
3516
  const metadata = cloneMetadata(chunk.metadata);
3490
3517
  return {
@@ -3513,22 +3540,60 @@ function toIndexedRemoteChunk(chunk) {
3513
3540
  const readChunk = toRemoteReadChunk(chunk);
3514
3541
  return toIndexedReadChunk(readChunk);
3515
3542
  }
3516
- function toIndexedSnapshotChunk(chunk) {
3517
- return toIndexedReadChunk({
3518
- position: chunk.sortOrder,
3519
- chunkId: chunk.chunkId,
3520
- chunkType: chunk.chunkType,
3521
- contentSource: chunk.contentSource,
3522
- content: chunk.content,
3523
- readableContent: chunk.chunkType === "page" && typeof chunk.metadata.summary === "string" && chunk.metadata.summary.trim().length > 0 ? chunk.metadata.summary : chunk.content,
3524
- sectionPath: chunk.sectionPath ?? "",
3525
- sourceChunkPath: chunk.sourceChunkPath,
3526
- filePath: chunk.filePath,
3527
- assetUrl: chunk.assetUrl,
3528
- pageNumbers: getChunkPageNumbers(chunk.metadata),
3529
- metadata: cloneMetadata(chunk.metadata)
3543
+ function parseStoredResultChunks(params) {
3544
+ const rawChunks = extractStoredChunkRecords(params.payload);
3545
+ return rawChunks.map((record, index) => {
3546
+ const metadata = readRecordMetadata(record);
3547
+ const chunkType = readRecordString(record, "type", "chunkType", "chunk_type");
3548
+ const content = readRecordString(record, "content") ?? "";
3549
+ const sourceChunkPath = readRecordString(record, "path", "sourceChunkPath", "source_chunk_path") ?? "";
3550
+ const chunk = {
3551
+ position: index + 1,
3552
+ chunkId: readRecordString(record, "chunkId", "chunk_id") ?? "",
3553
+ chunkType: isKnowledgeChunkType(chunkType) ? chunkType : "text",
3554
+ contentSource: readRecordString(record, "contentSource", "content_source"),
3555
+ content,
3556
+ readableContent: chunkType === "page" && typeof metadata.summary === "string" && metadata.summary.trim().length > 0 ? metadata.summary : content,
3557
+ sectionPath: normalizeSectionPath(sourceChunkPath, params.sourceFileName),
3558
+ sourceChunkPath,
3559
+ filePath: readRecordString(record, "filePath", "file_path") ?? (typeof metadata.filePath === "string" ? metadata.filePath : void 0),
3560
+ assetUrl: readRecordString(record, "assetUrl", "asset_url"),
3561
+ pageNumbers: getChunkPageNumbers(metadata),
3562
+ metadata
3563
+ };
3564
+ return toIndexedReadChunk(chunk);
3530
3565
  });
3531
3566
  }
3567
+ function extractStoredChunkRecords(payload) {
3568
+ if (Array.isArray(payload)) {
3569
+ return payload.filter(isRecord2);
3570
+ }
3571
+ if (isRecord2(payload) && Array.isArray(payload.chunks)) {
3572
+ return payload.chunks.filter(isRecord2);
3573
+ }
3574
+ return [];
3575
+ }
3576
+ function readRecordString(record, ...keys) {
3577
+ for (const key of keys) {
3578
+ const value = record[key];
3579
+ if (typeof value === "string") return value;
3580
+ }
3581
+ return void 0;
3582
+ }
3583
+ function readRecordNumber(record, ...keys) {
3584
+ for (const key of keys) {
3585
+ const value = record[key];
3586
+ if (typeof value === "number") return value;
3587
+ }
3588
+ return void 0;
3589
+ }
3590
+ function readRecordMetadata(record) {
3591
+ const metadata = record.metadata;
3592
+ return isRecord2(metadata) ? keysToCamel(metadata) : {};
3593
+ }
3594
+ function isKnowledgeChunkType(value) {
3595
+ return value === "text" || value === "image" || value === "table" || value === "page";
3596
+ }
3532
3597
  function toIndexedReadChunk(chunk) {
3533
3598
  return {
3534
3599
  source: createSyntheticChunk(chunk),
@@ -3582,204 +3647,105 @@ function getNextChunkPosition(chunks, selected) {
3582
3647
  }
3583
3648
  return chunks[chunks.indexOf(lastSelected) + 1]?.position;
3584
3649
  }
3585
- function applyAssetUrlPolicyToReadChunks(chunks, assetUrlPolicy) {
3586
- if (assetUrlPolicy !== "none") {
3587
- return chunks.map((chunk) => ({
3588
- ...chunk,
3589
- metadata: cloneMetadata(chunk.metadata)
3590
- }));
3591
- }
3592
- return chunks.map((chunk) => ({
3593
- ...chunk,
3594
- assetUrl: void 0,
3595
- metadata: removeAssetUrlsFromMetadata(chunk.metadata)
3596
- }));
3650
+ async function applyStoredAssetUrlsToReadChunks(params) {
3651
+ return Promise.all(
3652
+ params.chunks.map(
3653
+ (chunk) => applyStoredAssetUrlsToReadChunk({
3654
+ ...params,
3655
+ chunk
3656
+ })
3657
+ )
3658
+ );
3597
3659
  }
3598
- async function hardenReadChunkAssetUrls(params) {
3660
+ async function applyStoredAssetUrlsToReadChunk(params) {
3599
3661
  const metadata = cloneMetadata(params.chunk.metadata);
3600
- const assetUrl = await hardenPrimaryAssetUrl(params, metadata);
3601
- const pageAssets = await hardenPageAssetUrls(params, metadata);
3602
- if (pageAssets) {
3603
- metadata.pageAssets = pageAssets;
3604
- }
3605
- return {
3606
- ...params.chunk,
3607
- assetUrl,
3608
- metadata
3609
- };
3610
- }
3611
- async function hardenPrimaryAssetUrl(params, metadata) {
3612
- if (!params.chunk.assetUrl || !params.chunk.filePath) {
3613
- return void 0;
3614
- }
3615
- return writeDurableAssetUrl({
3662
+ const storedAssetUrl = await getStoredObjectUrl({
3616
3663
  storageConfig: params.storageConfig,
3617
3664
  documentId: params.documentId,
3618
3665
  revisionKey: params.revisionKey,
3619
- sourcePath: params.chunk.filePath,
3620
- sourceUrl: params.chunk.assetUrl,
3621
- fallbackContentType: inferContentTypeFromPath(params.chunk.filePath),
3622
- metadata: {
3623
- chunkId: params.chunk.chunkId,
3624
- chunkType: params.chunk.chunkType,
3625
- sourcePath: params.chunk.filePath,
3626
- ...stringifyFlatMetadata(metadata)
3627
- }
3666
+ path: params.chunk.filePath
3628
3667
  });
3629
- }
3630
- async function hardenPageAssetUrls(params, metadata) {
3631
- const pageAssets = toUnknownArray(metadata.pageAssets);
3632
- if (!pageAssets) {
3633
- return void 0;
3634
- }
3635
- const hardenedAssets = [];
3636
- for (const pageAsset of pageAssets) {
3637
- if (!isRecord2(pageAsset)) {
3638
- hardenedAssets.push(pageAsset);
3639
- continue;
3640
- }
3641
- const artifactRef = pageAsset.artifactRef;
3642
- const sourceUrl = pageAsset.assetUrl;
3643
- if (typeof artifactRef !== "string" || typeof sourceUrl !== "string") {
3644
- hardenedAssets.push(removeAssetUrlField(pageAsset));
3645
- continue;
3646
- }
3647
- const durableUrl = await writeDurableAssetUrl({
3648
- storageConfig: params.storageConfig,
3649
- documentId: params.documentId,
3650
- revisionKey: params.revisionKey,
3651
- sourcePath: artifactRef,
3652
- sourceUrl,
3653
- fallbackContentType: typeof pageAsset.contentType === "string" ? pageAsset.contentType : inferContentTypeFromPath(artifactRef),
3654
- metadata: {
3655
- chunkId: params.chunk.chunkId,
3656
- chunkType: params.chunk.chunkType,
3657
- sourcePath: artifactRef
3658
- }
3659
- });
3660
- const rest = removeAssetUrlField(pageAsset);
3661
- hardenedAssets.push(durableUrl ? { ...rest, assetUrl: durableUrl } : rest);
3662
- }
3663
- return hardenedAssets;
3664
- }
3665
- async function writeDurableAssetUrl(params) {
3666
- const existingUrl = await params.storageConfig.storage.getAssetUrl({
3668
+ const pageAssets = await applyStoredPageAssetUrls({
3669
+ storageConfig: params.storageConfig,
3667
3670
  documentId: params.documentId,
3668
3671
  revisionKey: params.revisionKey,
3669
- sourcePath: params.sourcePath
3672
+ metadata
3670
3673
  });
3671
- if (existingUrl) {
3672
- return existingUrl;
3673
- }
3674
- try {
3675
- const fetched = await fetchAsset(params.sourceUrl, params.fallbackContentType);
3676
- const written = await params.storageConfig.storage.writeAsset({
3677
- documentId: params.documentId,
3678
- revisionKey: params.revisionKey,
3679
- sourcePath: params.sourcePath,
3680
- body: fetched.body,
3681
- contentType: fetched.contentType,
3682
- metadata: params.metadata
3683
- });
3684
- return written.url ?? await params.storageConfig.storage.getAssetUrl({
3685
- documentId: params.documentId,
3686
- revisionKey: params.revisionKey,
3687
- sourcePath: params.sourcePath
3688
- }) ?? void 0;
3689
- } catch {
3690
- return void 0;
3691
- }
3692
- }
3693
- async function fetchAsset(sourceUrl, fallbackContentType) {
3694
- const response = await fetch(sourceUrl);
3695
- if (!response.ok) {
3696
- throw new Error(`Unable to fetch parsed asset: ${response.status}`);
3674
+ if (pageAssets) {
3675
+ metadata.pageAssets = pageAssets;
3676
+ delete metadata.page_assets;
3697
3677
  }
3698
3678
  return {
3699
- body: new Uint8Array(await response.arrayBuffer()),
3700
- contentType: response.headers.get("content-type") ?? fallbackContentType
3679
+ ...params.chunk,
3680
+ assetUrl: storedAssetUrl ?? params.chunk.assetUrl,
3681
+ metadata
3701
3682
  };
3702
3683
  }
3703
- function removeAssetUrlsFromMetadata(metadata) {
3704
- const cloned = cloneMetadata(metadata);
3705
- const pageAssets = toUnknownArray(cloned.pageAssets);
3684
+ async function applyStoredPageAssetUrls(params) {
3685
+ const pageAssets = getStoredPageAssets(params.metadata);
3706
3686
  if (!pageAssets) {
3707
- return cloned;
3687
+ return void 0;
3708
3688
  }
3709
- cloned.pageAssets = pageAssets.map((pageAsset) => {
3710
- if (!isRecord2(pageAsset)) {
3689
+ return Promise.all(
3690
+ pageAssets.map(async (pageAsset) => {
3691
+ if (!isRecord2(pageAsset)) {
3692
+ return pageAsset;
3693
+ }
3694
+ const artifactRef = readRecordString(pageAsset, "artifactRef", "artifact_ref");
3695
+ if (typeof artifactRef !== "string") {
3696
+ return pageAsset;
3697
+ }
3698
+ const storedAssetUrl = await getStoredObjectUrl({
3699
+ storageConfig: params.storageConfig,
3700
+ documentId: params.documentId,
3701
+ revisionKey: params.revisionKey,
3702
+ path: artifactRef
3703
+ });
3704
+ if (storedAssetUrl) {
3705
+ return {
3706
+ ...pageAsset,
3707
+ artifactRef,
3708
+ assetUrl: storedAssetUrl
3709
+ };
3710
+ }
3711
3711
  return pageAsset;
3712
- }
3713
- return removeAssetUrlField(pageAsset);
3714
- });
3715
- return cloned;
3716
- }
3717
- function removeAssetUrlField(value) {
3718
- const cloned = { ...value };
3719
- delete cloned.assetUrl;
3720
- return cloned;
3721
- }
3722
- function toSnapshotChunkPageFromReadChunks(params) {
3723
- return {
3724
- version: 1,
3725
- jobId: params.response.jobId ?? params.revisionKey,
3726
- revisionKey: params.revisionKey,
3727
- documentId: params.response.documentId,
3728
- namespace: params.response.namespace,
3729
- sourceFileName: params.response.documentId,
3730
- page: params.response.pagination.page,
3731
- pageSize: params.response.pagination.pageSize,
3732
- total: params.response.pagination.total,
3733
- totalPages: params.response.pagination.totalPages,
3734
- chunks: params.chunks.map(toSnapshotChunkFromReadChunk)
3735
- };
3712
+ })
3713
+ );
3736
3714
  }
3737
- function toSnapshotChunkFromReadChunk(chunk) {
3715
+ function getStoredPageAssets(metadata) {
3716
+ const pageAssets = toUnknownArray(metadata.pageAssets) ?? toUnknownArray(metadata.page_assets) ?? void 0;
3717
+ return pageAssets?.map(normalizeStoredPageAsset);
3718
+ }
3719
+ function normalizeStoredPageAsset(pageAsset) {
3720
+ if (!isRecord2(pageAsset)) {
3721
+ return pageAsset;
3722
+ }
3723
+ const normalizedPageAsset = { ...pageAsset };
3724
+ delete normalizedPageAsset.page_num;
3725
+ delete normalizedPageAsset.artifact_ref;
3726
+ delete normalizedPageAsset.asset_url;
3727
+ delete normalizedPageAsset.content_type;
3728
+ const pageNum = readRecordNumber(pageAsset, "pageNum", "page_num");
3729
+ const artifactRef = readRecordString(pageAsset, "artifactRef", "artifact_ref");
3730
+ const assetUrl = readRecordString(pageAsset, "assetUrl", "asset_url");
3731
+ const contentType = readRecordString(pageAsset, "contentType", "content_type");
3738
3732
  return {
3739
- id: chunk.chunkId,
3740
- chunkId: chunk.chunkId,
3741
- chunkType: chunk.chunkType,
3742
- contentSource: chunk.contentSource,
3743
- content: chunk.content,
3744
- sectionPath: chunk.sectionPath,
3745
- sourceChunkPath: chunk.sourceChunkPath,
3746
- filePath: chunk.filePath,
3747
- sortOrder: chunk.position,
3748
- metadata: cloneMetadata(chunk.metadata),
3749
- assetUrl: chunk.assetUrl
3733
+ ...normalizedPageAsset,
3734
+ ...pageNum === void 0 ? {} : { pageNum },
3735
+ ...artifactRef === void 0 ? {} : { artifactRef },
3736
+ ...assetUrl === void 0 ? {} : { assetUrl },
3737
+ ...contentType === void 0 ? {} : { contentType }
3750
3738
  };
3751
3739
  }
3752
- function createRemoteSnapshotManifest(params) {
3753
- return {
3754
- version: 1,
3755
- kind: "knowhere-parsed-result-snapshot",
3756
- jobId: params.response.jobId ?? params.revisionKey,
3740
+ async function getStoredObjectUrl(params) {
3741
+ if (!params.path) {
3742
+ return void 0;
3743
+ }
3744
+ return await params.storageConfig.storage.getObjectUrl?.({
3745
+ documentId: params.documentId,
3757
3746
  revisionKey: params.revisionKey,
3758
- documentId: params.response.documentId,
3759
- namespace: params.response.namespace,
3760
- sourceFileName: params.response.documentId,
3761
- totalChunks: params.response.pagination.total,
3762
- typeCounts: countSnapshotPagesTypes(params.chunkPages),
3763
- chunkPageSize: params.response.pagination.pageSize,
3764
- chunkPages: Array.from({ length: params.response.pagination.totalPages }, (_, index) => ({
3765
- page: index + 1,
3766
- pageSize: params.response.pagination.pageSize,
3767
- chunkCount: index + 1 === params.response.pagination.totalPages ? params.response.pagination.total - params.response.pagination.pageSize * (params.response.pagination.totalPages - 1) : params.response.pagination.pageSize,
3768
- key: `parsed/chunks/page-${index + 1}.json`
3769
- })),
3770
- assetUrlsByFilePath: {},
3771
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
3772
- };
3773
- }
3774
- function countSnapshotPagesTypes(pages) {
3775
- return pages.flatMap((page) => page.chunks).reduce(
3776
- (counts, chunk) => {
3777
- const chunkType = chunk.chunkType;
3778
- counts[chunkType] += 1;
3779
- return counts;
3780
- },
3781
- { text: 0, image: 0, table: 0, page: 0 }
3782
- );
3747
+ path: params.path
3748
+ }) ?? void 0;
3783
3749
  }
3784
3750
  function countRemoteChunkTypes(chunks) {
3785
3751
  return chunks.reduce(
@@ -3857,22 +3823,10 @@ function isOptionalNonNegativeInteger(value) {
3857
3823
  function cloneMetadata(metadata) {
3858
3824
  return { ...metadata };
3859
3825
  }
3860
- function stringifyFlatMetadata(metadata) {
3861
- const entries = Object.entries(metadata).flatMap(([key, value]) => {
3862
- if (typeof value === "string") {
3863
- return [[key, value]];
3864
- }
3865
- if (typeof value === "number" || typeof value === "boolean") {
3866
- return [[key, String(value)]];
3867
- }
3868
- return [];
3869
- });
3870
- return Object.fromEntries(entries);
3871
- }
3872
3826
  function toUnknownArray(value) {
3873
3827
  return Array.isArray(value) ? value : null;
3874
3828
  }
3875
- function inferContentTypeFromPath(filePath) {
3829
+ function inferContentTypeFromPath2(filePath) {
3876
3830
  const extension = filePath.split(".").at(-1)?.toLowerCase();
3877
3831
  if (extension === "png") return "image/png";
3878
3832
  if (extension === "jpg" || extension === "jpeg") return "image/jpeg";
@@ -3882,6 +3836,9 @@ function inferContentTypeFromPath(filePath) {
3882
3836
  function isRecord2(value) {
3883
3837
  return typeof value === "object" && value !== null && !Array.isArray(value);
3884
3838
  }
3839
+ function isDocumentChunkArray(value) {
3840
+ return Array.isArray(value) && value.every(isRecord2);
3841
+ }
3885
3842
  function indexChunks(result) {
3886
3843
  return result.chunks.map((chunk, index) => {
3887
3844
  const filePath = getChunkFilePath2(chunk);
@@ -4327,51 +4284,59 @@ var Knowhere = class {
4327
4284
  var import_crypto3 = require("crypto");
4328
4285
  var import_fs4 = require("fs");
4329
4286
  var import_path4 = __toESM(require("path"));
4287
+ var syncProgressPath = ".knowhere-sdk/sync-progress.json";
4330
4288
  var DiskParsedDocumentStorage = class {
4331
4289
  rootDirectory;
4332
4290
  constructor(rootDirectory) {
4333
4291
  this.rootDirectory = rootDirectory;
4334
4292
  }
4335
- async readManifest(params) {
4336
- return this.readOptionalJson(
4337
- this.getManifestPath(params.documentId, params.revisionKey)
4338
- );
4339
- }
4340
- async writeManifest(params) {
4341
- await this.writeJson(
4342
- this.getManifestPath(params.documentId, params.revisionKey),
4343
- params.manifest
4344
- );
4345
- }
4346
- async readChunkPage(params) {
4347
- return this.readOptionalJson(
4348
- this.getChunkPagePath(params.documentId, params.revisionKey, params.page)
4349
- );
4350
- }
4351
- async writeChunkPage(params) {
4352
- await this.writeJson(
4353
- this.getChunkPagePath(params.documentId, params.revisionKey, params.page.page),
4354
- params.page
4355
- );
4293
+ async readObject(params) {
4294
+ const objectPath = this.getObjectPath(params);
4295
+ try {
4296
+ const body = await import_fs4.promises.readFile(objectPath);
4297
+ const metadata = await this.readObjectMetadata(objectPath);
4298
+ return {
4299
+ ...params,
4300
+ body,
4301
+ contentType: metadata?.contentType,
4302
+ contentLength: body.byteLength,
4303
+ metadata: metadata?.metadata,
4304
+ url: toFileUrl(objectPath)
4305
+ };
4306
+ } catch (error) {
4307
+ if (isMissingFileError3(error)) {
4308
+ return null;
4309
+ }
4310
+ throw error;
4311
+ }
4356
4312
  }
4357
- async writeAsset(params) {
4358
- const assetPath = this.getAssetPath(params.documentId, params.revisionKey, params.sourcePath);
4359
- await import_fs4.promises.mkdir(import_path4.default.dirname(assetPath), { recursive: true });
4360
- await import_fs4.promises.writeFile(assetPath, params.body);
4361
- await this.writeJson(`${assetPath}.metadata.json`, {
4313
+ async writeObject(params) {
4314
+ const objectPath = this.getObjectPath(params);
4315
+ await import_fs4.promises.mkdir(import_path4.default.dirname(objectPath), { recursive: true });
4316
+ await import_fs4.promises.writeFile(objectPath, params.body);
4317
+ await this.writeObjectMetadata(objectPath, {
4362
4318
  contentType: params.contentType,
4363
- metadata: params.metadata ?? {}
4319
+ metadata: params.metadata
4364
4320
  });
4365
4321
  return {
4366
- sourcePath: params.sourcePath,
4367
- url: toFileUrl(assetPath)
4322
+ documentId: params.documentId,
4323
+ revisionKey: params.revisionKey,
4324
+ path: params.path,
4325
+ url: toFileUrl(objectPath)
4368
4326
  };
4369
4327
  }
4370
- async getAssetUrl(params) {
4371
- const assetPath = this.getAssetPath(params.documentId, params.revisionKey, params.sourcePath);
4328
+ async headObject(params) {
4329
+ const objectPath = this.getObjectPath(params);
4372
4330
  try {
4373
- await import_fs4.promises.access(assetPath);
4374
- return toFileUrl(assetPath);
4331
+ const stat = await import_fs4.promises.stat(objectPath);
4332
+ const metadata = await this.readObjectMetadata(objectPath);
4333
+ return {
4334
+ ...params,
4335
+ contentType: metadata?.contentType,
4336
+ contentLength: stat.size,
4337
+ metadata: metadata?.metadata,
4338
+ url: toFileUrl(objectPath)
4339
+ };
4375
4340
  } catch (error) {
4376
4341
  if (isMissingFileError3(error)) {
4377
4342
  return null;
@@ -4379,53 +4344,54 @@ var DiskParsedDocumentStorage = class {
4379
4344
  throw error;
4380
4345
  }
4381
4346
  }
4382
- async readSyncProgress(params) {
4383
- return this.readOptionalJson(
4384
- this.getProgressPath(params.documentId, params.revisionKey)
4385
- );
4386
- }
4387
- async writeSyncProgress(params) {
4388
- await this.writeJson(this.getProgressPath(params.documentId, params.revisionKey), params);
4347
+ async getObjectUrl(params) {
4348
+ const head = await this.headObject(params);
4349
+ return head?.url ?? null;
4389
4350
  }
4390
- getManifestPath(documentId, revisionKey) {
4391
- return import_path4.default.join(
4392
- this.getRevisionDirectory(documentId, revisionKey),
4393
- "manifest",
4394
- "current.json"
4395
- );
4351
+ async deletePrefix(params) {
4352
+ await import_fs4.promises.rm(this.getRevisionDirectory(params.documentId, params.revisionKey), {
4353
+ recursive: true,
4354
+ force: true
4355
+ });
4396
4356
  }
4397
- getChunkPagePath(documentId, revisionKey, page) {
4398
- return import_path4.default.join(
4399
- this.getRevisionDirectory(documentId, revisionKey),
4400
- "chunks",
4401
- `page-${page}.json`
4402
- );
4357
+ async readSyncProgress(params) {
4358
+ return this.readOptionalJson({
4359
+ ...params,
4360
+ path: syncProgressPath
4361
+ });
4403
4362
  }
4404
- getProgressPath(documentId, revisionKey) {
4405
- return import_path4.default.join(this.getRevisionDirectory(documentId, revisionKey), "sync-progress.json");
4363
+ async writeSyncProgress(params) {
4364
+ await this.writeObject({
4365
+ documentId: params.documentId,
4366
+ revisionKey: params.revisionKey,
4367
+ path: syncProgressPath,
4368
+ body: Buffer.from(JSON.stringify(params, null, 2), "utf8"),
4369
+ contentType: "application/json; charset=utf-8"
4370
+ });
4406
4371
  }
4407
- getAssetPath(documentId, revisionKey, sourcePath) {
4408
- const normalizedSourcePath = normalizeRelativeStoragePath(sourcePath);
4409
- const assetPath = import_path4.default.resolve(
4410
- this.getRevisionDirectory(documentId, revisionKey),
4411
- "assets",
4412
- normalizedSourcePath
4413
- );
4414
- const assetsDirectory = import_path4.default.resolve(
4415
- this.getRevisionDirectory(documentId, revisionKey),
4416
- "assets"
4417
- );
4418
- if (!isPathInsideDirectory2(assetPath, assetsDirectory)) {
4419
- throw new Error(`Parsed asset path resolves outside storage: ${sourcePath}`);
4372
+ getObjectPath(params) {
4373
+ const revisionDirectory = this.getRevisionDirectory(params.documentId, params.revisionKey);
4374
+ const objectPath = import_path4.default.resolve(revisionDirectory, normalizeRelativeStoragePath(params.path));
4375
+ if (!isPathInsideDirectory2(objectPath, revisionDirectory)) {
4376
+ throw new Error(`Parsed document object path resolves outside storage: ${params.path}`);
4420
4377
  }
4421
- return assetPath;
4378
+ return objectPath;
4422
4379
  }
4423
4380
  getRevisionDirectory(documentId, revisionKey) {
4424
4381
  return import_path4.default.join(this.rootDirectory, hashPathPart(documentId), hashPathPart(revisionKey));
4425
4382
  }
4426
- async readOptionalJson(filePath) {
4383
+ async readOptionalJson(params) {
4384
+ const object = await this.readObject(params);
4385
+ if (!object) {
4386
+ return null;
4387
+ }
4388
+ return JSON.parse(Buffer.from(object.body).toString("utf8"));
4389
+ }
4390
+ async readObjectMetadata(filePath) {
4427
4391
  try {
4428
- return JSON.parse(await import_fs4.promises.readFile(filePath, "utf8"));
4392
+ return JSON.parse(
4393
+ await import_fs4.promises.readFile(getMetadataPath(filePath), "utf8")
4394
+ );
4429
4395
  } catch (error) {
4430
4396
  if (isMissingFileError3(error)) {
4431
4397
  return null;
@@ -4433,16 +4399,22 @@ var DiskParsedDocumentStorage = class {
4433
4399
  throw error;
4434
4400
  }
4435
4401
  }
4436
- async writeJson(filePath, value) {
4437
- await import_fs4.promises.mkdir(import_path4.default.dirname(filePath), { recursive: true });
4438
- await import_fs4.promises.writeFile(filePath, JSON.stringify(value, null, 2), {
4402
+ async writeObjectMetadata(filePath, metadata) {
4403
+ await import_fs4.promises.writeFile(getMetadataPath(filePath), JSON.stringify(metadata, null, 2), {
4439
4404
  encoding: "utf8",
4440
4405
  flag: "w"
4441
4406
  });
4442
4407
  }
4443
4408
  };
4409
+ function getMetadataPath(filePath) {
4410
+ return `${filePath}.metadata.json`;
4411
+ }
4444
4412
  function hashPathPart(value) {
4445
- return (0, import_crypto3.createHash)("sha256").update(value).digest("hex").slice(0, 24);
4413
+ const normalized = value.trim();
4414
+ if (normalized.length === 0) {
4415
+ throw new Error("Parsed document storage path part must be a non-empty value.");
4416
+ }
4417
+ return (0, import_crypto3.createHash)("sha256").update(normalized).digest("hex").slice(0, 24);
4446
4418
  }
4447
4419
  function normalizeRelativeStoragePath(value) {
4448
4420
  const normalized = value.replaceAll("\\", "/").replace(/^\.\/+/, "");