@ontos-ai/knowhere-sdk 2.0.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +98 -21
- package/dist/index.d.mts +707 -381
- package/dist/index.d.ts +707 -381
- package/dist/index.js +2009 -60
- package/dist/index.mjs +2005 -59
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -35,6 +35,7 @@ __export(index_exports, {
|
|
|
35
35
|
BadRequestError: () => BadRequestError,
|
|
36
36
|
ChecksumError: () => ChecksumError,
|
|
37
37
|
ConflictError: () => ConflictError,
|
|
38
|
+
DiskParsedDocumentStorage: () => DiskParsedDocumentStorage,
|
|
38
39
|
Documents: () => Documents,
|
|
39
40
|
GatewayTimeoutError: () => GatewayTimeoutError,
|
|
40
41
|
InternalServerError: () => InternalServerError,
|
|
@@ -56,7 +57,9 @@ __export(index_exports, {
|
|
|
56
57
|
TimeoutError: () => TimeoutError,
|
|
57
58
|
VERSION: () => VERSION,
|
|
58
59
|
ValidationError: () => ValidationError,
|
|
59
|
-
default: () => Knowhere
|
|
60
|
+
default: () => Knowhere,
|
|
61
|
+
storeParseResultAssets: () => storeParseResultAssets,
|
|
62
|
+
syncParseResultToParsedDocumentStorage: () => syncParseResultToParsedDocumentStorage
|
|
60
63
|
});
|
|
61
64
|
module.exports = __toCommonJS(index_exports);
|
|
62
65
|
|
|
@@ -369,8 +372,8 @@ function enrichParseResult(parseResult2, scope) {
|
|
|
369
372
|
}
|
|
370
373
|
return parseResult2;
|
|
371
374
|
}
|
|
372
|
-
function sanitizePath(
|
|
373
|
-
let sanitized =
|
|
375
|
+
function sanitizePath(path4) {
|
|
376
|
+
let sanitized = path4.replace(/^\/+/, "");
|
|
374
377
|
sanitized = sanitized.replace(/\.\.(\/|\\)/g, "");
|
|
375
378
|
sanitized = sanitized.replace(/\\/g, "/");
|
|
376
379
|
return sanitized;
|
|
@@ -756,8 +759,8 @@ var BaseResource = class {
|
|
|
756
759
|
constructor(httpClient) {
|
|
757
760
|
this.httpClient = httpClient;
|
|
758
761
|
}
|
|
759
|
-
endpoint(
|
|
760
|
-
return `/v2${
|
|
762
|
+
endpoint(path4) {
|
|
763
|
+
return `/v2${path4.startsWith("/") ? path4 : `/${path4}`}`;
|
|
761
764
|
}
|
|
762
765
|
};
|
|
763
766
|
|
|
@@ -973,17 +976,28 @@ async function saveExpandedParseResult(result, directory) {
|
|
|
973
976
|
if (result.rawZip.length > 0) {
|
|
974
977
|
const didExtractZip = await tryExtractRawZip(result.rawZip, directory);
|
|
975
978
|
if (didExtractZip) {
|
|
979
|
+
await writeExpandedParseResultMetadata(result, directory);
|
|
976
980
|
return directory;
|
|
977
981
|
}
|
|
978
982
|
}
|
|
979
983
|
await import_fs2.promises.mkdir(directory, { recursive: true });
|
|
984
|
+
await writeExpandedParseResultMetadata(result, directory);
|
|
985
|
+
for (const imageChunk of result.imageChunks) {
|
|
986
|
+
await writeBinaryAsset(directory, imageChunk.filePath, imageChunk.data);
|
|
987
|
+
}
|
|
988
|
+
for (const tableChunk of result.tableChunks) {
|
|
989
|
+
await writeTextAsset(directory, tableChunk.filePath, tableChunk.html);
|
|
990
|
+
}
|
|
991
|
+
return directory;
|
|
992
|
+
}
|
|
993
|
+
async function writeExpandedParseResultMetadata(result, directory) {
|
|
980
994
|
await import_fs2.promises.writeFile((0, import_path.join)(directory, "manifest.json"), JSON.stringify(result.manifest, null, 2));
|
|
981
995
|
if (result.docNav) {
|
|
982
996
|
await import_fs2.promises.writeFile((0, import_path.join)(directory, "doc_nav.json"), JSON.stringify(result.docNav, null, 2));
|
|
983
997
|
}
|
|
984
998
|
await import_fs2.promises.writeFile(
|
|
985
999
|
(0, import_path.join)(directory, "chunks.json"),
|
|
986
|
-
JSON.stringify(serializeChunks(result.chunks), null, 2)
|
|
1000
|
+
JSON.stringify(keysToSnake(serializeChunks(result.chunks)), null, 2)
|
|
987
1001
|
);
|
|
988
1002
|
if (result.chunksSlim) {
|
|
989
1003
|
await import_fs2.promises.writeFile(
|
|
@@ -1012,13 +1026,6 @@ async function saveExpandedParseResult(result, directory) {
|
|
|
1012
1026
|
if (result.hierarchyViewHtml) {
|
|
1013
1027
|
await import_fs2.promises.writeFile((0, import_path.join)(directory, "hierarchy_view.html"), result.hierarchyViewHtml);
|
|
1014
1028
|
}
|
|
1015
|
-
for (const imageChunk of result.imageChunks) {
|
|
1016
|
-
await writeBinaryAsset(directory, imageChunk.filePath, imageChunk.data);
|
|
1017
|
-
}
|
|
1018
|
-
for (const tableChunk of result.tableChunks) {
|
|
1019
|
-
await writeTextAsset(directory, tableChunk.filePath, tableChunk.html);
|
|
1020
|
-
}
|
|
1021
|
-
return directory;
|
|
1022
1029
|
}
|
|
1023
1030
|
async function tryExtractRawZip(zipBuffer, directory) {
|
|
1024
1031
|
try {
|
|
@@ -1157,13 +1164,14 @@ function buildTextChunk(chunkData) {
|
|
|
1157
1164
|
};
|
|
1158
1165
|
}
|
|
1159
1166
|
function buildPageChunk(chunkData) {
|
|
1167
|
+
const metadata = chunkData.metadata ?? {};
|
|
1160
1168
|
return {
|
|
1161
1169
|
chunkId: chunkData.chunkId ?? "",
|
|
1162
1170
|
type: "page",
|
|
1163
1171
|
contentSource: chunkData.contentSource ?? "summary",
|
|
1164
1172
|
content: chunkData.content ?? "",
|
|
1165
1173
|
path: chunkData.path ?? "",
|
|
1166
|
-
metadata
|
|
1174
|
+
metadata
|
|
1167
1175
|
};
|
|
1168
1176
|
}
|
|
1169
1177
|
function buildImageChunk(chunkData, filePath, imageBuffer) {
|
|
@@ -1174,6 +1182,7 @@ function buildImageChunk(chunkData, filePath, imageBuffer) {
|
|
|
1174
1182
|
content: chunkData.content ?? "",
|
|
1175
1183
|
path: chunkData.path ?? "",
|
|
1176
1184
|
filePath,
|
|
1185
|
+
assetUrl: chunkData.assetUrl,
|
|
1177
1186
|
data: imageBuffer,
|
|
1178
1187
|
metadata: chunkData.metadata ?? {},
|
|
1179
1188
|
get format() {
|
|
@@ -1192,6 +1201,7 @@ function buildTableChunk(chunkData, filePath, html) {
|
|
|
1192
1201
|
content: chunkData.content ?? "",
|
|
1193
1202
|
path: chunkData.path ?? "",
|
|
1194
1203
|
filePath,
|
|
1204
|
+
assetUrl: chunkData.assetUrl,
|
|
1195
1205
|
html,
|
|
1196
1206
|
metadata: chunkData.metadata ?? {},
|
|
1197
1207
|
async save(directory) {
|
|
@@ -1286,6 +1296,7 @@ function serializeChunks(chunks) {
|
|
|
1286
1296
|
};
|
|
1287
1297
|
if (chunk.type === "image" || chunk.type === "table") {
|
|
1288
1298
|
rawChunk.filePath = chunk.filePath;
|
|
1299
|
+
rawChunk.assetUrl = chunk.assetUrl;
|
|
1289
1300
|
}
|
|
1290
1301
|
return rawChunk;
|
|
1291
1302
|
})
|
|
@@ -1494,6 +1505,14 @@ var Documents = class extends BaseResource {
|
|
|
1494
1505
|
this.createChunkGetRequestConfig(params)
|
|
1495
1506
|
);
|
|
1496
1507
|
}
|
|
1508
|
+
/**
|
|
1509
|
+
* Get a signed normalized source-file URL for compatibility and debugging.
|
|
1510
|
+
*/
|
|
1511
|
+
async getPageCitationSource(documentId) {
|
|
1512
|
+
return this.httpClient.get(
|
|
1513
|
+
this.endpoint(`/documents/${documentId}/files/page-citation-source`)
|
|
1514
|
+
);
|
|
1515
|
+
}
|
|
1497
1516
|
/**
|
|
1498
1517
|
* Archive one canonical document by ID.
|
|
1499
1518
|
*/
|
|
@@ -1566,6 +1585,514 @@ var Documents = class extends BaseResource {
|
|
|
1566
1585
|
// src/knowledge/knowledge.ts
|
|
1567
1586
|
var import_crypto2 = require("crypto");
|
|
1568
1587
|
|
|
1588
|
+
// src/storage/asset-storage.ts
|
|
1589
|
+
var import_jszip2 = __toESM(require("jszip"));
|
|
1590
|
+
var pageCitationAssetsMetadataKey = "pageAssets";
|
|
1591
|
+
var defaultImageContentType = "application/octet-stream";
|
|
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
|
+
async function storeParseResultAssets(result, options) {
|
|
1598
|
+
if (!options) {
|
|
1599
|
+
return {
|
|
1600
|
+
result,
|
|
1601
|
+
assetUrlsByFilePath: {}
|
|
1602
|
+
};
|
|
1603
|
+
}
|
|
1604
|
+
const normalizedKeyPrefix = normalizeStorageKeyPrefix(options.keyPrefix);
|
|
1605
|
+
const assets = dedupeStorageAssets(await collectStorageAssets(result, normalizedKeyPrefix));
|
|
1606
|
+
const assetUrlsByFilePath = {};
|
|
1607
|
+
for (const asset of assets) {
|
|
1608
|
+
const storedUrl = await storeAsset(asset, options.adapter, options.skipExisting ?? true);
|
|
1609
|
+
if (storedUrl) {
|
|
1610
|
+
assetUrlsByFilePath[asset.sourcePath] = storedUrl;
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
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
|
+
return {
|
|
1621
|
+
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)
|
|
1738
|
+
};
|
|
1739
|
+
}
|
|
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
|
+
async function collectStorageAssets(result, keyPrefix) {
|
|
1757
|
+
const resultZip = await loadResultZipForPageCitationAssets(result);
|
|
1758
|
+
return [
|
|
1759
|
+
...result.imageChunks.flatMap((chunk) => collectImageStorageAsset(chunk, keyPrefix)),
|
|
1760
|
+
...result.tableChunks.flatMap((chunk) => collectTableStorageAsset(chunk, keyPrefix)),
|
|
1761
|
+
...resultZip ? await collectPageCitationStorageAssets(result.pageChunks, keyPrefix, resultZip) : []
|
|
1762
|
+
];
|
|
1763
|
+
}
|
|
1764
|
+
function collectImageStorageAsset(chunk, keyPrefix) {
|
|
1765
|
+
const sourcePath = normalizeResultAssetPath(chunk.filePath);
|
|
1766
|
+
if (!sourcePath) return [];
|
|
1767
|
+
return [
|
|
1768
|
+
{
|
|
1769
|
+
sourcePath,
|
|
1770
|
+
storageKey: `${keyPrefix}/${sourcePath}`,
|
|
1771
|
+
body: chunk.data,
|
|
1772
|
+
contentType: getImageContentType(chunk.filePath),
|
|
1773
|
+
metadata: {
|
|
1774
|
+
chunkId: chunk.chunkId,
|
|
1775
|
+
chunkType: chunk.type,
|
|
1776
|
+
sourcePath
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
];
|
|
1780
|
+
}
|
|
1781
|
+
function collectTableStorageAsset(chunk, keyPrefix) {
|
|
1782
|
+
const sourcePath = normalizeResultAssetPath(chunk.filePath);
|
|
1783
|
+
if (!sourcePath) return [];
|
|
1784
|
+
return [
|
|
1785
|
+
{
|
|
1786
|
+
sourcePath,
|
|
1787
|
+
storageKey: `${keyPrefix}/${sourcePath}`,
|
|
1788
|
+
body: Buffer.from(chunk.html, "utf8"),
|
|
1789
|
+
contentType: tableContentType,
|
|
1790
|
+
metadata: {
|
|
1791
|
+
chunkId: chunk.chunkId,
|
|
1792
|
+
chunkType: chunk.type,
|
|
1793
|
+
sourcePath
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
];
|
|
1797
|
+
}
|
|
1798
|
+
async function collectPageCitationStorageAssets(chunks, keyPrefix, resultZip) {
|
|
1799
|
+
const assets = [];
|
|
1800
|
+
for (const chunk of chunks) {
|
|
1801
|
+
const pageAssets = parsePageCitationAssets(chunk.metadata[pageCitationAssetsMetadataKey]);
|
|
1802
|
+
for (const pageAsset of pageAssets) {
|
|
1803
|
+
const sourcePath = normalizeResultAssetPath(pageAsset.artifactRef);
|
|
1804
|
+
if (!sourcePath) continue;
|
|
1805
|
+
const zipEntry = resultZip.file(sourcePath);
|
|
1806
|
+
if (!zipEntry) continue;
|
|
1807
|
+
assets.push({
|
|
1808
|
+
sourcePath,
|
|
1809
|
+
storageKey: `${keyPrefix}/${sourcePath}`,
|
|
1810
|
+
body: await zipEntry.async("uint8array"),
|
|
1811
|
+
contentType: pageAsset.contentType,
|
|
1812
|
+
metadata: getPageCitationAssetMetadata(chunk, pageAsset, sourcePath)
|
|
1813
|
+
});
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
return assets;
|
|
1817
|
+
}
|
|
1818
|
+
function getPageCitationAssetMetadata(chunk, pageAsset, sourcePath) {
|
|
1819
|
+
return {
|
|
1820
|
+
chunkId: chunk.chunkId,
|
|
1821
|
+
chunkType: chunk.type,
|
|
1822
|
+
pageNum: String(pageAsset.pageNum),
|
|
1823
|
+
sourcePath
|
|
1824
|
+
};
|
|
1825
|
+
}
|
|
1826
|
+
async function loadResultZipForPageCitationAssets(result) {
|
|
1827
|
+
if (!hasPageCitationAssetReferences(result) || result.rawZip.length === 0) {
|
|
1828
|
+
return null;
|
|
1829
|
+
}
|
|
1830
|
+
try {
|
|
1831
|
+
return await import_jszip2.default.loadAsync(result.rawZip);
|
|
1832
|
+
} catch (cause) {
|
|
1833
|
+
throw new Error("Unable to read page citation assets from the Knowhere result ZIP.", {
|
|
1834
|
+
cause
|
|
1835
|
+
});
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
function hasPageCitationAssetReferences(result) {
|
|
1839
|
+
return result.pageChunks.some(
|
|
1840
|
+
(chunk) => parsePageCitationAssets(chunk.metadata[pageCitationAssetsMetadataKey]).length > 0
|
|
1841
|
+
);
|
|
1842
|
+
}
|
|
1843
|
+
function dedupeStorageAssets(assets) {
|
|
1844
|
+
const assetsBySourcePath = /* @__PURE__ */ new Map();
|
|
1845
|
+
for (const asset of assets) {
|
|
1846
|
+
if (!assetsBySourcePath.has(asset.sourcePath)) {
|
|
1847
|
+
assetsBySourcePath.set(asset.sourcePath, asset);
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
return [...assetsBySourcePath.values()];
|
|
1851
|
+
}
|
|
1852
|
+
async function storeAsset(asset, adapter, skipExisting) {
|
|
1853
|
+
if (skipExisting && adapter.headObject) {
|
|
1854
|
+
const existing = await adapter.headObject(asset.storageKey);
|
|
1855
|
+
if (existing) {
|
|
1856
|
+
const existingUrl = existing.url ?? await adapter.getObjectUrl?.(asset.storageKey);
|
|
1857
|
+
if (existingUrl) return existingUrl;
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
const writeResult = await adapter.writeObject({
|
|
1861
|
+
key: asset.storageKey,
|
|
1862
|
+
body: asset.body,
|
|
1863
|
+
contentType: asset.contentType,
|
|
1864
|
+
metadata: asset.metadata
|
|
1865
|
+
});
|
|
1866
|
+
return writeResult.url ?? await adapter.getObjectUrl?.(writeResult.key) ?? null;
|
|
1867
|
+
}
|
|
1868
|
+
function rewriteResultAssetUrls(result, assetUrlsByFilePath) {
|
|
1869
|
+
const chunks = result.chunks.map((chunk) => rewriteChunkAssetUrls(chunk, assetUrlsByFilePath));
|
|
1870
|
+
result.chunks.splice(0, result.chunks.length, ...chunks);
|
|
1871
|
+
refreshStaticChunkCollections(result);
|
|
1872
|
+
return result;
|
|
1873
|
+
}
|
|
1874
|
+
function rewriteChunkAssetUrls(chunk, assetUrlsByPath) {
|
|
1875
|
+
if (chunk.type === "image" || chunk.type === "table") {
|
|
1876
|
+
const sourcePath = normalizeResultAssetPath(chunk.filePath);
|
|
1877
|
+
const assetUrl = sourcePath ? assetUrlsByPath[sourcePath] : void 0;
|
|
1878
|
+
if (!assetUrl) return chunk;
|
|
1879
|
+
return {
|
|
1880
|
+
...chunk,
|
|
1881
|
+
assetUrl
|
|
1882
|
+
};
|
|
1883
|
+
}
|
|
1884
|
+
if (chunk.type === "page") {
|
|
1885
|
+
const pageAssets = parsePageCitationAssets(chunk.metadata[pageCitationAssetsMetadataKey]);
|
|
1886
|
+
if (pageAssets.length === 0) return chunk;
|
|
1887
|
+
const rewrittenPageAssets = pageAssets.map((pageAsset) => {
|
|
1888
|
+
const sourcePath = normalizeResultAssetPath(pageAsset.artifactRef);
|
|
1889
|
+
const assetUrl = sourcePath ? assetUrlsByPath[sourcePath] : void 0;
|
|
1890
|
+
return assetUrl ? { ...pageAsset, assetUrl } : pageAsset;
|
|
1891
|
+
});
|
|
1892
|
+
return {
|
|
1893
|
+
...chunk,
|
|
1894
|
+
metadata: {
|
|
1895
|
+
...chunk.metadata,
|
|
1896
|
+
[pageCitationAssetsMetadataKey]: rewrittenPageAssets
|
|
1897
|
+
}
|
|
1898
|
+
};
|
|
1899
|
+
}
|
|
1900
|
+
return chunk;
|
|
1901
|
+
}
|
|
1902
|
+
function parsePageCitationAssets(value) {
|
|
1903
|
+
if (!Array.isArray(value)) return [];
|
|
1904
|
+
return value.flatMap((item) => {
|
|
1905
|
+
if (!isRecord(item)) return [];
|
|
1906
|
+
const pageNum = item.pageNum;
|
|
1907
|
+
const artifactRef = item.artifactRef;
|
|
1908
|
+
const contentType = item.contentType;
|
|
1909
|
+
const source = item.source;
|
|
1910
|
+
if (typeof pageNum !== "number" || !Number.isSafeInteger(pageNum) || pageNum <= 0) return [];
|
|
1911
|
+
if (typeof artifactRef !== "string") return [];
|
|
1912
|
+
if (contentType !== "image/png" && contentType !== "image/jpeg") return [];
|
|
1913
|
+
if (source !== "knowhere-rendered-page-citation-source") return [];
|
|
1914
|
+
return [
|
|
1915
|
+
{
|
|
1916
|
+
pageNum,
|
|
1917
|
+
artifactRef,
|
|
1918
|
+
assetUrl: typeof item.assetUrl === "string" ? item.assetUrl : void 0,
|
|
1919
|
+
contentType,
|
|
1920
|
+
width: typeof item.width === "number" ? item.width : void 0,
|
|
1921
|
+
height: typeof item.height === "number" ? item.height : void 0,
|
|
1922
|
+
source
|
|
1923
|
+
}
|
|
1924
|
+
];
|
|
1925
|
+
});
|
|
1926
|
+
}
|
|
1927
|
+
function normalizeStorageKeyPrefix(value) {
|
|
1928
|
+
const normalized = normalizeStoragePath(value, { allowDotPrefix: false });
|
|
1929
|
+
if (!normalized) {
|
|
1930
|
+
throw new Error("storageAdapter keyPrefix must be a non-empty relative POSIX path.");
|
|
1931
|
+
}
|
|
1932
|
+
return normalized;
|
|
1933
|
+
}
|
|
1934
|
+
function normalizeResultAssetPath(value) {
|
|
1935
|
+
return normalizeStoragePath(value, { allowDotPrefix: true });
|
|
1936
|
+
}
|
|
1937
|
+
function normalizeStoragePath(value, options) {
|
|
1938
|
+
if (!value) return null;
|
|
1939
|
+
const trimmed = value.trim();
|
|
1940
|
+
if (trimmed.length === 0 || trimmed.includes("\0")) return null;
|
|
1941
|
+
if (trimmed.startsWith("/") || /^[A-Za-z]:/.test(trimmed)) return null;
|
|
1942
|
+
const normalized = options.allowDotPrefix ? trimmed.replaceAll("\\", "/").replace(/^\.\/+/, "") : trimmed.replaceAll("\\", "/");
|
|
1943
|
+
if (normalized.length === 0) return null;
|
|
1944
|
+
const parts = normalized.split("/");
|
|
1945
|
+
if (parts.some((part) => part.length === 0 || part === "." || part === "..")) return null;
|
|
1946
|
+
return parts.join("/");
|
|
1947
|
+
}
|
|
1948
|
+
function refreshStaticChunkCollections(result) {
|
|
1949
|
+
replaceStaticChunkCollection(
|
|
1950
|
+
result,
|
|
1951
|
+
"textChunks",
|
|
1952
|
+
result.chunks.filter((chunk) => chunk.type === "text")
|
|
1953
|
+
);
|
|
1954
|
+
replaceStaticChunkCollection(
|
|
1955
|
+
result,
|
|
1956
|
+
"imageChunks",
|
|
1957
|
+
result.chunks.filter((chunk) => chunk.type === "image")
|
|
1958
|
+
);
|
|
1959
|
+
replaceStaticChunkCollection(
|
|
1960
|
+
result,
|
|
1961
|
+
"tableChunks",
|
|
1962
|
+
result.chunks.filter((chunk) => chunk.type === "table")
|
|
1963
|
+
);
|
|
1964
|
+
replaceStaticChunkCollection(
|
|
1965
|
+
result,
|
|
1966
|
+
"pageChunks",
|
|
1967
|
+
result.chunks.filter((chunk) => chunk.type === "page")
|
|
1968
|
+
);
|
|
1969
|
+
}
|
|
1970
|
+
function replaceStaticChunkCollection(result, property, value) {
|
|
1971
|
+
const descriptor = Object.getOwnPropertyDescriptor(result, property);
|
|
1972
|
+
if (!descriptor || descriptor.get || descriptor.writable !== true) return;
|
|
1973
|
+
Object.defineProperty(result, property, {
|
|
1974
|
+
...descriptor,
|
|
1975
|
+
value
|
|
1976
|
+
});
|
|
1977
|
+
}
|
|
1978
|
+
function getImageContentType(filePath) {
|
|
1979
|
+
const extension = filePath.split(".").at(-1)?.toLowerCase();
|
|
1980
|
+
if (extension === "jpg" || extension === "jpeg") return "image/jpeg";
|
|
1981
|
+
if (extension === "png") return "image/png";
|
|
1982
|
+
if (extension === "webp") return "image/webp";
|
|
1983
|
+
if (extension === "gif") return "image/gif";
|
|
1984
|
+
if (extension === "svg") return "image/svg+xml";
|
|
1985
|
+
return defaultImageContentType;
|
|
1986
|
+
}
|
|
1987
|
+
function isRecord(value) {
|
|
1988
|
+
return typeof value === "object" && value !== null;
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
// 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$/;
|
|
1996
|
+
async function syncParseResultToParsedDocumentStorage(params) {
|
|
1997
|
+
const documentId = params.documentId ?? params.result.documentId ?? params.result.jobId;
|
|
1998
|
+
const revisionKey = params.revisionKey ?? params.result.jobId;
|
|
1999
|
+
const adapter = createParsedDocumentObjectStorageAdapter({
|
|
2000
|
+
storage: params.storage,
|
|
2001
|
+
documentId,
|
|
2002
|
+
revisionKey
|
|
2003
|
+
});
|
|
2004
|
+
const stored = await storeParseResultAssets(params.result, {
|
|
2005
|
+
adapter,
|
|
2006
|
+
keyPrefix: parsedStorageKeyPrefix,
|
|
2007
|
+
chunkPageSize: params.chunkPageSize,
|
|
2008
|
+
revisionKey
|
|
2009
|
+
});
|
|
2010
|
+
return {
|
|
2011
|
+
result: stored.result,
|
|
2012
|
+
snapshot: stored.snapshot,
|
|
2013
|
+
documentId,
|
|
2014
|
+
revisionKey
|
|
2015
|
+
};
|
|
2016
|
+
}
|
|
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
|
+
};
|
|
2023
|
+
}
|
|
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 };
|
|
2036
|
+
}
|
|
2037
|
+
if (storagePath === indexStoragePath) {
|
|
2038
|
+
return { key: input.key };
|
|
2039
|
+
}
|
|
2040
|
+
const chunkPageMatch = storagePath.match(chunkPagePathPattern);
|
|
2041
|
+
if (chunkPageMatch) {
|
|
2042
|
+
const page = JSON.parse(
|
|
2043
|
+
Buffer.from(input.body).toString("utf8")
|
|
2044
|
+
);
|
|
2045
|
+
await params.storage.writeChunkPage({
|
|
2046
|
+
documentId: params.documentId,
|
|
2047
|
+
revisionKey: params.revisionKey,
|
|
2048
|
+
page
|
|
2049
|
+
});
|
|
2050
|
+
return { key: input.key };
|
|
2051
|
+
}
|
|
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
|
+
});
|
|
2060
|
+
return {
|
|
2061
|
+
key: input.key,
|
|
2062
|
+
url: stored.url
|
|
2063
|
+
};
|
|
2064
|
+
}
|
|
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({
|
|
2071
|
+
documentId: params.documentId,
|
|
2072
|
+
revisionKey: params.revisionKey,
|
|
2073
|
+
sourcePath: storagePath
|
|
2074
|
+
});
|
|
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;
|
|
2084
|
+
}
|
|
2085
|
+
return params.storage.getAssetUrl({
|
|
2086
|
+
documentId: params.documentId,
|
|
2087
|
+
revisionKey: params.revisionKey,
|
|
2088
|
+
sourcePath: storagePath
|
|
2089
|
+
});
|
|
2090
|
+
}
|
|
2091
|
+
function stripParsedStorageKeyPrefix(key) {
|
|
2092
|
+
const prefix = `${parsedStorageKeyPrefix}/`;
|
|
2093
|
+
return key.startsWith(prefix) ? key.slice(prefix.length) : key;
|
|
2094
|
+
}
|
|
2095
|
+
|
|
1569
2096
|
// src/knowledge/local-store.ts
|
|
1570
2097
|
var import_crypto = require("crypto");
|
|
1571
2098
|
var import_os = __toESM(require("os"));
|
|
@@ -1791,27 +2318,62 @@ function isMissingFileError2(error) {
|
|
|
1791
2318
|
// src/knowledge/knowledge.ts
|
|
1792
2319
|
var DEFAULT_READ_LIMIT = 12;
|
|
1793
2320
|
var MAX_READ_LIMIT = 40;
|
|
2321
|
+
var DEFAULT_PAGE_SIZE = 20;
|
|
2322
|
+
var MAX_PAGE_SIZE = 200;
|
|
1794
2323
|
var DEFAULT_GREP_LIMIT = 20;
|
|
1795
2324
|
var MAX_GREP_LIMIT = 50;
|
|
1796
2325
|
var DEFAULT_CONTEXT_CHARS = 80;
|
|
2326
|
+
var DEFAULT_REMOTE_SCAN_PAGE_SIZE = 100;
|
|
2327
|
+
var DEFAULT_MAX_SYNC_PAGES = 10;
|
|
2328
|
+
var DEFAULT_MAX_SYNC_ASSETS = 20;
|
|
2329
|
+
var DEFAULT_SYNC_DEADLINE_MS = 8e3;
|
|
2330
|
+
var DEFAULT_GREP_MAX_PAGES = 50;
|
|
2331
|
+
var DEFAULT_GREP_DEADLINE_MS = 8e3;
|
|
2332
|
+
var DEFAULT_OUTLINE_MAX_PAGES = 50;
|
|
2333
|
+
var DEFAULT_OUTLINE_DEADLINE_MS = 8e3;
|
|
1797
2334
|
var SAFE_LOCAL_DOCUMENT_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
1798
2335
|
var REMOTE_DOCUMENT_ID_PATTERN = /^doc[_-]/;
|
|
1799
2336
|
var Knowledge = class _Knowledge {
|
|
1800
2337
|
client;
|
|
1801
2338
|
store;
|
|
2339
|
+
cacheDirectory;
|
|
2340
|
+
parsedStorageConfig;
|
|
1802
2341
|
constructor(client, options) {
|
|
1803
2342
|
this.client = client;
|
|
2343
|
+
this.cacheDirectory = options?.cacheDirectory;
|
|
2344
|
+
this.parsedStorageConfig = options?.parsedStorage;
|
|
1804
2345
|
this.store = new LocalKnowledgeStore(options?.cacheDirectory);
|
|
1805
2346
|
}
|
|
1806
2347
|
withCacheDirectory(cacheDirectory) {
|
|
1807
|
-
return new _Knowledge(this.client, {
|
|
2348
|
+
return new _Knowledge(this.client, {
|
|
2349
|
+
cacheDirectory,
|
|
2350
|
+
parsedStorage: this.parsedStorageConfig
|
|
2351
|
+
});
|
|
1808
2352
|
}
|
|
1809
|
-
|
|
1810
|
-
|
|
2353
|
+
withParsedStorage(parsedStorage) {
|
|
2354
|
+
return new _Knowledge(this.client, {
|
|
2355
|
+
cacheDirectory: this.cacheDirectory,
|
|
2356
|
+
parsedStorage
|
|
2357
|
+
});
|
|
2358
|
+
}
|
|
2359
|
+
async parseToLocalCache(params) {
|
|
2360
|
+
const loadedResult = params.storageAdapter ? await this.parseWithoutClientStorageAdapter(params) : await this.client.parse(params);
|
|
2361
|
+
const storedAssets = await storeParseResultAssets(loadedResult, params.storageAdapter);
|
|
2362
|
+
const syncedStorage = await this.syncParseResultToConfiguredStorage(storedAssets.result);
|
|
2363
|
+
const result = syncedStorage.result;
|
|
1811
2364
|
const document = await this.store.saveResult(result, {
|
|
1812
2365
|
localDocumentId: params.localDocumentId
|
|
1813
2366
|
});
|
|
1814
|
-
return {
|
|
2367
|
+
return {
|
|
2368
|
+
document,
|
|
2369
|
+
result,
|
|
2370
|
+
assetUrlsByFilePath: storedAssets.assetUrlsByFilePath,
|
|
2371
|
+
parsedSnapshot: storedAssets.snapshot
|
|
2372
|
+
};
|
|
2373
|
+
}
|
|
2374
|
+
/** @deprecated Use parseToLocalCache for local cache imports or the top-level client.parse for server-safe parsing. */
|
|
2375
|
+
async parse(params) {
|
|
2376
|
+
return this.parseToLocalCache(params);
|
|
1815
2377
|
}
|
|
1816
2378
|
async startParse(params) {
|
|
1817
2379
|
const job = await this.client.startParse(params);
|
|
@@ -1842,14 +2404,100 @@ var Knowledge = class _Knowledge {
|
|
|
1842
2404
|
results
|
|
1843
2405
|
};
|
|
1844
2406
|
}
|
|
1845
|
-
async
|
|
1846
|
-
const
|
|
2407
|
+
async loadJobResult(params) {
|
|
2408
|
+
const loadedResult = await this.client.jobs.load(params.jobId, {
|
|
1847
2409
|
verifyChecksum: params.verifyChecksum
|
|
1848
2410
|
});
|
|
2411
|
+
const storedAssets = await storeParseResultAssets(loadedResult, params.storageAdapter);
|
|
2412
|
+
const syncedStorage = await this.syncParseResultToConfiguredStorage(storedAssets.result);
|
|
2413
|
+
const result = syncedStorage.result;
|
|
2414
|
+
return {
|
|
2415
|
+
result,
|
|
2416
|
+
assetUrlsByFilePath: storedAssets.assetUrlsByFilePath,
|
|
2417
|
+
parsedSnapshot: syncedStorage.snapshot ?? storedAssets.snapshot
|
|
2418
|
+
};
|
|
2419
|
+
}
|
|
2420
|
+
async importJobResult(params) {
|
|
2421
|
+
const stored = await this.loadJobResult(params);
|
|
2422
|
+
const result = stored.result;
|
|
1849
2423
|
const document = await this.store.saveResult(result, {
|
|
1850
2424
|
localDocumentId: params.localDocumentId
|
|
1851
2425
|
});
|
|
1852
|
-
return {
|
|
2426
|
+
return {
|
|
2427
|
+
document,
|
|
2428
|
+
result,
|
|
2429
|
+
assetUrlsByFilePath: stored.assetUrlsByFilePath,
|
|
2430
|
+
parsedSnapshot: stored.parsedSnapshot
|
|
2431
|
+
};
|
|
2432
|
+
}
|
|
2433
|
+
/** @deprecated Use importJobResult for local cache imports or loadJobResult for server-safe loads. */
|
|
2434
|
+
async cacheJobResult(params) {
|
|
2435
|
+
return this.importJobResult(params);
|
|
2436
|
+
}
|
|
2437
|
+
async syncParsedDocument(params) {
|
|
2438
|
+
const normalized = normalizeDocumentReference(params);
|
|
2439
|
+
const parsedStorageConfig = this.requireParsedStorageConfig();
|
|
2440
|
+
if (normalized.documentId) {
|
|
2441
|
+
return this.syncRemoteDocumentToParsedStorage({
|
|
2442
|
+
documentId: normalized.documentId,
|
|
2443
|
+
revisionKey: params.revisionKey,
|
|
2444
|
+
parsedStorageConfig
|
|
2445
|
+
});
|
|
2446
|
+
}
|
|
2447
|
+
if (normalized.jobId) {
|
|
2448
|
+
const loadedResult = await this.client.jobs.load(normalized.jobId);
|
|
2449
|
+
const synced2 = await syncParseResultToParsedDocumentStorage({
|
|
2450
|
+
result: loadedResult,
|
|
2451
|
+
storage: parsedStorageConfig.storage,
|
|
2452
|
+
documentId: loadedResult.documentId ?? normalized.localDocumentId ?? normalized.jobId,
|
|
2453
|
+
revisionKey: params.revisionKey ?? normalized.jobId,
|
|
2454
|
+
chunkPageSize: parsedStorageConfig.limits?.chunkPageSize
|
|
2455
|
+
});
|
|
2456
|
+
return {
|
|
2457
|
+
documentId: synced2.documentId,
|
|
2458
|
+
revisionKey: synced2.revisionKey,
|
|
2459
|
+
completed: true,
|
|
2460
|
+
manifest: synced2.snapshot?.manifest
|
|
2461
|
+
};
|
|
2462
|
+
}
|
|
2463
|
+
if (!normalized.localDocumentId) {
|
|
2464
|
+
throw new ValidationError("localDocumentId, documentId, or jobId is required");
|
|
2465
|
+
}
|
|
2466
|
+
const { result } = await this.store.loadResult(normalized.localDocumentId);
|
|
2467
|
+
const synced = await syncParseResultToParsedDocumentStorage({
|
|
2468
|
+
result,
|
|
2469
|
+
storage: parsedStorageConfig.storage,
|
|
2470
|
+
documentId: result.documentId ?? normalized.localDocumentId,
|
|
2471
|
+
revisionKey: params.revisionKey ?? result.jobId,
|
|
2472
|
+
chunkPageSize: parsedStorageConfig.limits?.chunkPageSize
|
|
2473
|
+
});
|
|
2474
|
+
return {
|
|
2475
|
+
documentId: synced.documentId,
|
|
2476
|
+
revisionKey: synced.revisionKey,
|
|
2477
|
+
completed: true,
|
|
2478
|
+
manifest: synced.snapshot?.manifest
|
|
2479
|
+
};
|
|
2480
|
+
}
|
|
2481
|
+
async syncParseResultToConfiguredStorage(result) {
|
|
2482
|
+
const parsedStorageConfig = this.parsedStorageConfig;
|
|
2483
|
+
if (!parsedStorageConfig) {
|
|
2484
|
+
return { result };
|
|
2485
|
+
}
|
|
2486
|
+
const synced = await syncParseResultToParsedDocumentStorage({
|
|
2487
|
+
result,
|
|
2488
|
+
storage: parsedStorageConfig.storage,
|
|
2489
|
+
chunkPageSize: parsedStorageConfig.limits?.chunkPageSize
|
|
2490
|
+
});
|
|
2491
|
+
return {
|
|
2492
|
+
result: synced.result,
|
|
2493
|
+
snapshot: synced.snapshot
|
|
2494
|
+
};
|
|
2495
|
+
}
|
|
2496
|
+
async parseWithoutClientStorageAdapter(params) {
|
|
2497
|
+
const parseParams = { ...params };
|
|
2498
|
+
delete parseParams.localDocumentId;
|
|
2499
|
+
delete parseParams.storageAdapter;
|
|
2500
|
+
return this.client.parse(parseParams);
|
|
1853
2501
|
}
|
|
1854
2502
|
async cacheDocument(params) {
|
|
1855
2503
|
if (!params.documentId) {
|
|
@@ -1859,7 +2507,7 @@ var Knowledge = class _Knowledge {
|
|
|
1859
2507
|
params.documentId
|
|
1860
2508
|
);
|
|
1861
2509
|
const jobId = await this.getPublishedDocumentJobId(params.documentId);
|
|
1862
|
-
return this.
|
|
2510
|
+
return this.importJobResult({
|
|
1863
2511
|
jobId,
|
|
1864
2512
|
localDocumentId: params.localDocumentId ?? existing?.localDocumentId ?? createLocalDocumentIdForRemote(params.documentId)
|
|
1865
2513
|
});
|
|
@@ -1896,7 +2544,7 @@ var Knowledge = class _Knowledge {
|
|
|
1896
2544
|
};
|
|
1897
2545
|
}
|
|
1898
2546
|
try {
|
|
1899
|
-
const cached = await this.
|
|
2547
|
+
const cached = await this.importJobResult({
|
|
1900
2548
|
jobId,
|
|
1901
2549
|
localDocumentId: trackedJob.localDocumentId
|
|
1902
2550
|
});
|
|
@@ -1921,6 +2569,13 @@ var Knowledge = class _Knowledge {
|
|
|
1921
2569
|
return this.store.listDocuments();
|
|
1922
2570
|
}
|
|
1923
2571
|
async getDocumentOutline(reference) {
|
|
2572
|
+
const normalized = normalizeDocumentReference(reference);
|
|
2573
|
+
if (normalized.documentId) {
|
|
2574
|
+
return this.getRemoteDocumentOutline(normalized.documentId, normalized.revisionKey);
|
|
2575
|
+
}
|
|
2576
|
+
if (normalized.localDocumentId && looksLikeRemoteDocumentId(normalized.localDocumentId) && !await this.store.getDocument(normalized.localDocumentId)) {
|
|
2577
|
+
return this.getRemoteDocumentOutline(normalized.localDocumentId, normalized.revisionKey);
|
|
2578
|
+
}
|
|
1924
2579
|
const { document, result } = await this.loadReadableResult(reference);
|
|
1925
2580
|
const chunks = indexChunks(result);
|
|
1926
2581
|
const sections = buildFlatSections(result, chunks);
|
|
@@ -1936,6 +2591,14 @@ var Knowledge = class _Knowledge {
|
|
|
1936
2591
|
};
|
|
1937
2592
|
}
|
|
1938
2593
|
async readChunks(params) {
|
|
2594
|
+
validateReadParams(params);
|
|
2595
|
+
const normalized = normalizeDocumentReference(params);
|
|
2596
|
+
if (normalized.documentId) {
|
|
2597
|
+
return this.readRemoteDocumentChunks(normalized.documentId, params);
|
|
2598
|
+
}
|
|
2599
|
+
if (normalized.localDocumentId && looksLikeRemoteDocumentId(normalized.localDocumentId) && !await this.store.getDocument(normalized.localDocumentId)) {
|
|
2600
|
+
return this.readRemoteDocumentChunks(normalized.localDocumentId, params);
|
|
2601
|
+
}
|
|
1939
2602
|
const { document, result } = await this.loadReadableResult(params);
|
|
1940
2603
|
const limit = clampLimit(params.limit, DEFAULT_READ_LIMIT, MAX_READ_LIMIT);
|
|
1941
2604
|
const chunks = indexChunks(result).filter((chunk) => matchesReadScope(chunk, params));
|
|
@@ -1952,6 +2615,13 @@ var Knowledge = class _Knowledge {
|
|
|
1952
2615
|
if (!params.pattern) {
|
|
1953
2616
|
throw new ValidationError("pattern is required");
|
|
1954
2617
|
}
|
|
2618
|
+
const normalized = normalizeDocumentReference(params);
|
|
2619
|
+
if (normalized.documentId) {
|
|
2620
|
+
return this.grepRemoteDocumentChunks(normalized.documentId, params);
|
|
2621
|
+
}
|
|
2622
|
+
if (normalized.localDocumentId && looksLikeRemoteDocumentId(normalized.localDocumentId) && !await this.store.getDocument(normalized.localDocumentId)) {
|
|
2623
|
+
return this.grepRemoteDocumentChunks(normalized.localDocumentId, params);
|
|
2624
|
+
}
|
|
1955
2625
|
const { document, result } = await this.loadReadableResult(params);
|
|
1956
2626
|
const maxResults = clampLimit(params.maxResults, DEFAULT_GREP_LIMIT, MAX_GREP_LIMIT);
|
|
1957
2627
|
const contextChars = params.contextChars ?? DEFAULT_CONTEXT_CHARS;
|
|
@@ -2031,7 +2701,7 @@ var Knowledge = class _Knowledge {
|
|
|
2031
2701
|
});
|
|
2032
2702
|
}
|
|
2033
2703
|
if (normalized.jobId) {
|
|
2034
|
-
return this.
|
|
2704
|
+
return this.importJobResult({
|
|
2035
2705
|
jobId: normalized.jobId,
|
|
2036
2706
|
localDocumentId: normalized.localDocumentId
|
|
2037
2707
|
});
|
|
@@ -2051,31 +2721,677 @@ var Knowledge = class _Knowledge {
|
|
|
2051
2721
|
}
|
|
2052
2722
|
throw new Error(`Local Knowhere document not found: ${normalized.localDocumentId}`);
|
|
2053
2723
|
}
|
|
2054
|
-
async
|
|
2055
|
-
const
|
|
2056
|
-
|
|
2724
|
+
async readRemoteDocumentChunks(documentId, params) {
|
|
2725
|
+
const explicitRevisionKey = params.revisionKey ?? params.jobId;
|
|
2726
|
+
if (explicitRevisionKey) {
|
|
2727
|
+
const stored2 = await this.tryReadChunksFromParsedStorage({
|
|
2728
|
+
documentId,
|
|
2729
|
+
revisionKey: explicitRevisionKey,
|
|
2730
|
+
params
|
|
2731
|
+
});
|
|
2732
|
+
if (stored2) {
|
|
2733
|
+
return stored2;
|
|
2734
|
+
}
|
|
2735
|
+
}
|
|
2736
|
+
if (hasScanReadFilters(params)) {
|
|
2737
|
+
return this.scanRemoteDocumentChunks(documentId, params);
|
|
2738
|
+
}
|
|
2739
|
+
const pageParams = getReadPageParams(params);
|
|
2740
|
+
const remotePage = await this.client.documents.listChunks(documentId, {
|
|
2741
|
+
page: pageParams.page,
|
|
2742
|
+
pageSize: pageParams.pageSize,
|
|
2743
|
+
chunkType: params.chunkType,
|
|
2744
|
+
includeAssetUrls: shouldRequestRemoteAssetUrls(
|
|
2745
|
+
params.assetUrlPolicy,
|
|
2746
|
+
this.parsedStorageConfig
|
|
2747
|
+
)
|
|
2748
|
+
});
|
|
2749
|
+
const revisionKey = getRemoteRevisionKey(remotePage);
|
|
2750
|
+
const stored = await this.tryReadChunksFromParsedStorage({
|
|
2751
|
+
documentId,
|
|
2752
|
+
revisionKey,
|
|
2753
|
+
params
|
|
2754
|
+
});
|
|
2755
|
+
if (stored) {
|
|
2756
|
+
return stored;
|
|
2757
|
+
}
|
|
2758
|
+
const chunks = await this.toRemoteReadChunks({
|
|
2759
|
+
documentId,
|
|
2760
|
+
revisionKey,
|
|
2761
|
+
chunks: remotePage.chunks,
|
|
2762
|
+
assetUrlPolicy: params.assetUrlPolicy
|
|
2763
|
+
});
|
|
2764
|
+
this.scheduleParsedStorageSync(documentId, revisionKey);
|
|
2765
|
+
return {
|
|
2766
|
+
document: createRemoteKnowledgeDocument({
|
|
2767
|
+
documentId,
|
|
2768
|
+
response: remotePage,
|
|
2769
|
+
revisionKey
|
|
2770
|
+
}),
|
|
2771
|
+
chunks,
|
|
2772
|
+
page: remotePage.pagination.page,
|
|
2773
|
+
pageSize: remotePage.pagination.pageSize,
|
|
2774
|
+
totalChunks: remotePage.pagination.total,
|
|
2775
|
+
totalPages: remotePage.pagination.totalPages
|
|
2776
|
+
};
|
|
2057
2777
|
}
|
|
2058
|
-
async
|
|
2059
|
-
const
|
|
2778
|
+
async scanRemoteDocumentChunks(documentId, params) {
|
|
2779
|
+
const explicitRevisionKey = params.revisionKey ?? params.jobId;
|
|
2780
|
+
if (explicitRevisionKey) {
|
|
2781
|
+
const stored2 = await this.tryReadChunksFromParsedStorage({
|
|
2782
|
+
documentId,
|
|
2783
|
+
revisionKey: explicitRevisionKey,
|
|
2784
|
+
params
|
|
2785
|
+
});
|
|
2786
|
+
if (stored2) {
|
|
2787
|
+
return stored2;
|
|
2788
|
+
}
|
|
2789
|
+
}
|
|
2790
|
+
const limit = clampLimit(params.limit, DEFAULT_READ_LIMIT, MAX_READ_LIMIT);
|
|
2791
|
+
const limits = getParsedStorageLimits(this.parsedStorageConfig?.limits);
|
|
2792
|
+
const firstPage = await this.client.documents.listChunks(documentId, {
|
|
2060
2793
|
page: 1,
|
|
2061
|
-
pageSize:
|
|
2794
|
+
pageSize: limits.remotePageSize,
|
|
2795
|
+
chunkType: params.chunkType,
|
|
2796
|
+
includeAssetUrls: shouldRequestRemoteAssetUrls(
|
|
2797
|
+
params.assetUrlPolicy,
|
|
2798
|
+
this.parsedStorageConfig
|
|
2799
|
+
)
|
|
2062
2800
|
});
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2801
|
+
const revisionKey = getRemoteRevisionKey(firstPage);
|
|
2802
|
+
const stored = await this.tryReadChunksFromParsedStorage({
|
|
2803
|
+
documentId,
|
|
2804
|
+
revisionKey,
|
|
2805
|
+
params
|
|
2806
|
+
});
|
|
2807
|
+
if (stored) {
|
|
2808
|
+
return stored;
|
|
2067
2809
|
}
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2810
|
+
const selected = [];
|
|
2811
|
+
let scannedPages = 0;
|
|
2812
|
+
let page = 1;
|
|
2813
|
+
let response = firstPage;
|
|
2814
|
+
const startedAt = Date.now();
|
|
2815
|
+
while (true) {
|
|
2816
|
+
scannedPages += 1;
|
|
2817
|
+
selected.push(...response.chunks.filter((chunk) => matchesRemoteReadScope(chunk, params)));
|
|
2818
|
+
if (selected.length >= limit || response.pagination.page >= response.pagination.totalPages || scannedPages >= limits.outlineMaxPages || Date.now() - startedAt >= limits.outlineDeadlineMs) {
|
|
2819
|
+
break;
|
|
2820
|
+
}
|
|
2821
|
+
page += 1;
|
|
2822
|
+
response = await this.client.documents.listChunks(documentId, {
|
|
2823
|
+
page,
|
|
2824
|
+
pageSize: limits.remotePageSize,
|
|
2825
|
+
chunkType: params.chunkType,
|
|
2826
|
+
includeAssetUrls: shouldRequestRemoteAssetUrls(
|
|
2827
|
+
params.assetUrlPolicy,
|
|
2828
|
+
this.parsedStorageConfig
|
|
2829
|
+
)
|
|
2830
|
+
});
|
|
2831
|
+
}
|
|
2832
|
+
const chunks = await this.toRemoteReadChunks({
|
|
2833
|
+
documentId,
|
|
2834
|
+
revisionKey,
|
|
2835
|
+
chunks: selected.slice(0, limit),
|
|
2836
|
+
assetUrlPolicy: params.assetUrlPolicy
|
|
2837
|
+
});
|
|
2838
|
+
this.scheduleParsedStorageSync(documentId, revisionKey);
|
|
2839
|
+
return {
|
|
2840
|
+
document: createRemoteKnowledgeDocument({
|
|
2841
|
+
documentId,
|
|
2842
|
+
response: firstPage,
|
|
2843
|
+
revisionKey
|
|
2844
|
+
}),
|
|
2845
|
+
chunks,
|
|
2846
|
+
nextChunk: selected.length > limit ? toChunkPosition(selected[limit]) : void 0,
|
|
2847
|
+
totalChunks: firstPage.pagination.total,
|
|
2848
|
+
totalPages: firstPage.pagination.totalPages
|
|
2849
|
+
};
|
|
2074
2850
|
}
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2851
|
+
async grepRemoteDocumentChunks(documentId, params) {
|
|
2852
|
+
const explicitRevisionKey = params.revisionKey ?? params.jobId;
|
|
2853
|
+
if (explicitRevisionKey && !params.continuationCursor) {
|
|
2854
|
+
const stored2 = await this.tryGrepChunksFromParsedStorage({
|
|
2855
|
+
documentId,
|
|
2856
|
+
revisionKey: explicitRevisionKey,
|
|
2857
|
+
params
|
|
2858
|
+
});
|
|
2859
|
+
if (stored2) {
|
|
2860
|
+
return stored2;
|
|
2861
|
+
}
|
|
2862
|
+
}
|
|
2863
|
+
const maxResults = clampLimit(params.maxResults, DEFAULT_GREP_LIMIT, MAX_GREP_LIMIT);
|
|
2864
|
+
const contextChars = params.contextChars ?? DEFAULT_CONTEXT_CHARS;
|
|
2865
|
+
const matcher = createMatcher(params);
|
|
2866
|
+
const limits = getParsedStorageLimits(this.parsedStorageConfig?.limits);
|
|
2867
|
+
const cursor = parseContinuationCursor(params.continuationCursor);
|
|
2868
|
+
const startPage = cursor?.documentId === documentId ? cursor.nextPage : 1;
|
|
2869
|
+
const firstPage = await this.client.documents.listChunks(documentId, {
|
|
2870
|
+
page: startPage,
|
|
2871
|
+
pageSize: limits.remotePageSize,
|
|
2872
|
+
chunkType: params.chunkType,
|
|
2873
|
+
includeAssetUrls: false
|
|
2874
|
+
});
|
|
2875
|
+
const revisionKey = getRemoteRevisionKey(firstPage);
|
|
2876
|
+
const stored = startPage === 1 ? await this.tryGrepChunksFromParsedStorage({
|
|
2877
|
+
documentId,
|
|
2878
|
+
revisionKey,
|
|
2879
|
+
params
|
|
2880
|
+
}) : null;
|
|
2881
|
+
if (stored) {
|
|
2882
|
+
return stored;
|
|
2883
|
+
}
|
|
2884
|
+
const matches = [];
|
|
2885
|
+
let scannedChunks = 0;
|
|
2886
|
+
let scannedPages = 0;
|
|
2887
|
+
let response = firstPage;
|
|
2888
|
+
let page = startPage;
|
|
2889
|
+
const startedAt = Date.now();
|
|
2890
|
+
while (true) {
|
|
2891
|
+
scannedPages += 1;
|
|
2892
|
+
for (const [chunkIndex, chunk] of response.chunks.entries()) {
|
|
2893
|
+
if (response.pagination.page === startPage && cursor?.nextChunkIndex !== void 0 && chunkIndex < cursor.nextChunkIndex) {
|
|
2894
|
+
continue;
|
|
2895
|
+
}
|
|
2896
|
+
if (!matchesGrepScope(toIndexedRemoteChunk(chunk), params)) {
|
|
2897
|
+
continue;
|
|
2898
|
+
}
|
|
2899
|
+
scannedChunks += 1;
|
|
2900
|
+
const chunkMatches = matcher(chunk.content ?? "");
|
|
2901
|
+
for (const [matchIndex, match] of chunkMatches.entries()) {
|
|
2902
|
+
if (response.pagination.page === startPage && cursor?.nextChunkIndex === chunkIndex && cursor.nextMatchIndex !== void 0 && matchIndex < cursor.nextMatchIndex) {
|
|
2903
|
+
continue;
|
|
2904
|
+
}
|
|
2905
|
+
matches.push({
|
|
2906
|
+
position: toChunkPosition(chunk),
|
|
2907
|
+
chunkId: chunk.chunkId,
|
|
2908
|
+
chunkType: chunk.chunkType,
|
|
2909
|
+
sectionPath: chunk.sectionPath ?? "",
|
|
2910
|
+
sourceChunkPath: chunk.sourceChunkPath ?? chunk.sectionPath ?? "",
|
|
2911
|
+
filePath: chunk.filePath ?? void 0,
|
|
2912
|
+
startOffset: match.startOffset,
|
|
2913
|
+
endOffset: match.endOffset,
|
|
2914
|
+
snippet: buildSnippet(
|
|
2915
|
+
chunk.content ?? "",
|
|
2916
|
+
match.startOffset,
|
|
2917
|
+
match.endOffset,
|
|
2918
|
+
contextChars
|
|
2919
|
+
)
|
|
2920
|
+
});
|
|
2921
|
+
if (matches.length >= maxResults) {
|
|
2922
|
+
const continuationCursor = createGrepContinuationCursor({
|
|
2923
|
+
documentId,
|
|
2924
|
+
revisionKey,
|
|
2925
|
+
response,
|
|
2926
|
+
chunkIndex,
|
|
2927
|
+
matchIndex,
|
|
2928
|
+
chunkMatchCount: chunkMatches.length
|
|
2929
|
+
});
|
|
2930
|
+
this.scheduleParsedStorageSync(documentId, revisionKey);
|
|
2931
|
+
return {
|
|
2932
|
+
document: createRemoteKnowledgeDocument({
|
|
2933
|
+
documentId,
|
|
2934
|
+
response: firstPage,
|
|
2935
|
+
revisionKey
|
|
2936
|
+
}),
|
|
2937
|
+
matches,
|
|
2938
|
+
scannedChunks,
|
|
2939
|
+
truncated: continuationCursor !== void 0,
|
|
2940
|
+
continuationCursor
|
|
2941
|
+
};
|
|
2942
|
+
}
|
|
2943
|
+
}
|
|
2944
|
+
}
|
|
2945
|
+
const shouldStop = response.pagination.page >= response.pagination.totalPages || scannedPages >= limits.grepMaxPages || Date.now() - startedAt >= limits.grepDeadlineMs;
|
|
2946
|
+
if (shouldStop) {
|
|
2947
|
+
const truncated = response.pagination.page < response.pagination.totalPages;
|
|
2948
|
+
this.scheduleParsedStorageSync(documentId, revisionKey);
|
|
2949
|
+
return {
|
|
2950
|
+
document: createRemoteKnowledgeDocument({
|
|
2951
|
+
documentId,
|
|
2952
|
+
response: firstPage,
|
|
2953
|
+
revisionKey
|
|
2954
|
+
}),
|
|
2955
|
+
matches,
|
|
2956
|
+
scannedChunks,
|
|
2957
|
+
truncated,
|
|
2958
|
+
continuationCursor: truncated ? createContinuationCursor({
|
|
2959
|
+
documentId,
|
|
2960
|
+
revisionKey,
|
|
2961
|
+
nextPage: response.pagination.page + 1
|
|
2962
|
+
}) : void 0
|
|
2963
|
+
};
|
|
2964
|
+
}
|
|
2965
|
+
page += 1;
|
|
2966
|
+
response = await this.client.documents.listChunks(documentId, {
|
|
2967
|
+
page,
|
|
2968
|
+
pageSize: limits.remotePageSize,
|
|
2969
|
+
chunkType: params.chunkType,
|
|
2970
|
+
includeAssetUrls: false
|
|
2971
|
+
});
|
|
2972
|
+
}
|
|
2973
|
+
}
|
|
2974
|
+
async getRemoteDocumentOutline(documentId, revisionKeyOverride) {
|
|
2975
|
+
if (revisionKeyOverride) {
|
|
2976
|
+
const stored2 = await this.tryReadOutlineFromParsedStorage(documentId, revisionKeyOverride);
|
|
2977
|
+
if (stored2) {
|
|
2978
|
+
return stored2;
|
|
2979
|
+
}
|
|
2980
|
+
}
|
|
2981
|
+
const limits = getParsedStorageLimits(this.parsedStorageConfig?.limits);
|
|
2982
|
+
const firstPage = await this.client.documents.listChunks(documentId, {
|
|
2983
|
+
page: 1,
|
|
2984
|
+
pageSize: limits.remotePageSize,
|
|
2985
|
+
includeAssetUrls: false
|
|
2986
|
+
});
|
|
2987
|
+
const revisionKey = getRemoteRevisionKey(firstPage);
|
|
2988
|
+
const stored = await this.tryReadOutlineFromParsedStorage(documentId, revisionKey);
|
|
2989
|
+
if (stored) {
|
|
2990
|
+
return stored;
|
|
2991
|
+
}
|
|
2992
|
+
const chunks = [];
|
|
2993
|
+
let page = 1;
|
|
2994
|
+
let response = firstPage;
|
|
2995
|
+
let scannedPages = 0;
|
|
2996
|
+
const startedAt = Date.now();
|
|
2997
|
+
while (true) {
|
|
2998
|
+
scannedPages += 1;
|
|
2999
|
+
chunks.push(...response.chunks.map(toIndexedRemoteChunk));
|
|
3000
|
+
if (response.pagination.page >= response.pagination.totalPages || scannedPages >= limits.outlineMaxPages || Date.now() - startedAt >= limits.outlineDeadlineMs) {
|
|
3001
|
+
break;
|
|
3002
|
+
}
|
|
3003
|
+
page += 1;
|
|
3004
|
+
response = await this.client.documents.listChunks(documentId, {
|
|
3005
|
+
page,
|
|
3006
|
+
pageSize: limits.remotePageSize,
|
|
3007
|
+
includeAssetUrls: false
|
|
3008
|
+
});
|
|
3009
|
+
}
|
|
3010
|
+
const truncated = response.pagination.page < response.pagination.totalPages;
|
|
3011
|
+
const sections = buildFlatSectionsFromIndexedChunks(chunks);
|
|
3012
|
+
this.scheduleParsedStorageSync(documentId, revisionKey);
|
|
3013
|
+
return {
|
|
3014
|
+
document: createRemoteKnowledgeDocument({
|
|
3015
|
+
documentId,
|
|
3016
|
+
response: firstPage,
|
|
3017
|
+
revisionKey,
|
|
3018
|
+
typeCounts: countIndexedTypes(chunks)
|
|
3019
|
+
}),
|
|
3020
|
+
totalChunks: firstPage.pagination.total,
|
|
3021
|
+
typeCounts: countIndexedTypes(chunks),
|
|
3022
|
+
sections,
|
|
3023
|
+
sectionTree: nestSections(sections),
|
|
3024
|
+
truncated,
|
|
3025
|
+
continuationCursor: truncated ? createContinuationCursor({
|
|
3026
|
+
documentId,
|
|
3027
|
+
revisionKey,
|
|
3028
|
+
nextPage: response.pagination.page + 1
|
|
3029
|
+
}) : void 0
|
|
3030
|
+
};
|
|
3031
|
+
}
|
|
3032
|
+
async tryReadChunksFromParsedStorage(params) {
|
|
3033
|
+
const parsedStorageConfig = this.parsedStorageConfig;
|
|
3034
|
+
if (!parsedStorageConfig) {
|
|
3035
|
+
return null;
|
|
3036
|
+
}
|
|
3037
|
+
const manifest = await this.readFreshParsedStorageManifest(
|
|
3038
|
+
params.documentId,
|
|
3039
|
+
params.revisionKey
|
|
3040
|
+
);
|
|
3041
|
+
if (!manifest) {
|
|
3042
|
+
return null;
|
|
3043
|
+
}
|
|
3044
|
+
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));
|
|
3055
|
+
const selected = hasScanReadFilters(params.params) ? selectReadWindow(
|
|
3056
|
+
scopedChunks,
|
|
3057
|
+
params.params,
|
|
3058
|
+
clampLimit(params.params.limit, DEFAULT_READ_LIMIT, MAX_READ_LIMIT)
|
|
3059
|
+
) : scopedChunks.slice(
|
|
3060
|
+
(pageParams.page - 1) * pageParams.pageSize,
|
|
3061
|
+
pageParams.page * pageParams.pageSize
|
|
3062
|
+
);
|
|
3063
|
+
const visibleChunks = applyAssetUrlPolicyToReadChunks(
|
|
3064
|
+
selected.map(toReadChunk),
|
|
3065
|
+
params.params.assetUrlPolicy
|
|
3066
|
+
);
|
|
3067
|
+
const totalChunks = scopedChunks.length;
|
|
3068
|
+
return {
|
|
3069
|
+
document: createStoredKnowledgeDocument({
|
|
3070
|
+
documentId: params.documentId,
|
|
3071
|
+
manifest,
|
|
3072
|
+
revisionKey: params.revisionKey,
|
|
3073
|
+
typeCounts: countIndexedTypes(indexedChunks)
|
|
3074
|
+
}),
|
|
3075
|
+
chunks: visibleChunks,
|
|
3076
|
+
page: hasScanReadFilters(params.params) ? void 0 : pageParams.page,
|
|
3077
|
+
pageSize: hasScanReadFilters(params.params) ? void 0 : pageParams.pageSize,
|
|
3078
|
+
totalChunks,
|
|
3079
|
+
totalPages: Math.max(1, Math.ceil(totalChunks / pageParams.pageSize)),
|
|
3080
|
+
nextChunk: getNextChunkPosition(scopedChunks, selected)
|
|
3081
|
+
};
|
|
3082
|
+
}
|
|
3083
|
+
async tryGrepChunksFromParsedStorage(params) {
|
|
3084
|
+
const parsedStorageConfig = this.parsedStorageConfig;
|
|
3085
|
+
if (!parsedStorageConfig) {
|
|
3086
|
+
return null;
|
|
3087
|
+
}
|
|
3088
|
+
const manifest = await this.readFreshParsedStorageManifest(
|
|
3089
|
+
params.documentId,
|
|
3090
|
+
params.revisionKey
|
|
3091
|
+
);
|
|
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
|
+
}
|
|
3104
|
+
const maxResults = clampLimit(params.params.maxResults, DEFAULT_GREP_LIMIT, MAX_GREP_LIMIT);
|
|
3105
|
+
const contextChars = params.params.contextChars ?? DEFAULT_CONTEXT_CHARS;
|
|
3106
|
+
const matcher = createMatcher(params.params);
|
|
3107
|
+
const scopedChunks = indexedChunks.filter((chunk) => matchesGrepScope(chunk, params.params));
|
|
3108
|
+
const matches = [];
|
|
3109
|
+
let scannedChunks = 0;
|
|
3110
|
+
for (const chunk of scopedChunks) {
|
|
3111
|
+
scannedChunks += 1;
|
|
3112
|
+
for (const match of matcher(chunk.content)) {
|
|
3113
|
+
matches.push({
|
|
3114
|
+
position: chunk.position,
|
|
3115
|
+
chunkId: chunk.chunkId,
|
|
3116
|
+
chunkType: chunk.chunkType,
|
|
3117
|
+
sectionPath: chunk.sectionPath,
|
|
3118
|
+
sourceChunkPath: chunk.sourceChunkPath,
|
|
3119
|
+
filePath: chunk.filePath,
|
|
3120
|
+
startOffset: match.startOffset,
|
|
3121
|
+
endOffset: match.endOffset,
|
|
3122
|
+
snippet: buildSnippet(chunk.content, match.startOffset, match.endOffset, contextChars)
|
|
3123
|
+
});
|
|
3124
|
+
if (matches.length >= maxResults) {
|
|
3125
|
+
return {
|
|
3126
|
+
document: createStoredKnowledgeDocument({
|
|
3127
|
+
documentId: params.documentId,
|
|
3128
|
+
manifest,
|
|
3129
|
+
revisionKey: params.revisionKey,
|
|
3130
|
+
typeCounts: countIndexedTypes(indexedChunks)
|
|
3131
|
+
}),
|
|
3132
|
+
matches,
|
|
3133
|
+
scannedChunks,
|
|
3134
|
+
truncated: true
|
|
3135
|
+
};
|
|
3136
|
+
}
|
|
3137
|
+
}
|
|
3138
|
+
}
|
|
3139
|
+
return {
|
|
3140
|
+
document: createStoredKnowledgeDocument({
|
|
3141
|
+
documentId: params.documentId,
|
|
3142
|
+
manifest,
|
|
3143
|
+
revisionKey: params.revisionKey,
|
|
3144
|
+
typeCounts: countIndexedTypes(indexedChunks)
|
|
3145
|
+
}),
|
|
3146
|
+
matches,
|
|
3147
|
+
scannedChunks,
|
|
3148
|
+
truncated: false
|
|
3149
|
+
};
|
|
3150
|
+
}
|
|
3151
|
+
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);
|
|
3166
|
+
return {
|
|
3167
|
+
document: createStoredKnowledgeDocument({
|
|
3168
|
+
documentId,
|
|
3169
|
+
manifest,
|
|
3170
|
+
revisionKey,
|
|
3171
|
+
typeCounts
|
|
3172
|
+
}),
|
|
3173
|
+
totalChunks: manifest.totalChunks,
|
|
3174
|
+
typeCounts,
|
|
3175
|
+
sections,
|
|
3176
|
+
sectionTree: nestSections(sections),
|
|
3177
|
+
truncated: false
|
|
3178
|
+
};
|
|
3179
|
+
}
|
|
3180
|
+
async readFreshParsedStorageManifest(documentId, revisionKey) {
|
|
3181
|
+
const parsedStorageConfig = this.parsedStorageConfig;
|
|
3182
|
+
if (!parsedStorageConfig) {
|
|
3183
|
+
return null;
|
|
3184
|
+
}
|
|
3185
|
+
const manifest = await parsedStorageConfig.storage.readManifest({
|
|
3186
|
+
documentId,
|
|
3187
|
+
revisionKey
|
|
3188
|
+
});
|
|
3189
|
+
if (!manifest || !isFreshManifest(manifest, revisionKey)) {
|
|
3190
|
+
return null;
|
|
3191
|
+
}
|
|
3192
|
+
return manifest;
|
|
3193
|
+
}
|
|
3194
|
+
async readStoredSnapshotChunks(params) {
|
|
3195
|
+
const parsedStorageConfig = this.parsedStorageConfig;
|
|
3196
|
+
if (!parsedStorageConfig) {
|
|
3197
|
+
return null;
|
|
3198
|
+
}
|
|
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;
|
|
3244
|
+
}
|
|
3245
|
+
scheduleParsedStorageSync(documentId, revisionKey) {
|
|
3246
|
+
const parsedStorageConfig = this.parsedStorageConfig;
|
|
3247
|
+
if (!parsedStorageConfig) {
|
|
3248
|
+
return;
|
|
3249
|
+
}
|
|
3250
|
+
const scheduler = parsedStorageConfig.scheduler ?? defaultParsedStorageScheduler;
|
|
3251
|
+
const task = async () => {
|
|
3252
|
+
try {
|
|
3253
|
+
await this.syncRemoteDocumentToParsedStorage({
|
|
3254
|
+
documentId,
|
|
3255
|
+
revisionKey,
|
|
3256
|
+
parsedStorageConfig
|
|
3257
|
+
});
|
|
3258
|
+
} catch (error) {
|
|
3259
|
+
await parsedStorageConfig.storage.writeSyncProgress({
|
|
3260
|
+
documentId,
|
|
3261
|
+
revisionKey,
|
|
3262
|
+
nextChunkPage: 1,
|
|
3263
|
+
nextAssetIndex: 0,
|
|
3264
|
+
status: "failed",
|
|
3265
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3266
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3267
|
+
});
|
|
3268
|
+
}
|
|
3269
|
+
};
|
|
3270
|
+
void Promise.resolve(scheduler.schedule(task)).catch(() => void 0);
|
|
3271
|
+
}
|
|
3272
|
+
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,
|
|
3282
|
+
includeAssetUrls: true
|
|
3283
|
+
});
|
|
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
|
|
3290
|
+
});
|
|
3291
|
+
nextPage = 1;
|
|
3292
|
+
}
|
|
3293
|
+
const totalPages = response.pagination.totalPages;
|
|
3294
|
+
const chunkPages = [];
|
|
3295
|
+
let syncedPages = 0;
|
|
3296
|
+
const startedAt = Date.now();
|
|
3297
|
+
while (nextPage <= totalPages) {
|
|
3298
|
+
if (syncedPages > 0) {
|
|
3299
|
+
response = await this.client.documents.listChunks(params.documentId, {
|
|
3300
|
+
page: nextPage,
|
|
3301
|
+
pageSize: limits.remotePageSize,
|
|
3302
|
+
includeAssetUrls: true
|
|
3303
|
+
});
|
|
3304
|
+
}
|
|
3305
|
+
const readChunks = await this.hardenReadChunkAssetUrls({
|
|
3306
|
+
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
|
|
3319
|
+
});
|
|
3320
|
+
chunkPages.push(page);
|
|
3321
|
+
nextPage += 1;
|
|
3322
|
+
syncedPages += 1;
|
|
3323
|
+
await params.parsedStorageConfig.storage.writeSyncProgress({
|
|
3324
|
+
documentId: params.documentId,
|
|
3325
|
+
revisionKey,
|
|
3326
|
+
nextChunkPage: nextPage,
|
|
3327
|
+
nextAssetIndex: 0,
|
|
3328
|
+
status: "running",
|
|
3329
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3330
|
+
});
|
|
3331
|
+
if (syncedPages >= limits.maxPagesPerSync || Date.now() - startedAt >= limits.syncDeadlineMs) {
|
|
3332
|
+
return {
|
|
3333
|
+
documentId: params.documentId,
|
|
3334
|
+
revisionKey,
|
|
3335
|
+
completed: false
|
|
3336
|
+
};
|
|
3337
|
+
}
|
|
3338
|
+
}
|
|
3339
|
+
const manifest = createRemoteSnapshotManifest({
|
|
3340
|
+
response,
|
|
3341
|
+
revisionKey,
|
|
3342
|
+
chunkPages
|
|
3343
|
+
});
|
|
3344
|
+
await params.parsedStorageConfig.storage.writeManifest({
|
|
3345
|
+
documentId: params.documentId,
|
|
3346
|
+
revisionKey,
|
|
3347
|
+
manifest
|
|
3348
|
+
});
|
|
3349
|
+
await params.parsedStorageConfig.storage.writeSyncProgress({
|
|
3350
|
+
documentId: params.documentId,
|
|
3351
|
+
revisionKey,
|
|
3352
|
+
nextChunkPage: totalPages + 1,
|
|
3353
|
+
nextAssetIndex: 0,
|
|
3354
|
+
status: "completed",
|
|
3355
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3356
|
+
});
|
|
3357
|
+
return {
|
|
3358
|
+
documentId: params.documentId,
|
|
3359
|
+
revisionKey,
|
|
3360
|
+
completed: true,
|
|
3361
|
+
manifest
|
|
3362
|
+
};
|
|
3363
|
+
}
|
|
3364
|
+
requireParsedStorageConfig() {
|
|
3365
|
+
if (!this.parsedStorageConfig) {
|
|
3366
|
+
throw new ValidationError("parsed document storage is not configured");
|
|
3367
|
+
}
|
|
3368
|
+
return this.parsedStorageConfig;
|
|
3369
|
+
}
|
|
3370
|
+
async findLocalDocumentByRemoteId(documentId) {
|
|
3371
|
+
const documents = await this.store.listDocuments();
|
|
3372
|
+
return documents.find((document) => document.documentId === documentId);
|
|
3373
|
+
}
|
|
3374
|
+
async getPublishedDocumentJobId(documentId) {
|
|
3375
|
+
const response = await this.client.documents.listChunks(documentId, {
|
|
3376
|
+
page: 1,
|
|
3377
|
+
pageSize: 1
|
|
3378
|
+
});
|
|
3379
|
+
if (!response.jobId) {
|
|
3380
|
+
throw new Error(
|
|
3381
|
+
`Cannot sync server document ${documentId}: current published job id was not returned.`
|
|
3382
|
+
);
|
|
3383
|
+
}
|
|
3384
|
+
return response.jobId;
|
|
3385
|
+
}
|
|
3386
|
+
};
|
|
3387
|
+
function normalizeDocumentReference(reference) {
|
|
3388
|
+
if (typeof reference === "string") {
|
|
3389
|
+
return { localDocumentId: reference };
|
|
3390
|
+
}
|
|
3391
|
+
return reference;
|
|
3392
|
+
}
|
|
3393
|
+
function looksLikeRemoteDocumentId(value) {
|
|
3394
|
+
return REMOTE_DOCUMENT_ID_PATTERN.test(value);
|
|
2079
3395
|
}
|
|
2080
3396
|
function createLocalDocumentIdForRemote(documentId) {
|
|
2081
3397
|
if (SAFE_LOCAL_DOCUMENT_ID_PATTERN.test(documentId) && !documentId.includes("..") && !documentId.includes("/") && !documentId.includes("\\")) {
|
|
@@ -2084,6 +3400,488 @@ function createLocalDocumentIdForRemote(documentId) {
|
|
|
2084
3400
|
const hash = (0, import_crypto2.createHash)("sha256").update(documentId).digest("hex").slice(0, 16);
|
|
2085
3401
|
return `remote_${hash}`;
|
|
2086
3402
|
}
|
|
3403
|
+
var defaultParsedStorageScheduler = {
|
|
3404
|
+
schedule(task) {
|
|
3405
|
+
void task();
|
|
3406
|
+
}
|
|
3407
|
+
};
|
|
3408
|
+
function getParsedStorageLimits(limits) {
|
|
3409
|
+
return {
|
|
3410
|
+
chunkPageSize: clampLimit(limits?.chunkPageSize, DEFAULT_REMOTE_SCAN_PAGE_SIZE, MAX_PAGE_SIZE),
|
|
3411
|
+
remotePageSize: clampLimit(
|
|
3412
|
+
limits?.remotePageSize,
|
|
3413
|
+
DEFAULT_REMOTE_SCAN_PAGE_SIZE,
|
|
3414
|
+
MAX_PAGE_SIZE
|
|
3415
|
+
),
|
|
3416
|
+
maxPagesPerSync: clampLimit(limits?.maxPagesPerSync, DEFAULT_MAX_SYNC_PAGES, 1e3),
|
|
3417
|
+
maxAssetsPerSync: clampLimit(limits?.maxAssetsPerSync, DEFAULT_MAX_SYNC_ASSETS, 1e3),
|
|
3418
|
+
syncDeadlineMs: clampLimit(limits?.syncDeadlineMs, DEFAULT_SYNC_DEADLINE_MS, 6e4),
|
|
3419
|
+
grepMaxPages: clampLimit(limits?.grepMaxPages, DEFAULT_GREP_MAX_PAGES, 1e3),
|
|
3420
|
+
grepDeadlineMs: clampLimit(limits?.grepDeadlineMs, DEFAULT_GREP_DEADLINE_MS, 6e4),
|
|
3421
|
+
outlineMaxPages: clampLimit(limits?.outlineMaxPages, DEFAULT_OUTLINE_MAX_PAGES, 1e3),
|
|
3422
|
+
outlineDeadlineMs: clampLimit(limits?.outlineDeadlineMs, DEFAULT_OUTLINE_DEADLINE_MS, 6e4)
|
|
3423
|
+
};
|
|
3424
|
+
}
|
|
3425
|
+
function validateReadParams(params) {
|
|
3426
|
+
const usesPagedDisplay = params.page !== void 0 || params.pageSize !== void 0 || params.assetUrlPolicy !== void 0;
|
|
3427
|
+
if (!usesPagedDisplay) {
|
|
3428
|
+
return;
|
|
3429
|
+
}
|
|
3430
|
+
if (params.sectionPath !== void 0 || params.startChunk !== void 0 || params.endChunk !== void 0 || params.chunkId !== void 0) {
|
|
3431
|
+
throw new ValidationError(
|
|
3432
|
+
"page, pageSize, and assetUrlPolicy cannot be combined with sectionPath, startChunk, endChunk, or chunkId"
|
|
3433
|
+
);
|
|
3434
|
+
}
|
|
3435
|
+
}
|
|
3436
|
+
function hasScanReadFilters(params) {
|
|
3437
|
+
return params.sectionPath !== void 0 || params.startChunk !== void 0 || params.endChunk !== void 0 || params.chunkId !== void 0;
|
|
3438
|
+
}
|
|
3439
|
+
function getReadPageParams(params) {
|
|
3440
|
+
return {
|
|
3441
|
+
page: clampLimit(params.page, 1, Number.MAX_SAFE_INTEGER),
|
|
3442
|
+
pageSize: clampLimit(params.pageSize ?? params.limit, DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE)
|
|
3443
|
+
};
|
|
3444
|
+
}
|
|
3445
|
+
function shouldRequestRemoteAssetUrls(assetUrlPolicy, parsedStorageConfig) {
|
|
3446
|
+
return assetUrlPolicy === "durable" && parsedStorageConfig !== void 0;
|
|
3447
|
+
}
|
|
3448
|
+
function getRemoteRevisionKey(response) {
|
|
3449
|
+
const revisionKey = response.jobResultId ?? response.jobId;
|
|
3450
|
+
if (!revisionKey) {
|
|
3451
|
+
throw new Error(
|
|
3452
|
+
`Cannot read server document ${response.documentId}: current published revision was not returned.`
|
|
3453
|
+
);
|
|
3454
|
+
}
|
|
3455
|
+
return revisionKey;
|
|
3456
|
+
}
|
|
3457
|
+
function createRemoteKnowledgeDocument(params) {
|
|
3458
|
+
return {
|
|
3459
|
+
localDocumentId: params.documentId,
|
|
3460
|
+
jobId: params.response.jobId ?? params.revisionKey,
|
|
3461
|
+
documentId: params.documentId,
|
|
3462
|
+
namespace: params.response.namespace,
|
|
3463
|
+
sourceFileName: params.documentId,
|
|
3464
|
+
chunkCount: params.response.pagination.total,
|
|
3465
|
+
typeCounts: params.typeCounts ?? countRemoteChunkTypes(params.response.chunks),
|
|
3466
|
+
resultDirectoryPath: `remote:${params.documentId}`,
|
|
3467
|
+
createdAt: /* @__PURE__ */ new Date(0),
|
|
3468
|
+
updatedAt: /* @__PURE__ */ new Date(0)
|
|
3469
|
+
};
|
|
3470
|
+
}
|
|
3471
|
+
function createStoredKnowledgeDocument(params) {
|
|
3472
|
+
return {
|
|
3473
|
+
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,
|
|
3480
|
+
resultDirectoryPath: `parsed-storage:${params.documentId}`,
|
|
3481
|
+
createdAt: new Date(params.manifest.createdAt),
|
|
3482
|
+
updatedAt: new Date(params.manifest.createdAt)
|
|
3483
|
+
};
|
|
3484
|
+
}
|
|
3485
|
+
function isFreshManifest(manifest, revisionKey) {
|
|
3486
|
+
return (manifest.revisionKey ?? manifest.jobId) === revisionKey;
|
|
3487
|
+
}
|
|
3488
|
+
function toRemoteReadChunk(chunk) {
|
|
3489
|
+
const metadata = cloneMetadata(chunk.metadata);
|
|
3490
|
+
return {
|
|
3491
|
+
position: toChunkPosition(chunk),
|
|
3492
|
+
chunkId: chunk.chunkId,
|
|
3493
|
+
chunkType: chunk.chunkType,
|
|
3494
|
+
contentSource: chunk.contentSource ?? void 0,
|
|
3495
|
+
content: chunk.content ?? "",
|
|
3496
|
+
readableContent: getReadableRemoteChunkContent(chunk, metadata),
|
|
3497
|
+
sectionPath: chunk.sectionPath ?? "",
|
|
3498
|
+
sourceChunkPath: chunk.sourceChunkPath ?? chunk.sectionPath ?? "",
|
|
3499
|
+
filePath: chunk.filePath ?? void 0,
|
|
3500
|
+
assetUrl: chunk.assetUrl ?? void 0,
|
|
3501
|
+
pageNumbers: getChunkPageNumbers(metadata),
|
|
3502
|
+
metadata
|
|
3503
|
+
};
|
|
3504
|
+
}
|
|
3505
|
+
function getReadableRemoteChunkContent(chunk, metadata) {
|
|
3506
|
+
if (chunk.chunkType !== "page") {
|
|
3507
|
+
return chunk.content ?? "";
|
|
3508
|
+
}
|
|
3509
|
+
const summary = metadata.summary;
|
|
3510
|
+
return typeof summary === "string" && summary.trim().length > 0 ? summary : chunk.content ?? "";
|
|
3511
|
+
}
|
|
3512
|
+
function toIndexedRemoteChunk(chunk) {
|
|
3513
|
+
const readChunk = toRemoteReadChunk(chunk);
|
|
3514
|
+
return toIndexedReadChunk(readChunk);
|
|
3515
|
+
}
|
|
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)
|
|
3530
|
+
});
|
|
3531
|
+
}
|
|
3532
|
+
function toIndexedReadChunk(chunk) {
|
|
3533
|
+
return {
|
|
3534
|
+
source: createSyntheticChunk(chunk),
|
|
3535
|
+
position: chunk.position,
|
|
3536
|
+
chunkId: chunk.chunkId,
|
|
3537
|
+
chunkType: chunk.chunkType,
|
|
3538
|
+
contentSource: chunk.contentSource,
|
|
3539
|
+
content: chunk.content,
|
|
3540
|
+
readableContent: chunk.readableContent,
|
|
3541
|
+
sectionPath: chunk.sectionPath,
|
|
3542
|
+
sourceChunkPath: chunk.sourceChunkPath,
|
|
3543
|
+
filePath: chunk.filePath,
|
|
3544
|
+
assetUrl: chunk.assetUrl,
|
|
3545
|
+
pageNumbers: chunk.pageNumbers,
|
|
3546
|
+
metadata: chunk.metadata
|
|
3547
|
+
};
|
|
3548
|
+
}
|
|
3549
|
+
function createSyntheticChunk(chunk) {
|
|
3550
|
+
return {
|
|
3551
|
+
chunkId: chunk.chunkId,
|
|
3552
|
+
type: chunk.chunkType,
|
|
3553
|
+
contentSource: chunk.contentSource,
|
|
3554
|
+
content: chunk.content,
|
|
3555
|
+
path: chunk.sourceChunkPath,
|
|
3556
|
+
metadata: chunk.metadata
|
|
3557
|
+
};
|
|
3558
|
+
}
|
|
3559
|
+
function toChunkPosition(chunk) {
|
|
3560
|
+
return chunk ? chunk.sortOrder + 1 : 1;
|
|
3561
|
+
}
|
|
3562
|
+
function buildFlatSectionsFromIndexedChunks(chunks) {
|
|
3563
|
+
const byPath = /* @__PURE__ */ new Map();
|
|
3564
|
+
for (const chunk of chunks) {
|
|
3565
|
+
const path4 = chunk.sectionPath || chunk.sourceChunkPath;
|
|
3566
|
+
const existing = byPath.get(path4);
|
|
3567
|
+
if (existing) {
|
|
3568
|
+
addChunkToSection(existing, chunk);
|
|
3569
|
+
} else {
|
|
3570
|
+
byPath.set(path4, createSectionFromChunk(path4, chunk));
|
|
3571
|
+
}
|
|
3572
|
+
}
|
|
3573
|
+
return [...byPath.values()].sort(compareSections);
|
|
3574
|
+
}
|
|
3575
|
+
function matchesRemoteReadScope(chunk, params) {
|
|
3576
|
+
return matchesReadScope(toIndexedRemoteChunk(chunk), params);
|
|
3577
|
+
}
|
|
3578
|
+
function getNextChunkPosition(chunks, selected) {
|
|
3579
|
+
const lastSelected = selected[selected.length - 1];
|
|
3580
|
+
if (!lastSelected || selected.length >= chunks.length) {
|
|
3581
|
+
return void 0;
|
|
3582
|
+
}
|
|
3583
|
+
return chunks[chunks.indexOf(lastSelected) + 1]?.position;
|
|
3584
|
+
}
|
|
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
|
+
}));
|
|
3597
|
+
}
|
|
3598
|
+
async function hardenReadChunkAssetUrls(params) {
|
|
3599
|
+
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({
|
|
3616
|
+
storageConfig: params.storageConfig,
|
|
3617
|
+
documentId: params.documentId,
|
|
3618
|
+
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
|
+
}
|
|
3628
|
+
});
|
|
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({
|
|
3667
|
+
documentId: params.documentId,
|
|
3668
|
+
revisionKey: params.revisionKey,
|
|
3669
|
+
sourcePath: params.sourcePath
|
|
3670
|
+
});
|
|
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}`);
|
|
3697
|
+
}
|
|
3698
|
+
return {
|
|
3699
|
+
body: new Uint8Array(await response.arrayBuffer()),
|
|
3700
|
+
contentType: response.headers.get("content-type") ?? fallbackContentType
|
|
3701
|
+
};
|
|
3702
|
+
}
|
|
3703
|
+
function removeAssetUrlsFromMetadata(metadata) {
|
|
3704
|
+
const cloned = cloneMetadata(metadata);
|
|
3705
|
+
const pageAssets = toUnknownArray(cloned.pageAssets);
|
|
3706
|
+
if (!pageAssets) {
|
|
3707
|
+
return cloned;
|
|
3708
|
+
}
|
|
3709
|
+
cloned.pageAssets = pageAssets.map((pageAsset) => {
|
|
3710
|
+
if (!isRecord2(pageAsset)) {
|
|
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
|
+
};
|
|
3736
|
+
}
|
|
3737
|
+
function toSnapshotChunkFromReadChunk(chunk) {
|
|
3738
|
+
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
|
|
3750
|
+
};
|
|
3751
|
+
}
|
|
3752
|
+
function createRemoteSnapshotManifest(params) {
|
|
3753
|
+
return {
|
|
3754
|
+
version: 1,
|
|
3755
|
+
kind: "knowhere-parsed-result-snapshot",
|
|
3756
|
+
jobId: params.response.jobId ?? params.revisionKey,
|
|
3757
|
+
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
|
+
);
|
|
3783
|
+
}
|
|
3784
|
+
function countRemoteChunkTypes(chunks) {
|
|
3785
|
+
return chunks.reduce(
|
|
3786
|
+
(counts, chunk) => {
|
|
3787
|
+
counts[chunk.chunkType] += 1;
|
|
3788
|
+
return counts;
|
|
3789
|
+
},
|
|
3790
|
+
{ text: 0, image: 0, table: 0, page: 0 }
|
|
3791
|
+
);
|
|
3792
|
+
}
|
|
3793
|
+
function createContinuationCursor(cursor) {
|
|
3794
|
+
return Buffer.from(JSON.stringify(cursor), "utf8").toString("base64url");
|
|
3795
|
+
}
|
|
3796
|
+
function createGrepContinuationCursor(params) {
|
|
3797
|
+
if (params.matchIndex + 1 < params.chunkMatchCount) {
|
|
3798
|
+
return createContinuationCursor({
|
|
3799
|
+
documentId: params.documentId,
|
|
3800
|
+
revisionKey: params.revisionKey,
|
|
3801
|
+
nextPage: params.response.pagination.page,
|
|
3802
|
+
nextChunkIndex: params.chunkIndex,
|
|
3803
|
+
nextMatchIndex: params.matchIndex + 1
|
|
3804
|
+
});
|
|
3805
|
+
}
|
|
3806
|
+
if (params.chunkIndex + 1 < params.response.chunks.length) {
|
|
3807
|
+
return createContinuationCursor({
|
|
3808
|
+
documentId: params.documentId,
|
|
3809
|
+
revisionKey: params.revisionKey,
|
|
3810
|
+
nextPage: params.response.pagination.page,
|
|
3811
|
+
nextChunkIndex: params.chunkIndex + 1,
|
|
3812
|
+
nextMatchIndex: 0
|
|
3813
|
+
});
|
|
3814
|
+
}
|
|
3815
|
+
if (params.response.pagination.page < params.response.pagination.totalPages) {
|
|
3816
|
+
return createContinuationCursor({
|
|
3817
|
+
documentId: params.documentId,
|
|
3818
|
+
revisionKey: params.revisionKey,
|
|
3819
|
+
nextPage: params.response.pagination.page + 1,
|
|
3820
|
+
nextChunkIndex: 0,
|
|
3821
|
+
nextMatchIndex: 0
|
|
3822
|
+
});
|
|
3823
|
+
}
|
|
3824
|
+
return void 0;
|
|
3825
|
+
}
|
|
3826
|
+
function parseContinuationCursor(value) {
|
|
3827
|
+
if (!value) {
|
|
3828
|
+
return null;
|
|
3829
|
+
}
|
|
3830
|
+
try {
|
|
3831
|
+
const parsed = JSON.parse(Buffer.from(value, "base64url").toString("utf8"));
|
|
3832
|
+
if (!isRecord2(parsed)) {
|
|
3833
|
+
return null;
|
|
3834
|
+
}
|
|
3835
|
+
const documentId = parsed.documentId;
|
|
3836
|
+
const revisionKey = parsed.revisionKey;
|
|
3837
|
+
const nextPage = parsed.nextPage;
|
|
3838
|
+
const nextChunkIndex = parsed.nextChunkIndex;
|
|
3839
|
+
const nextMatchIndex = parsed.nextMatchIndex;
|
|
3840
|
+
if (typeof documentId !== "string" || typeof revisionKey !== "string" || typeof nextPage !== "number" || !Number.isInteger(nextPage) || nextPage < 1 || !isOptionalNonNegativeInteger(nextChunkIndex) || !isOptionalNonNegativeInteger(nextMatchIndex)) {
|
|
3841
|
+
return null;
|
|
3842
|
+
}
|
|
3843
|
+
return {
|
|
3844
|
+
documentId,
|
|
3845
|
+
revisionKey,
|
|
3846
|
+
nextPage,
|
|
3847
|
+
nextChunkIndex,
|
|
3848
|
+
nextMatchIndex
|
|
3849
|
+
};
|
|
3850
|
+
} catch {
|
|
3851
|
+
return null;
|
|
3852
|
+
}
|
|
3853
|
+
}
|
|
3854
|
+
function isOptionalNonNegativeInteger(value) {
|
|
3855
|
+
return value === void 0 || typeof value === "number" && Number.isInteger(value) && value >= 0;
|
|
3856
|
+
}
|
|
3857
|
+
function cloneMetadata(metadata) {
|
|
3858
|
+
return { ...metadata };
|
|
3859
|
+
}
|
|
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
|
+
function toUnknownArray(value) {
|
|
3873
|
+
return Array.isArray(value) ? value : null;
|
|
3874
|
+
}
|
|
3875
|
+
function inferContentTypeFromPath(filePath) {
|
|
3876
|
+
const extension = filePath.split(".").at(-1)?.toLowerCase();
|
|
3877
|
+
if (extension === "png") return "image/png";
|
|
3878
|
+
if (extension === "jpg" || extension === "jpeg") return "image/jpeg";
|
|
3879
|
+
if (extension === "html" || extension === "htm") return "text/html; charset=utf-8";
|
|
3880
|
+
return "application/octet-stream";
|
|
3881
|
+
}
|
|
3882
|
+
function isRecord2(value) {
|
|
3883
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3884
|
+
}
|
|
2087
3885
|
function indexChunks(result) {
|
|
2088
3886
|
return result.chunks.map((chunk, index) => {
|
|
2089
3887
|
const filePath = getChunkFilePath2(chunk);
|
|
@@ -2099,6 +3897,7 @@ function indexChunks(result) {
|
|
|
2099
3897
|
sectionPath: normalizeSectionPath(chunk.path, result.manifest.sourceFileName),
|
|
2100
3898
|
sourceChunkPath: chunk.path,
|
|
2101
3899
|
filePath,
|
|
3900
|
+
assetUrl: getChunkAssetUrl(chunk),
|
|
2102
3901
|
pageNumbers: getChunkPageNumbers(chunk.metadata),
|
|
2103
3902
|
metadata: chunk.metadata
|
|
2104
3903
|
};
|
|
@@ -2112,12 +3911,11 @@ function getReadableChunkContent(chunk) {
|
|
|
2112
3911
|
return typeof summary === "string" && summary.trim().length > 0 ? summary : chunk.content;
|
|
2113
3912
|
}
|
|
2114
3913
|
function getChunkPageNumbers(metadata) {
|
|
2115
|
-
const
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
(pageNumber) => Number.isInteger(pageNumber) && pageNumber > 0
|
|
3914
|
+
const values = [metadata.pageNums, metadata.page_nums].filter(Array.isArray);
|
|
3915
|
+
const pageNumbers = values.flatMap(
|
|
3916
|
+
(value) => value.filter(
|
|
3917
|
+
(pageNumber) => Number.isInteger(pageNumber) && pageNumber > 0
|
|
3918
|
+
)
|
|
2121
3919
|
);
|
|
2122
3920
|
return pageNumbers.length > 0 ? [...new Set(pageNumbers)].sort((left, right) => left - right) : void 0;
|
|
2123
3921
|
}
|
|
@@ -2128,14 +3926,17 @@ function getChunkFilePath2(chunk) {
|
|
|
2128
3926
|
const filePath = chunk.metadata.filePath;
|
|
2129
3927
|
return typeof filePath === "string" ? filePath : void 0;
|
|
2130
3928
|
}
|
|
2131
|
-
function
|
|
2132
|
-
|
|
3929
|
+
function getChunkAssetUrl(chunk) {
|
|
3930
|
+
return chunk.type === "image" || chunk.type === "table" ? chunk.assetUrl : void 0;
|
|
3931
|
+
}
|
|
3932
|
+
function normalizeSectionPath(path4, sourceFileName) {
|
|
3933
|
+
if (!path4) {
|
|
2133
3934
|
return "";
|
|
2134
3935
|
}
|
|
2135
|
-
if (
|
|
2136
|
-
return
|
|
3936
|
+
if (path4.startsWith("images/") || path4.startsWith("tables/")) {
|
|
3937
|
+
return path4;
|
|
2137
3938
|
}
|
|
2138
|
-
const parts =
|
|
3939
|
+
const parts = path4.split("/").filter(Boolean);
|
|
2139
3940
|
if (sourceFileName) {
|
|
2140
3941
|
const fileNameIndex = parts.indexOf(sourceFileName);
|
|
2141
3942
|
if (fileNameIndex >= 0) {
|
|
@@ -2157,12 +3958,12 @@ function buildFlatSections(result, chunks) {
|
|
|
2157
3958
|
}
|
|
2158
3959
|
const byPath = /* @__PURE__ */ new Map();
|
|
2159
3960
|
for (const chunk of chunks) {
|
|
2160
|
-
const
|
|
2161
|
-
const existing = byPath.get(
|
|
3961
|
+
const path4 = chunk.sectionPath || chunk.sourceChunkPath;
|
|
3962
|
+
const existing = byPath.get(path4);
|
|
2162
3963
|
if (existing) {
|
|
2163
3964
|
addChunkToSection(existing, chunk);
|
|
2164
3965
|
} else {
|
|
2165
|
-
byPath.set(
|
|
3966
|
+
byPath.set(path4, createSectionFromChunk(path4, chunk));
|
|
2166
3967
|
}
|
|
2167
3968
|
}
|
|
2168
3969
|
return [...byPath.values()].sort(compareSections);
|
|
@@ -2296,6 +4097,7 @@ function toReadChunk(chunk) {
|
|
|
2296
4097
|
sectionPath: chunk.sectionPath,
|
|
2297
4098
|
sourceChunkPath: chunk.sourceChunkPath,
|
|
2298
4099
|
filePath: chunk.filePath,
|
|
4100
|
+
assetUrl: chunk.assetUrl,
|
|
2299
4101
|
pageNumbers: chunk.pageNumbers,
|
|
2300
4102
|
metadata: chunk.metadata
|
|
2301
4103
|
};
|
|
@@ -2472,7 +4274,12 @@ var Knowhere = class {
|
|
|
2472
4274
|
const result = await this.jobs.load(jobResult, {
|
|
2473
4275
|
verifyChecksum: params.verifyChecksum
|
|
2474
4276
|
});
|
|
2475
|
-
|
|
4277
|
+
const enrichedResult = enrichParseResult(result, {
|
|
4278
|
+
namespace: jobResult.namespace,
|
|
4279
|
+
documentId: jobResult.documentId ?? params.documentId
|
|
4280
|
+
});
|
|
4281
|
+
const storedResult = await storeParseResultAssets(enrichedResult, params.storageAdapter);
|
|
4282
|
+
return storedResult.result;
|
|
2476
4283
|
}
|
|
2477
4284
|
/**
|
|
2478
4285
|
* Start a parse job and return immediately after the URL job is created or
|
|
@@ -2515,6 +4322,145 @@ var Knowhere = class {
|
|
|
2515
4322
|
return job;
|
|
2516
4323
|
}
|
|
2517
4324
|
};
|
|
4325
|
+
|
|
4326
|
+
// src/storage/disk-parsed-document-storage.ts
|
|
4327
|
+
var import_crypto3 = require("crypto");
|
|
4328
|
+
var import_fs4 = require("fs");
|
|
4329
|
+
var import_path4 = __toESM(require("path"));
|
|
4330
|
+
var DiskParsedDocumentStorage = class {
|
|
4331
|
+
rootDirectory;
|
|
4332
|
+
constructor(rootDirectory) {
|
|
4333
|
+
this.rootDirectory = rootDirectory;
|
|
4334
|
+
}
|
|
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
|
+
);
|
|
4356
|
+
}
|
|
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`, {
|
|
4362
|
+
contentType: params.contentType,
|
|
4363
|
+
metadata: params.metadata ?? {}
|
|
4364
|
+
});
|
|
4365
|
+
return {
|
|
4366
|
+
sourcePath: params.sourcePath,
|
|
4367
|
+
url: toFileUrl(assetPath)
|
|
4368
|
+
};
|
|
4369
|
+
}
|
|
4370
|
+
async getAssetUrl(params) {
|
|
4371
|
+
const assetPath = this.getAssetPath(params.documentId, params.revisionKey, params.sourcePath);
|
|
4372
|
+
try {
|
|
4373
|
+
await import_fs4.promises.access(assetPath);
|
|
4374
|
+
return toFileUrl(assetPath);
|
|
4375
|
+
} catch (error) {
|
|
4376
|
+
if (isMissingFileError3(error)) {
|
|
4377
|
+
return null;
|
|
4378
|
+
}
|
|
4379
|
+
throw error;
|
|
4380
|
+
}
|
|
4381
|
+
}
|
|
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);
|
|
4389
|
+
}
|
|
4390
|
+
getManifestPath(documentId, revisionKey) {
|
|
4391
|
+
return import_path4.default.join(
|
|
4392
|
+
this.getRevisionDirectory(documentId, revisionKey),
|
|
4393
|
+
"manifest",
|
|
4394
|
+
"current.json"
|
|
4395
|
+
);
|
|
4396
|
+
}
|
|
4397
|
+
getChunkPagePath(documentId, revisionKey, page) {
|
|
4398
|
+
return import_path4.default.join(
|
|
4399
|
+
this.getRevisionDirectory(documentId, revisionKey),
|
|
4400
|
+
"chunks",
|
|
4401
|
+
`page-${page}.json`
|
|
4402
|
+
);
|
|
4403
|
+
}
|
|
4404
|
+
getProgressPath(documentId, revisionKey) {
|
|
4405
|
+
return import_path4.default.join(this.getRevisionDirectory(documentId, revisionKey), "sync-progress.json");
|
|
4406
|
+
}
|
|
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}`);
|
|
4420
|
+
}
|
|
4421
|
+
return assetPath;
|
|
4422
|
+
}
|
|
4423
|
+
getRevisionDirectory(documentId, revisionKey) {
|
|
4424
|
+
return import_path4.default.join(this.rootDirectory, hashPathPart(documentId), hashPathPart(revisionKey));
|
|
4425
|
+
}
|
|
4426
|
+
async readOptionalJson(filePath) {
|
|
4427
|
+
try {
|
|
4428
|
+
return JSON.parse(await import_fs4.promises.readFile(filePath, "utf8"));
|
|
4429
|
+
} catch (error) {
|
|
4430
|
+
if (isMissingFileError3(error)) {
|
|
4431
|
+
return null;
|
|
4432
|
+
}
|
|
4433
|
+
throw error;
|
|
4434
|
+
}
|
|
4435
|
+
}
|
|
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), {
|
|
4439
|
+
encoding: "utf8",
|
|
4440
|
+
flag: "w"
|
|
4441
|
+
});
|
|
4442
|
+
}
|
|
4443
|
+
};
|
|
4444
|
+
function hashPathPart(value) {
|
|
4445
|
+
return (0, import_crypto3.createHash)("sha256").update(value).digest("hex").slice(0, 24);
|
|
4446
|
+
}
|
|
4447
|
+
function normalizeRelativeStoragePath(value) {
|
|
4448
|
+
const normalized = value.replaceAll("\\", "/").replace(/^\.\/+/, "");
|
|
4449
|
+
if (normalized.length === 0 || normalized.includes("\0") || normalized.startsWith("/") || normalized.split("/").some((part) => part.length === 0 || part === "." || part === "..")) {
|
|
4450
|
+
throw new Error(`Invalid parsed storage path: ${value}`);
|
|
4451
|
+
}
|
|
4452
|
+
return normalized;
|
|
4453
|
+
}
|
|
4454
|
+
function isPathInsideDirectory2(filePath, directory) {
|
|
4455
|
+
const relative = import_path4.default.relative(directory, filePath);
|
|
4456
|
+
return relative === "" || !relative.startsWith("..") && !import_path4.default.isAbsolute(relative);
|
|
4457
|
+
}
|
|
4458
|
+
function toFileUrl(filePath) {
|
|
4459
|
+
return `file://${filePath}`;
|
|
4460
|
+
}
|
|
4461
|
+
function isMissingFileError3(error) {
|
|
4462
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
4463
|
+
}
|
|
2518
4464
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2519
4465
|
0 && (module.exports = {
|
|
2520
4466
|
APIError,
|
|
@@ -2522,6 +4468,7 @@ var Knowhere = class {
|
|
|
2522
4468
|
BadRequestError,
|
|
2523
4469
|
ChecksumError,
|
|
2524
4470
|
ConflictError,
|
|
4471
|
+
DiskParsedDocumentStorage,
|
|
2525
4472
|
Documents,
|
|
2526
4473
|
GatewayTimeoutError,
|
|
2527
4474
|
InternalServerError,
|
|
@@ -2542,5 +4489,7 @@ var Knowhere = class {
|
|
|
2542
4489
|
ServiceUnavailableError,
|
|
2543
4490
|
TimeoutError,
|
|
2544
4491
|
VERSION,
|
|
2545
|
-
ValidationError
|
|
4492
|
+
ValidationError,
|
|
4493
|
+
storeParseResultAssets,
|
|
4494
|
+
syncParseResultToParsedDocumentStorage
|
|
2546
4495
|
});
|