@ontos-ai/knowhere-sdk 2.4.2 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/dist/chunk-4PWLXJGH.mjs +719 -0
- package/dist/index.d.mts +30 -2
- package/dist/index.d.ts +30 -2
- package/dist/index.js +1051 -513
- package/dist/index.mjs +127 -446
- package/dist/sequential-parsed-document-archive-S56UEARH.mjs +139 -0
- package/package.json +5 -2
package/dist/index.js
CHANGED
|
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
8
11
|
var __export = (target, all) => {
|
|
9
12
|
for (var name in all)
|
|
10
13
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -15,17 +18,877 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
18
|
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
19
|
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
20
|
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
24
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
25
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
26
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
27
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
28
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
29
|
+
mod
|
|
30
|
+
));
|
|
31
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
|
+
|
|
33
|
+
// src/constants.ts
|
|
34
|
+
var DEFAULT_BASE_URL, DEFAULT_TIMEOUT, DEFAULT_MAX_RETRIES, DEFAULT_POLL_INTERVAL, MAX_POLL_INTERVAL, DEFAULT_POLL_TIMEOUT, POLL_INTERVAL_INCREASE_THRESHOLD, POLL_INTERVAL_MULTIPLIER, INITIAL_RETRY_DELAY, MAX_RETRY_DELAY, RETRY_DELAY_BASE, RETRYABLE_STATUS_CODES, TERMINAL_JOB_STATUSES, ENV;
|
|
35
|
+
var init_constants = __esm({
|
|
36
|
+
"src/constants.ts"() {
|
|
37
|
+
"use strict";
|
|
38
|
+
DEFAULT_BASE_URL = "https://api.knowhereto.ai";
|
|
39
|
+
DEFAULT_TIMEOUT = 6e4;
|
|
40
|
+
DEFAULT_MAX_RETRIES = 5;
|
|
41
|
+
DEFAULT_POLL_INTERVAL = 1e4;
|
|
42
|
+
MAX_POLL_INTERVAL = 3e4;
|
|
43
|
+
DEFAULT_POLL_TIMEOUT = 18e5;
|
|
44
|
+
POLL_INTERVAL_INCREASE_THRESHOLD = 6e4;
|
|
45
|
+
POLL_INTERVAL_MULTIPLIER = 1.2;
|
|
46
|
+
INITIAL_RETRY_DELAY = 500;
|
|
47
|
+
MAX_RETRY_DELAY = 3e4;
|
|
48
|
+
RETRY_DELAY_BASE = 2;
|
|
49
|
+
RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([409, 429, 502, 503, 504]);
|
|
50
|
+
TERMINAL_JOB_STATUSES = /* @__PURE__ */ new Set(["done", "failed"]);
|
|
51
|
+
ENV = {
|
|
52
|
+
API_KEY: "KNOWHERE_API_KEY",
|
|
53
|
+
BASE_URL: "KNOWHERE_BASE_URL",
|
|
54
|
+
LOG_LEVEL: "KNOWHERE_LOG_LEVEL"
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// src/errors/base.ts
|
|
60
|
+
var KnowhereError, NetworkError, TimeoutError, PollingTimeoutError, ChecksumError, ValidationError, InvalidStateError;
|
|
61
|
+
var init_base = __esm({
|
|
62
|
+
"src/errors/base.ts"() {
|
|
63
|
+
"use strict";
|
|
64
|
+
KnowhereError = class extends Error {
|
|
65
|
+
constructor(message) {
|
|
66
|
+
super(message);
|
|
67
|
+
this.name = "KnowhereError";
|
|
68
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
NetworkError = class extends KnowhereError {
|
|
72
|
+
constructor(message, cause) {
|
|
73
|
+
super(message);
|
|
74
|
+
this.cause = cause;
|
|
75
|
+
this.name = "NetworkError";
|
|
76
|
+
}
|
|
77
|
+
cause;
|
|
78
|
+
};
|
|
79
|
+
TimeoutError = class extends NetworkError {
|
|
80
|
+
constructor(message = "Request timed out") {
|
|
81
|
+
super(message);
|
|
82
|
+
this.name = "TimeoutError";
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
PollingTimeoutError = class extends KnowhereError {
|
|
86
|
+
constructor(message = "Polling timed out", elapsedMs) {
|
|
87
|
+
super(message);
|
|
88
|
+
this.elapsedMs = elapsedMs;
|
|
89
|
+
this.name = "PollingTimeoutError";
|
|
90
|
+
}
|
|
91
|
+
elapsedMs;
|
|
92
|
+
};
|
|
93
|
+
ChecksumError = class extends KnowhereError {
|
|
94
|
+
constructor(message = "Checksum verification failed", expected, actual) {
|
|
95
|
+
super(message);
|
|
96
|
+
this.expected = expected;
|
|
97
|
+
this.actual = actual;
|
|
98
|
+
this.name = "ChecksumError";
|
|
99
|
+
}
|
|
100
|
+
expected;
|
|
101
|
+
actual;
|
|
102
|
+
};
|
|
103
|
+
ValidationError = class extends KnowhereError {
|
|
104
|
+
constructor(message) {
|
|
105
|
+
super(message);
|
|
106
|
+
this.name = "ValidationError";
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
InvalidStateError = class extends KnowhereError {
|
|
110
|
+
constructor(message) {
|
|
111
|
+
super(message);
|
|
112
|
+
this.name = "InvalidStateError";
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// src/errors/parsed-document-archive-error.ts
|
|
119
|
+
var ParsedDocumentArchiveError;
|
|
120
|
+
var init_parsed_document_archive_error = __esm({
|
|
121
|
+
"src/errors/parsed-document-archive-error.ts"() {
|
|
122
|
+
"use strict";
|
|
123
|
+
init_base();
|
|
124
|
+
ParsedDocumentArchiveError = class extends KnowhereError {
|
|
125
|
+
code = "ARCHIVE_SPOOL_FAILED";
|
|
126
|
+
cause;
|
|
127
|
+
constructor(cause) {
|
|
128
|
+
super(
|
|
129
|
+
"Parsed result ZIP temporary storage is unavailable. Range-enabled object storage avoids temporary disk usage."
|
|
130
|
+
);
|
|
131
|
+
this.name = "ParsedDocumentArchiveError";
|
|
132
|
+
this.cause = cause;
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// src/lib/utils.ts
|
|
139
|
+
function sleep(ms) {
|
|
140
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
141
|
+
}
|
|
142
|
+
function snakeToCamel(str) {
|
|
143
|
+
return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
144
|
+
}
|
|
145
|
+
function camelToSnake(str) {
|
|
146
|
+
return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
|
147
|
+
}
|
|
148
|
+
function keysToCamel(obj) {
|
|
149
|
+
if (obj === null || obj === void 0) {
|
|
150
|
+
return obj;
|
|
151
|
+
}
|
|
152
|
+
if (Array.isArray(obj)) {
|
|
153
|
+
return obj.map((item) => keysToCamel(item));
|
|
154
|
+
}
|
|
155
|
+
if (typeof obj === "object" && obj.constructor === Object) {
|
|
156
|
+
const result = {};
|
|
157
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
158
|
+
result[snakeToCamel(key)] = keysToCamel(value);
|
|
159
|
+
}
|
|
160
|
+
return result;
|
|
161
|
+
}
|
|
162
|
+
return obj;
|
|
163
|
+
}
|
|
164
|
+
function keysToSnake(obj) {
|
|
165
|
+
if (obj === null || obj === void 0) {
|
|
166
|
+
return obj;
|
|
167
|
+
}
|
|
168
|
+
if (Array.isArray(obj)) {
|
|
169
|
+
return obj.map((item) => keysToSnake(item));
|
|
170
|
+
}
|
|
171
|
+
if (typeof obj === "object" && obj.constructor === Object) {
|
|
172
|
+
const result = {};
|
|
173
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
174
|
+
result[camelToSnake(key)] = keysToSnake(value);
|
|
175
|
+
}
|
|
176
|
+
return result;
|
|
177
|
+
}
|
|
178
|
+
return obj;
|
|
179
|
+
}
|
|
180
|
+
function parseDates(obj) {
|
|
181
|
+
if (obj === null || obj === void 0) {
|
|
182
|
+
return obj;
|
|
183
|
+
}
|
|
184
|
+
if (Array.isArray(obj)) {
|
|
185
|
+
return obj.map((item) => parseDates(item));
|
|
186
|
+
}
|
|
187
|
+
if (typeof obj === "object" && obj.constructor === Object) {
|
|
188
|
+
const result = {};
|
|
189
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
190
|
+
if ((key.endsWith("At") || key.endsWith("Date")) && typeof value === "string" && /^\d{4}-\d{2}-\d{2}T/.test(value)) {
|
|
191
|
+
result[key] = new Date(value);
|
|
192
|
+
} else {
|
|
193
|
+
result[key] = parseDates(value);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return result;
|
|
197
|
+
}
|
|
198
|
+
return obj;
|
|
199
|
+
}
|
|
200
|
+
function isTerminalStatus(status) {
|
|
201
|
+
return TERMINAL_JOB_STATUSES.has(status);
|
|
202
|
+
}
|
|
203
|
+
function enrichJobResult(jobResult) {
|
|
204
|
+
const computedProperties = {};
|
|
205
|
+
if (!Object.getOwnPropertyDescriptor(jobResult, "isTerminal")) {
|
|
206
|
+
computedProperties.isTerminal = {
|
|
207
|
+
get() {
|
|
208
|
+
return isTerminalStatus(this.status);
|
|
209
|
+
},
|
|
210
|
+
enumerable: true,
|
|
211
|
+
configurable: true
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
if (!Object.getOwnPropertyDescriptor(jobResult, "isDone")) {
|
|
215
|
+
computedProperties.isDone = {
|
|
216
|
+
get() {
|
|
217
|
+
return this.status === "done";
|
|
218
|
+
},
|
|
219
|
+
enumerable: true,
|
|
220
|
+
configurable: true
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
if (!Object.getOwnPropertyDescriptor(jobResult, "isFailed")) {
|
|
224
|
+
computedProperties.isFailed = {
|
|
225
|
+
get() {
|
|
226
|
+
return this.status === "failed";
|
|
227
|
+
},
|
|
228
|
+
enumerable: true,
|
|
229
|
+
configurable: true
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
if (Object.keys(computedProperties).length > 0) {
|
|
233
|
+
Object.defineProperties(jobResult, computedProperties);
|
|
234
|
+
}
|
|
235
|
+
return jobResult;
|
|
236
|
+
}
|
|
237
|
+
function enrichParseResult(parseResult2, scope) {
|
|
238
|
+
if (scope.namespace !== void 0) {
|
|
239
|
+
parseResult2.namespace = scope.namespace;
|
|
240
|
+
}
|
|
241
|
+
if (scope.documentId !== void 0) {
|
|
242
|
+
parseResult2.documentId = scope.documentId;
|
|
243
|
+
}
|
|
244
|
+
return parseResult2;
|
|
245
|
+
}
|
|
246
|
+
function sanitizePath(path4) {
|
|
247
|
+
let sanitized = path4.replace(/^\/+/, "");
|
|
248
|
+
sanitized = sanitized.replace(/\.\.(\/|\\)/g, "");
|
|
249
|
+
sanitized = sanitized.replace(/\\/g, "/");
|
|
250
|
+
return sanitized;
|
|
251
|
+
}
|
|
252
|
+
function getFileExtension(filename) {
|
|
253
|
+
const match = filename.match(/\.([^.]+)$/);
|
|
254
|
+
return match ? match[1].toLowerCase() : "";
|
|
255
|
+
}
|
|
256
|
+
function jitter(value, percent = 0.2) {
|
|
257
|
+
const randomFactor = 1 + (Math.random() * 2 - 1) * percent;
|
|
258
|
+
return Math.round(value * randomFactor);
|
|
259
|
+
}
|
|
260
|
+
var init_utils = __esm({
|
|
261
|
+
"src/lib/utils.ts"() {
|
|
262
|
+
"use strict";
|
|
263
|
+
init_constants();
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// src/storage/parsed-document-storage.ts
|
|
268
|
+
async function syncParseResultToParsedDocumentStorage(params) {
|
|
269
|
+
const documentId = params.documentId ?? params.result.documentId ?? params.result.jobId;
|
|
270
|
+
const revisionKey = params.revisionKey ?? params.result.jobId;
|
|
271
|
+
for await (const object of collectResultLayoutObjects(params.result)) {
|
|
272
|
+
params.signal?.throwIfAborted();
|
|
273
|
+
await params.storage.writeObject({
|
|
274
|
+
documentId,
|
|
275
|
+
revisionKey,
|
|
276
|
+
...object
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
await params.beforeCommit?.();
|
|
280
|
+
params.signal?.throwIfAborted();
|
|
281
|
+
const commit = {
|
|
282
|
+
version: 1,
|
|
283
|
+
documentId,
|
|
284
|
+
revisionKey,
|
|
285
|
+
source: params.source ?? "resultZip",
|
|
286
|
+
committedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
287
|
+
};
|
|
288
|
+
await writeParsedDocumentJsonObject(params.storage, {
|
|
289
|
+
documentId,
|
|
290
|
+
revisionKey,
|
|
291
|
+
path: parsedDocumentCommitPath,
|
|
292
|
+
value: commit
|
|
293
|
+
});
|
|
294
|
+
return {
|
|
295
|
+
result: params.result,
|
|
296
|
+
documentId,
|
|
297
|
+
revisionKey,
|
|
298
|
+
commit
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
async function readParsedDocumentCommit(params) {
|
|
302
|
+
const object = await params.storage.readObject({
|
|
303
|
+
documentId: params.documentId,
|
|
304
|
+
revisionKey: params.revisionKey,
|
|
305
|
+
path: parsedDocumentCommitPath
|
|
306
|
+
});
|
|
307
|
+
if (!object) {
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
const commit = readJsonObject(object);
|
|
311
|
+
return commit.revisionKey === params.revisionKey && commit.documentId === params.documentId ? commit : null;
|
|
312
|
+
}
|
|
313
|
+
function readJsonObject(object) {
|
|
314
|
+
return JSON.parse(Buffer.from(object.body).toString("utf8"));
|
|
315
|
+
}
|
|
316
|
+
async function* collectResultLayoutObjects(result) {
|
|
317
|
+
const storedPaths = /* @__PURE__ */ new Set();
|
|
318
|
+
let zip;
|
|
319
|
+
try {
|
|
320
|
+
zip = await import_jszip3.default.loadAsync(result.rawZip);
|
|
321
|
+
} catch {
|
|
322
|
+
}
|
|
323
|
+
if (zip) {
|
|
324
|
+
for (const entry of Object.values(zip.files)) {
|
|
325
|
+
if (entry.dir || entry.name === "result.zip") continue;
|
|
326
|
+
const path4 = normalizeResultPath(entry.name);
|
|
327
|
+
if (isSdkMetadataPath(path4)) continue;
|
|
328
|
+
storedPaths.add(path4);
|
|
329
|
+
yield {
|
|
330
|
+
path: path4,
|
|
331
|
+
body: await entry.async("nodebuffer"),
|
|
332
|
+
contentType: inferContentTypeFromPath(path4)
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
for (const object of generateMissingResultObjects(result, storedPaths)) yield object;
|
|
337
|
+
}
|
|
338
|
+
function* generateMissingResultObjects(result, storedPaths) {
|
|
339
|
+
if (!storedPaths.has("manifest.json")) yield createJsonObject("manifest.json", result.manifest);
|
|
340
|
+
if (!storedPaths.has("chunks.json"))
|
|
341
|
+
yield createJsonObject("chunks.json", keysToSnake(serializeChunks2(result.chunks)));
|
|
342
|
+
if (!storedPaths.has("doc_nav.json") && result.docNav)
|
|
343
|
+
yield createJsonObject("doc_nav.json", result.docNav);
|
|
344
|
+
if (!storedPaths.has("full.md") && result.fullMarkdown)
|
|
345
|
+
yield createTextObject("full.md", result.fullMarkdown, markdownContentType);
|
|
346
|
+
if (!storedPaths.has("chunks_slim.json") && result.chunksSlim)
|
|
347
|
+
yield createJsonObject("chunks_slim.json", { chunks: result.chunksSlim });
|
|
348
|
+
if (!storedPaths.has("hierarchy.json") && result.hierarchy)
|
|
349
|
+
yield createJsonObject("hierarchy.json", result.hierarchy);
|
|
350
|
+
if (!storedPaths.has("toc_hierarchies.json") && result.tocHierarchies)
|
|
351
|
+
yield createJsonObject("toc_hierarchies.json", result.tocHierarchies);
|
|
352
|
+
if (!storedPaths.has("kb.csv") && result.kbCsv)
|
|
353
|
+
yield createTextObject("kb.csv", result.kbCsv, csvContentType);
|
|
354
|
+
if (!storedPaths.has("hierarchy_view.html") && result.hierarchyViewHtml)
|
|
355
|
+
yield createTextObject("hierarchy_view.html", result.hierarchyViewHtml, htmlContentType);
|
|
356
|
+
for (const chunk of result.imageChunks) {
|
|
357
|
+
const path4 = normalizeResultPath(chunk.filePath);
|
|
358
|
+
if (storedPaths.has(path4)) continue;
|
|
359
|
+
yield {
|
|
360
|
+
path: path4,
|
|
361
|
+
body: chunk.data,
|
|
362
|
+
contentType: inferContentTypeFromPath(path4),
|
|
363
|
+
metadata: { chunkId: chunk.chunkId, chunkType: chunk.type, sourcePath: chunk.filePath }
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
for (const chunk of result.tableChunks) {
|
|
367
|
+
const path4 = normalizeResultPath(chunk.filePath);
|
|
368
|
+
if (storedPaths.has(path4)) continue;
|
|
369
|
+
yield {
|
|
370
|
+
path: path4,
|
|
371
|
+
body: Buffer.from(chunk.html, "utf8"),
|
|
372
|
+
contentType: htmlContentType,
|
|
373
|
+
metadata: { chunkId: chunk.chunkId, chunkType: chunk.type, sourcePath: chunk.filePath }
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
function serializeChunks2(chunks) {
|
|
378
|
+
return {
|
|
379
|
+
chunks: chunks.map((chunk) => {
|
|
380
|
+
const rawChunk = {
|
|
381
|
+
chunkId: chunk.chunkId,
|
|
382
|
+
type: chunk.type,
|
|
383
|
+
contentSource: chunk.contentSource,
|
|
384
|
+
content: chunk.content,
|
|
385
|
+
path: chunk.path,
|
|
386
|
+
metadata: chunk.metadata
|
|
387
|
+
};
|
|
388
|
+
if (chunk.type === "image" || chunk.type === "table") {
|
|
389
|
+
return {
|
|
390
|
+
...rawChunk,
|
|
391
|
+
filePath: chunk.filePath,
|
|
392
|
+
assetUrl: chunk.assetUrl
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
return rawChunk;
|
|
396
|
+
})
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
async function writeParsedDocumentJsonObject(storage, params) {
|
|
400
|
+
await storage.writeObject({
|
|
401
|
+
documentId: params.documentId,
|
|
402
|
+
revisionKey: params.revisionKey,
|
|
403
|
+
path: params.path,
|
|
404
|
+
body: Buffer.from(JSON.stringify(params.value, null, 2), "utf8"),
|
|
405
|
+
contentType: jsonContentType
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
function createJsonObject(path4, value) {
|
|
409
|
+
return {
|
|
410
|
+
path: path4,
|
|
411
|
+
body: Buffer.from(JSON.stringify(value, null, 2), "utf8"),
|
|
412
|
+
contentType: jsonContentType
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
function createTextObject(path4, value, contentType) {
|
|
416
|
+
return {
|
|
417
|
+
path: path4,
|
|
418
|
+
body: Buffer.from(value, "utf8"),
|
|
419
|
+
contentType
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
function inferContentTypeFromPath(filePath) {
|
|
423
|
+
const lower = filePath.toLowerCase();
|
|
424
|
+
if (lower.endsWith(".json")) return jsonContentType;
|
|
425
|
+
if (lower.endsWith(".md")) return markdownContentType;
|
|
426
|
+
if (lower.endsWith(".csv")) return csvContentType;
|
|
427
|
+
if (lower.endsWith(".html") || lower.endsWith(".htm")) return htmlContentType;
|
|
428
|
+
if (lower.endsWith(".png")) return "image/png";
|
|
429
|
+
if (lower.endsWith(".jpg") || lower.endsWith(".jpeg")) return "image/jpeg";
|
|
430
|
+
if (lower.endsWith(".gif")) return "image/gif";
|
|
431
|
+
if (lower.endsWith(".webp")) return "image/webp";
|
|
432
|
+
if (lower.endsWith(".svg")) return "image/svg+xml";
|
|
433
|
+
return binaryContentType;
|
|
434
|
+
}
|
|
435
|
+
function normalizeResultPath(value) {
|
|
436
|
+
const normalized = value.replaceAll("\\", "/").replace(/^\.\/+/, "");
|
|
437
|
+
if (normalized.length === 0 || normalized.includes("\0") || normalized.startsWith("/") || normalized.split("/").some((part) => part.length === 0 || part === "." || part === "..")) {
|
|
438
|
+
throw new Error(`Invalid parsed result path: ${value}`);
|
|
439
|
+
}
|
|
440
|
+
return normalized;
|
|
441
|
+
}
|
|
442
|
+
function isSdkMetadataPath(path4) {
|
|
443
|
+
return path4 === ".knowhere-sdk" || path4.startsWith(".knowhere-sdk/");
|
|
444
|
+
}
|
|
445
|
+
var import_jszip3, parsedDocumentCommitPath, jsonContentType, markdownContentType, csvContentType, htmlContentType, binaryContentType;
|
|
446
|
+
var init_parsed_document_storage = __esm({
|
|
447
|
+
"src/storage/parsed-document-storage.ts"() {
|
|
448
|
+
"use strict";
|
|
449
|
+
import_jszip3 = __toESM(require("jszip"));
|
|
450
|
+
init_utils();
|
|
451
|
+
parsedDocumentCommitPath = ".knowhere-sdk/commit.json";
|
|
452
|
+
jsonContentType = "application/json; charset=utf-8";
|
|
453
|
+
markdownContentType = "text/markdown; charset=utf-8";
|
|
454
|
+
csvContentType = "text/csv; charset=utf-8";
|
|
455
|
+
htmlContentType = "text/html; charset=utf-8";
|
|
456
|
+
binaryContentType = "application/octet-stream";
|
|
457
|
+
}
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
// src/storage/sequential-parsed-document-archive.ts
|
|
461
|
+
var sequential_parsed_document_archive_exports = {};
|
|
462
|
+
__export(sequential_parsed_document_archive_exports, {
|
|
463
|
+
openSequentialArchive: () => openSequentialArchive
|
|
464
|
+
});
|
|
465
|
+
async function openSequentialArchive(params, identity) {
|
|
466
|
+
const response = await fetch(params.resultUrl, { signal: params.signal });
|
|
467
|
+
if (!response.ok || !response.body)
|
|
468
|
+
throw new Error(`Parsed result download failed (HTTP ${response.status}).`);
|
|
469
|
+
if (createDownloadIdentity(params.jobId, response) !== identity) {
|
|
470
|
+
await response.body.cancel();
|
|
471
|
+
throw new Error("Parsed result archive identity changed before sequential download.");
|
|
472
|
+
}
|
|
473
|
+
let directory;
|
|
474
|
+
try {
|
|
475
|
+
directory = await (0, import_promises2.mkdtemp)((0, import_path2.join)((0, import_os.tmpdir)(), "knowhere-sync-"));
|
|
476
|
+
} catch (error) {
|
|
477
|
+
await response.body.cancel();
|
|
478
|
+
throw new ParsedDocumentArchiveError(error);
|
|
479
|
+
}
|
|
480
|
+
let file;
|
|
481
|
+
try {
|
|
482
|
+
file = await (0, import_promises2.open)((0, import_path2.join)(directory, "archive.zip"), "w+");
|
|
483
|
+
} catch (error) {
|
|
484
|
+
await response.body.cancel();
|
|
485
|
+
await (0, import_promises2.rm)(directory, { recursive: true, force: true });
|
|
486
|
+
throw new ParsedDocumentArchiveError(error);
|
|
487
|
+
}
|
|
488
|
+
const input = import_stream.Readable.fromWeb(response.body);
|
|
489
|
+
const parser = (0, import_parse.default)({ forceStream: true });
|
|
490
|
+
const checksums = /* @__PURE__ */ new Map();
|
|
491
|
+
let archiveSize = 0;
|
|
492
|
+
const spool = new import_stream.Transform({
|
|
493
|
+
transform(chunk, _encoding, callback) {
|
|
494
|
+
archiveSize += chunk.length;
|
|
495
|
+
void file.writeFile(chunk).then(
|
|
496
|
+
() => {
|
|
497
|
+
callback(null, chunk);
|
|
498
|
+
},
|
|
499
|
+
(error) => {
|
|
500
|
+
callback(new ParsedDocumentArchiveError(error));
|
|
501
|
+
}
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
const completed = (0, import_promises.pipeline)(input, spool, parser, { signal: params.signal });
|
|
506
|
+
void completed.catch(() => void 0);
|
|
507
|
+
return {
|
|
508
|
+
identity,
|
|
509
|
+
downloadIdentity: identity,
|
|
510
|
+
canSkipEntries: false,
|
|
511
|
+
entries: (async function* () {
|
|
512
|
+
for await (const value of parser) {
|
|
513
|
+
const entry = value;
|
|
514
|
+
if (entry.type === "Directory" || !isSnapshotPath(entry.path)) {
|
|
515
|
+
await entry.autodrain().promise();
|
|
516
|
+
continue;
|
|
517
|
+
}
|
|
518
|
+
const path4 = normalizeResultPath(entry.path);
|
|
519
|
+
yield {
|
|
520
|
+
path: path4,
|
|
521
|
+
read: () => {
|
|
522
|
+
let checksum = 0;
|
|
523
|
+
let size = 0;
|
|
524
|
+
return import_stream.Readable.toWeb(entry).pipeThrough(
|
|
525
|
+
new TransformStream({
|
|
526
|
+
transform(chunk, controller) {
|
|
527
|
+
checksum = (0, import_zlib.crc32)(chunk, checksum);
|
|
528
|
+
size += chunk.length;
|
|
529
|
+
controller.enqueue(chunk);
|
|
530
|
+
},
|
|
531
|
+
flush() {
|
|
532
|
+
checksums.set(path4, { checksum, size });
|
|
533
|
+
}
|
|
534
|
+
})
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
await completed;
|
|
540
|
+
const reader = new import_zip.ZipReader(new DiskArchiveReader(file, archiveSize), {
|
|
541
|
+
useWebWorkers: false
|
|
542
|
+
});
|
|
543
|
+
try {
|
|
544
|
+
const files = (await reader.getEntries()).filter(
|
|
545
|
+
(entry) => !entry.directory && isSnapshotPath(entry.filename)
|
|
546
|
+
);
|
|
547
|
+
if (files.length !== checksums.size)
|
|
548
|
+
throw new Error("Parsed result ZIP directory does not match sequential entries.");
|
|
549
|
+
for (const entry of files) {
|
|
550
|
+
const actual = checksums.get(normalizeResultPath(entry.filename));
|
|
551
|
+
if (!actual || actual.checksum !== entry.signature || actual.size !== entry.uncompressedSize)
|
|
552
|
+
throw new Error(`Invalid parsed result ZIP checksum or size: ${entry.filename}`);
|
|
553
|
+
}
|
|
554
|
+
} finally {
|
|
555
|
+
await reader.close();
|
|
556
|
+
}
|
|
557
|
+
})(),
|
|
558
|
+
close: async () => {
|
|
559
|
+
input.destroy();
|
|
560
|
+
spool.destroy();
|
|
561
|
+
parser.destroy();
|
|
562
|
+
await completed.catch(() => void 0);
|
|
563
|
+
try {
|
|
564
|
+
await file.close();
|
|
565
|
+
} finally {
|
|
566
|
+
await (0, import_promises2.rm)(directory, { recursive: true, force: true });
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
var import_stream, import_promises, import_promises2, import_os, import_path2, import_zlib, import_zip, import_parse, DiskArchiveReader;
|
|
572
|
+
var init_sequential_parsed_document_archive = __esm({
|
|
573
|
+
"src/storage/sequential-parsed-document-archive.ts"() {
|
|
574
|
+
"use strict";
|
|
575
|
+
import_stream = require("stream");
|
|
576
|
+
import_promises = require("stream/promises");
|
|
577
|
+
import_promises2 = require("fs/promises");
|
|
578
|
+
import_os = require("os");
|
|
579
|
+
import_path2 = require("path");
|
|
580
|
+
import_zlib = require("zlib");
|
|
581
|
+
import_zip = require("@zip.js/zip.js");
|
|
582
|
+
import_parse = __toESM(require("unzipper/lib/parse.js"));
|
|
583
|
+
init_parsed_document_archive_error();
|
|
584
|
+
init_parsed_document_storage();
|
|
585
|
+
init_streamed_parsed_document_sync();
|
|
586
|
+
DiskArchiveReader = class extends import_zip.Reader {
|
|
587
|
+
constructor(file, size) {
|
|
588
|
+
super(file);
|
|
589
|
+
this.file = file;
|
|
590
|
+
this.size = size;
|
|
591
|
+
}
|
|
592
|
+
file;
|
|
593
|
+
async readUint8Array(index, length) {
|
|
594
|
+
const body = new Uint8Array(length);
|
|
595
|
+
const { bytesRead } = await this.file.read(body, 0, length, index);
|
|
596
|
+
if (bytesRead !== length) throw new Error("Truncated parsed result ZIP.");
|
|
597
|
+
return body;
|
|
598
|
+
}
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
// src/storage/streamed-parsed-document-sync.ts
|
|
604
|
+
async function syncRemoteResultArchive(params) {
|
|
605
|
+
params.signal?.throwIfAborted();
|
|
606
|
+
const startedAt = Date.now();
|
|
607
|
+
const maxEntries = Math.max(1, params.limits?.maxEntriesPerSync ?? 100);
|
|
608
|
+
const deadlineMs = Math.max(1, params.limits?.archiveSyncDeadlineMs ?? 12e4);
|
|
609
|
+
const previous = await params.storage.readSyncProgress(params);
|
|
610
|
+
const source = await openArchive(params);
|
|
611
|
+
const entryHashes = [];
|
|
612
|
+
const paths = /* @__PURE__ */ new Set();
|
|
613
|
+
let entryIndex = 0;
|
|
614
|
+
let copiedEntries = 0;
|
|
615
|
+
const nextEntry = previous?.status === "completed" ? 0 : previous?.nextArchiveEntry ?? 0;
|
|
616
|
+
try {
|
|
617
|
+
if (previous?.archiveIdentity && previous.archiveIdentity !== source.identity) {
|
|
618
|
+
throw new Error("Parsed result archive identity changed; start a new revision.");
|
|
619
|
+
}
|
|
620
|
+
if (previous?.pinnedRevisionKey && previous.pinnedRevisionKey !== params.revisionKey) {
|
|
621
|
+
throw new Error("Parsed result revision changed while resuming archive sync.");
|
|
622
|
+
}
|
|
623
|
+
for await (const entry of source.entries) {
|
|
624
|
+
params.signal?.throwIfAborted();
|
|
625
|
+
if (paths.has(entry.path)) throw new Error(`Duplicate parsed result path: ${entry.path}`);
|
|
626
|
+
paths.add(entry.path);
|
|
627
|
+
if (entryIndex >= nextEntry && copiedEntries > 0 && (copiedEntries >= maxEntries || Date.now() - startedAt >= deadlineMs)) {
|
|
628
|
+
return { documentId: params.documentId, revisionKey: params.revisionKey, completed: false };
|
|
629
|
+
}
|
|
630
|
+
if (entryIndex < nextEntry && source.canSkipEntries) {
|
|
631
|
+
const previousHash = previous?.archiveEntryHashes?.[entryIndex];
|
|
632
|
+
if (!previousHash) throw new Error("Parsed archive checkpoint is missing an entry hash.");
|
|
633
|
+
entryHashes.push(previousHash);
|
|
634
|
+
entryIndex += 1;
|
|
635
|
+
continue;
|
|
636
|
+
}
|
|
637
|
+
const hash = (0, import_crypto.createHash)("sha256");
|
|
638
|
+
const body = entry.read().pipeThrough(
|
|
639
|
+
new TransformStream({
|
|
640
|
+
transform(chunk, controller) {
|
|
641
|
+
params.signal?.throwIfAborted();
|
|
642
|
+
hash.update(chunk);
|
|
643
|
+
controller.enqueue(chunk);
|
|
644
|
+
}
|
|
645
|
+
})
|
|
646
|
+
);
|
|
647
|
+
if (entryIndex < nextEntry) {
|
|
648
|
+
await body.pipeTo(new WritableStream(), { signal: params.signal });
|
|
649
|
+
} else {
|
|
650
|
+
await writeStream(params.storage, {
|
|
651
|
+
documentId: params.documentId,
|
|
652
|
+
revisionKey: params.revisionKey,
|
|
653
|
+
path: entry.path,
|
|
654
|
+
body,
|
|
655
|
+
contentType: inferContentTypeFromPath(entry.path),
|
|
656
|
+
signal: params.signal
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
const entryHash = (0, import_crypto.createHash)("sha256").update(entry.path).update(hash.digest()).digest("hex");
|
|
660
|
+
if (entryIndex < nextEntry && previous?.archiveEntryHashes?.[entryIndex] !== entryHash) {
|
|
661
|
+
throw new Error("Parsed result archive entry changed while resuming.");
|
|
662
|
+
}
|
|
663
|
+
entryHashes.push(entryHash);
|
|
664
|
+
entryIndex += 1;
|
|
665
|
+
if (entryIndex <= nextEntry) continue;
|
|
666
|
+
copiedEntries += 1;
|
|
667
|
+
await params.storage.writeSyncProgress({
|
|
668
|
+
documentId: params.documentId,
|
|
669
|
+
revisionKey: params.revisionKey,
|
|
670
|
+
pinnedRevisionKey: params.revisionKey,
|
|
671
|
+
archiveIdentity: source.identity,
|
|
672
|
+
archiveEntryHashes: [...entryHashes],
|
|
673
|
+
nextArchiveEntry: entryIndex,
|
|
674
|
+
status: "running",
|
|
675
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
await validateRequiredObjects(params, paths);
|
|
679
|
+
await params.verifyRevision?.();
|
|
680
|
+
params.signal?.throwIfAborted();
|
|
681
|
+
const commit = {
|
|
682
|
+
version: 1,
|
|
683
|
+
documentId: params.documentId,
|
|
684
|
+
revisionKey: params.revisionKey,
|
|
685
|
+
source: "resultZip",
|
|
686
|
+
committedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
687
|
+
};
|
|
688
|
+
await params.storage.writeObject({
|
|
689
|
+
documentId: params.documentId,
|
|
690
|
+
revisionKey: params.revisionKey,
|
|
691
|
+
path: parsedDocumentCommitPath,
|
|
692
|
+
body: Buffer.from(JSON.stringify(commit, null, 2)),
|
|
693
|
+
contentType: "application/json; charset=utf-8"
|
|
694
|
+
});
|
|
695
|
+
await params.storage.writeSyncProgress({
|
|
696
|
+
documentId: params.documentId,
|
|
697
|
+
revisionKey: params.revisionKey,
|
|
698
|
+
pinnedRevisionKey: params.revisionKey,
|
|
699
|
+
archiveIdentity: source.identity,
|
|
700
|
+
archiveEntryHashes: entryHashes,
|
|
701
|
+
nextArchiveEntry: entryIndex,
|
|
702
|
+
status: "completed",
|
|
703
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
704
|
+
});
|
|
705
|
+
if (params.retainResultArchive) {
|
|
706
|
+
try {
|
|
707
|
+
await retainArchive(params, source.downloadIdentity);
|
|
708
|
+
} catch {
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
return {
|
|
712
|
+
documentId: params.documentId,
|
|
713
|
+
revisionKey: params.revisionKey,
|
|
714
|
+
completed: true,
|
|
715
|
+
commit
|
|
716
|
+
};
|
|
717
|
+
} finally {
|
|
718
|
+
await source.close();
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
async function openArchive(params) {
|
|
722
|
+
const probe = await fetch(params.resultUrl, {
|
|
723
|
+
headers: { Range: "bytes=0-0" },
|
|
724
|
+
signal: params.signal
|
|
725
|
+
});
|
|
726
|
+
if (!probe.ok) {
|
|
727
|
+
await probe.body?.cancel();
|
|
728
|
+
throw new Error(`Parsed result download failed (HTTP ${probe.status}).`);
|
|
729
|
+
}
|
|
730
|
+
const identity = createDownloadIdentity(params.jobId, probe);
|
|
731
|
+
const supportsRange = probe.status === 206 && probe.headers.has("content-range");
|
|
732
|
+
await probe.body?.cancel();
|
|
733
|
+
if (!supportsRange) {
|
|
734
|
+
const { openSequentialArchive: openSequentialArchive2 } = await Promise.resolve().then(() => (init_sequential_parsed_document_archive(), sequential_parsed_document_archive_exports));
|
|
735
|
+
return openSequentialArchive2(params, identity);
|
|
736
|
+
}
|
|
737
|
+
const options = {
|
|
738
|
+
forceRangeRequests: true,
|
|
739
|
+
preventHeadRequest: true,
|
|
740
|
+
checkResourceChanges: true,
|
|
741
|
+
fetch: async (input, init) => {
|
|
742
|
+
const response = await fetch(input, { ...init, signal: params.signal });
|
|
743
|
+
if (response.status !== 206) {
|
|
744
|
+
await response.body?.cancel();
|
|
745
|
+
throw new Error(`Parsed result Range request failed (HTTP ${response.status}).`);
|
|
746
|
+
}
|
|
747
|
+
return response;
|
|
748
|
+
}
|
|
749
|
+
};
|
|
750
|
+
const reader = new import_zip2.ZipReader(new import_zip2.HttpRangeReader(params.resultUrl, options), {
|
|
751
|
+
useWebWorkers: false,
|
|
752
|
+
checkCrc32: true
|
|
753
|
+
});
|
|
754
|
+
try {
|
|
755
|
+
const entries = await reader.getEntries();
|
|
756
|
+
const files = entries.filter(
|
|
757
|
+
(entry) => !entry.directory && isSnapshotPath(entry.filename)
|
|
758
|
+
);
|
|
759
|
+
const archiveIdentity = (0, import_crypto.createHash)("sha256").update(identity).update(
|
|
760
|
+
JSON.stringify(
|
|
761
|
+
files.map((entry) => [entry.filename, entry.uncompressedSize, entry.signature])
|
|
762
|
+
)
|
|
763
|
+
).digest("hex");
|
|
764
|
+
return {
|
|
765
|
+
identity: archiveIdentity,
|
|
766
|
+
downloadIdentity: identity,
|
|
767
|
+
canSkipEntries: true,
|
|
768
|
+
entries: (function* () {
|
|
769
|
+
for (const entry of files)
|
|
770
|
+
yield {
|
|
771
|
+
path: normalizeResultPath(entry.filename),
|
|
772
|
+
read: () => readRangeEntry(entry, params.signal)
|
|
773
|
+
};
|
|
774
|
+
})(),
|
|
775
|
+
close: async () => {
|
|
776
|
+
await reader.close();
|
|
777
|
+
}
|
|
778
|
+
};
|
|
779
|
+
} catch (error) {
|
|
780
|
+
await reader.close();
|
|
781
|
+
throw error;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
function readRangeEntry(entry, signal) {
|
|
785
|
+
const stream = new TransformStream();
|
|
786
|
+
void entry.getData(stream.writable, { signal, checkCrc32: true, useWebWorkers: false }).catch(async (error) => {
|
|
787
|
+
try {
|
|
788
|
+
await stream.writable.abort(error);
|
|
789
|
+
} catch {
|
|
790
|
+
}
|
|
791
|
+
});
|
|
792
|
+
return stream.readable;
|
|
793
|
+
}
|
|
794
|
+
async function writeStream(storage, params) {
|
|
795
|
+
if (storage.writeObjectStream) {
|
|
796
|
+
try {
|
|
797
|
+
await storage.writeObjectStream(params);
|
|
798
|
+
} catch (error) {
|
|
799
|
+
await params.body.cancel(error).catch(() => void 0);
|
|
800
|
+
throw error;
|
|
801
|
+
}
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
const parts = [];
|
|
805
|
+
for await (const part of params.body) {
|
|
806
|
+
params.signal?.throwIfAborted();
|
|
807
|
+
parts.push(part);
|
|
808
|
+
}
|
|
809
|
+
await storage.writeObject({ ...params, body: Buffer.concat(parts) });
|
|
810
|
+
}
|
|
811
|
+
async function validateRequiredObjects(params, paths) {
|
|
812
|
+
const required = /* @__PURE__ */ new Set(["manifest.json", "chunks.json"]);
|
|
813
|
+
for (const path4 of required)
|
|
814
|
+
if (!paths.has(path4)) throw new Error(`Required parsed result file missing: ${path4}`);
|
|
815
|
+
const manifestObject = await params.storage.readObject({ ...params, path: "manifest.json" });
|
|
816
|
+
const chunksObject = await params.storage.readObject({ ...params, path: "chunks.json" });
|
|
817
|
+
if (!manifestObject || !chunksObject)
|
|
818
|
+
throw new Error("Required parsed result manifest.json or chunks.json was not persisted.");
|
|
819
|
+
const manifest = JSON.parse(Buffer.from(manifestObject.body).toString("utf8"));
|
|
820
|
+
const payload = JSON.parse(Buffer.from(chunksObject.body).toString("utf8"));
|
|
821
|
+
if (!isRecord2(manifest)) throw new Error("Invalid parsed result manifest.json.");
|
|
822
|
+
const manifestJobId = manifest.job_id ?? manifest.jobId;
|
|
823
|
+
if (manifestJobId !== params.jobId)
|
|
824
|
+
throw new Error("Parsed result manifest job identity differs from the pinned job.");
|
|
825
|
+
const chunks = Array.isArray(payload) ? payload : isRecord2(payload) ? payload.chunks : void 0;
|
|
826
|
+
if (!Array.isArray(chunks)) throw new Error("Invalid parsed result chunks.json.");
|
|
827
|
+
if (isRecord2(manifest.files)) {
|
|
828
|
+
for (const path4 of Object.values(manifest.files))
|
|
829
|
+
if (typeof path4 === "string") required.add(normalizeResultPath(path4));
|
|
830
|
+
}
|
|
831
|
+
for (const chunk of chunks) {
|
|
832
|
+
if (!isRecord2(chunk)) throw new Error("Invalid parsed result chunk.");
|
|
833
|
+
const metadata = chunk.metadata;
|
|
834
|
+
const chunkType = chunk.type ?? chunk.chunk_type ?? chunk.chunkType;
|
|
835
|
+
const filePath = chunk.file_path ?? chunk.filePath ?? (isRecord2(metadata) ? metadata.file_path ?? metadata.filePath : void 0) ?? (chunkType === "image" || chunkType === "table" ? chunk.path : void 0);
|
|
836
|
+
if (typeof filePath === "string") required.add(normalizeResultPath(filePath));
|
|
837
|
+
if (!isRecord2(metadata)) continue;
|
|
838
|
+
const pageAssets = metadata.page_assets ?? metadata.pageAssets;
|
|
839
|
+
if (!Array.isArray(pageAssets)) continue;
|
|
840
|
+
for (const asset of pageAssets)
|
|
841
|
+
if (isRecord2(asset)) {
|
|
842
|
+
const ref = asset.artifact_ref ?? asset.artifactRef;
|
|
843
|
+
if (typeof ref === "string") required.add(normalizeResultPath(ref));
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
for (const path4 of required)
|
|
847
|
+
if (!paths.has(path4)) throw new Error(`Required parsed result file missing: ${path4}`);
|
|
848
|
+
}
|
|
849
|
+
async function retainArchive(params, expectedIdentity) {
|
|
850
|
+
const response = await fetch(params.resultUrl, { signal: params.signal });
|
|
851
|
+
if (!response.ok || !response.body)
|
|
852
|
+
throw new Error(`Optional archive download failed (HTTP ${response.status}).`);
|
|
853
|
+
if (createDownloadIdentity(params.jobId, response) !== expectedIdentity) {
|
|
854
|
+
await response.body.cancel();
|
|
855
|
+
throw new Error("Optional result archive identity changed.");
|
|
856
|
+
}
|
|
857
|
+
await writeStream(params.storage, {
|
|
858
|
+
documentId: params.documentId,
|
|
859
|
+
revisionKey: params.revisionKey,
|
|
860
|
+
path: "result.zip",
|
|
861
|
+
body: response.body,
|
|
862
|
+
contentType: "application/zip",
|
|
863
|
+
signal: params.signal
|
|
864
|
+
});
|
|
865
|
+
}
|
|
866
|
+
function isSnapshotPath(path4) {
|
|
867
|
+
const normalized = normalizeResultPath(path4.replace(/\/$/, ""));
|
|
868
|
+
return normalized !== "result.zip" && normalized !== ".knowhere-sdk" && !normalized.startsWith(".knowhere-sdk/");
|
|
869
|
+
}
|
|
870
|
+
function isRecord2(value) {
|
|
871
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
872
|
+
}
|
|
873
|
+
function createDownloadIdentity(jobId, response) {
|
|
874
|
+
return (0, import_crypto.createHash)("sha256").update(
|
|
875
|
+
JSON.stringify([
|
|
876
|
+
jobId,
|
|
877
|
+
response.headers.get("etag"),
|
|
878
|
+
response.headers.get("last-modified"),
|
|
879
|
+
response.headers.get("content-range")?.split("/").at(-1) ?? response.headers.get("content-length")
|
|
880
|
+
])
|
|
881
|
+
).digest("hex");
|
|
882
|
+
}
|
|
883
|
+
var import_crypto, import_zip2;
|
|
884
|
+
var init_streamed_parsed_document_sync = __esm({
|
|
885
|
+
"src/storage/streamed-parsed-document-sync.ts"() {
|
|
886
|
+
"use strict";
|
|
887
|
+
import_crypto = require("crypto");
|
|
888
|
+
import_zip2 = require("@zip.js/zip.js");
|
|
889
|
+
init_parsed_document_storage();
|
|
890
|
+
}
|
|
891
|
+
});
|
|
29
892
|
|
|
30
893
|
// src/index.ts
|
|
31
894
|
var index_exports = {};
|
|
@@ -49,6 +912,7 @@ __export(index_exports, {
|
|
|
49
912
|
NODE_SDK_DOCUMENT_METADATA_DEFAULTS: () => NODE_SDK_DOCUMENT_METADATA_DEFAULTS,
|
|
50
913
|
NetworkError: () => NetworkError,
|
|
51
914
|
NotFoundError: () => NotFoundError,
|
|
915
|
+
ParsedDocumentArchiveError: () => ParsedDocumentArchiveError,
|
|
52
916
|
PaymentRequiredError: () => PaymentRequiredError,
|
|
53
917
|
PermissionDeniedError: () => PermissionDeniedError,
|
|
54
918
|
PollingTimeoutError: () => PollingTimeoutError,
|
|
@@ -66,7 +930,7 @@ __export(index_exports, {
|
|
|
66
930
|
module.exports = __toCommonJS(index_exports);
|
|
67
931
|
|
|
68
932
|
// src/client.ts
|
|
69
|
-
var
|
|
933
|
+
var import_path4 = __toESM(require("path"));
|
|
70
934
|
|
|
71
935
|
// src/lib/http-client.ts
|
|
72
936
|
var import_axios = __toESM(require("axios"));
|
|
@@ -74,80 +938,14 @@ var import_axios = __toESM(require("axios"));
|
|
|
74
938
|
// src/version.ts
|
|
75
939
|
var VERSION = "2.1.3";
|
|
76
940
|
|
|
77
|
-
// src/
|
|
78
|
-
|
|
79
|
-
var DEFAULT_TIMEOUT = 6e4;
|
|
80
|
-
var DEFAULT_MAX_RETRIES = 5;
|
|
81
|
-
var DEFAULT_POLL_INTERVAL = 1e4;
|
|
82
|
-
var MAX_POLL_INTERVAL = 3e4;
|
|
83
|
-
var DEFAULT_POLL_TIMEOUT = 18e5;
|
|
84
|
-
var POLL_INTERVAL_INCREASE_THRESHOLD = 6e4;
|
|
85
|
-
var POLL_INTERVAL_MULTIPLIER = 1.2;
|
|
86
|
-
var INITIAL_RETRY_DELAY = 500;
|
|
87
|
-
var MAX_RETRY_DELAY = 3e4;
|
|
88
|
-
var RETRY_DELAY_BASE = 2;
|
|
89
|
-
var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([409, 429, 502, 503, 504]);
|
|
90
|
-
var TERMINAL_JOB_STATUSES = /* @__PURE__ */ new Set(["done", "failed"]);
|
|
91
|
-
var ENV = {
|
|
92
|
-
API_KEY: "KNOWHERE_API_KEY",
|
|
93
|
-
BASE_URL: "KNOWHERE_BASE_URL",
|
|
94
|
-
LOG_LEVEL: "KNOWHERE_LOG_LEVEL"
|
|
95
|
-
};
|
|
941
|
+
// src/lib/http-client.ts
|
|
942
|
+
init_constants();
|
|
96
943
|
|
|
97
|
-
// src/errors/
|
|
98
|
-
|
|
99
|
-
constructor(message) {
|
|
100
|
-
super(message);
|
|
101
|
-
this.name = "KnowhereError";
|
|
102
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
var NetworkError = class extends KnowhereError {
|
|
106
|
-
constructor(message, cause) {
|
|
107
|
-
super(message);
|
|
108
|
-
this.cause = cause;
|
|
109
|
-
this.name = "NetworkError";
|
|
110
|
-
}
|
|
111
|
-
cause;
|
|
112
|
-
};
|
|
113
|
-
var TimeoutError = class extends NetworkError {
|
|
114
|
-
constructor(message = "Request timed out") {
|
|
115
|
-
super(message);
|
|
116
|
-
this.name = "TimeoutError";
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
var PollingTimeoutError = class extends KnowhereError {
|
|
120
|
-
constructor(message = "Polling timed out", elapsedMs) {
|
|
121
|
-
super(message);
|
|
122
|
-
this.elapsedMs = elapsedMs;
|
|
123
|
-
this.name = "PollingTimeoutError";
|
|
124
|
-
}
|
|
125
|
-
elapsedMs;
|
|
126
|
-
};
|
|
127
|
-
var ChecksumError = class extends KnowhereError {
|
|
128
|
-
constructor(message = "Checksum verification failed", expected, actual) {
|
|
129
|
-
super(message);
|
|
130
|
-
this.expected = expected;
|
|
131
|
-
this.actual = actual;
|
|
132
|
-
this.name = "ChecksumError";
|
|
133
|
-
}
|
|
134
|
-
expected;
|
|
135
|
-
actual;
|
|
136
|
-
};
|
|
137
|
-
var ValidationError = class extends KnowhereError {
|
|
138
|
-
constructor(message) {
|
|
139
|
-
super(message);
|
|
140
|
-
this.name = "ValidationError";
|
|
141
|
-
}
|
|
142
|
-
};
|
|
143
|
-
var InvalidStateError = class extends KnowhereError {
|
|
144
|
-
constructor(message) {
|
|
145
|
-
super(message);
|
|
146
|
-
this.name = "InvalidStateError";
|
|
147
|
-
}
|
|
148
|
-
};
|
|
944
|
+
// src/errors/index.ts
|
|
945
|
+
init_base();
|
|
149
946
|
|
|
150
947
|
// src/errors/api-errors.ts
|
|
948
|
+
init_base();
|
|
151
949
|
var APIError = class extends KnowhereError {
|
|
152
950
|
constructor(message, statusCode, code, requestId, details, body) {
|
|
153
951
|
super(message);
|
|
@@ -234,162 +1032,48 @@ function createAPIError(statusCode, message, code, requestId, details, body, ret
|
|
|
234
1032
|
return new AuthenticationError(message, code, requestId, details, body);
|
|
235
1033
|
case 402:
|
|
236
1034
|
return new PaymentRequiredError(message, code, requestId, details, body);
|
|
237
|
-
case 403:
|
|
238
|
-
return new PermissionDeniedError(message, code, requestId, details, body);
|
|
239
|
-
case 404:
|
|
240
|
-
return new NotFoundError(message, code, requestId, details, body);
|
|
241
|
-
case 409:
|
|
242
|
-
return new ConflictError(message, code, requestId, details, body);
|
|
243
|
-
case 429:
|
|
244
|
-
return new RateLimitError(message, code, requestId, details, body, retryAfter);
|
|
245
|
-
case 500:
|
|
246
|
-
return new InternalServerError(message, code, requestId, details, body);
|
|
247
|
-
case 502:
|
|
248
|
-
case 503:
|
|
249
|
-
return new ServiceUnavailableError(message, statusCode, code, requestId, details, body);
|
|
250
|
-
case 504:
|
|
251
|
-
return new GatewayTimeoutError(message, code, requestId, details, body);
|
|
252
|
-
default:
|
|
253
|
-
return new APIError(message, statusCode, code, requestId, details, body);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// src/errors/job-errors.ts
|
|
258
|
-
var JobFailedError = class extends KnowhereError {
|
|
259
|
-
constructor(message, code, jobResult) {
|
|
260
|
-
super(message);
|
|
261
|
-
this.code = code;
|
|
262
|
-
this.jobResult = jobResult;
|
|
263
|
-
this.name = "JobFailedError";
|
|
264
|
-
}
|
|
265
|
-
code;
|
|
266
|
-
jobResult;
|
|
267
|
-
};
|
|
268
|
-
|
|
269
|
-
// src/lib/utils.ts
|
|
270
|
-
function sleep(ms) {
|
|
271
|
-
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
272
|
-
}
|
|
273
|
-
function snakeToCamel(str) {
|
|
274
|
-
return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
275
|
-
}
|
|
276
|
-
function camelToSnake(str) {
|
|
277
|
-
return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
|
278
|
-
}
|
|
279
|
-
function keysToCamel(obj) {
|
|
280
|
-
if (obj === null || obj === void 0) {
|
|
281
|
-
return obj;
|
|
282
|
-
}
|
|
283
|
-
if (Array.isArray(obj)) {
|
|
284
|
-
return obj.map((item) => keysToCamel(item));
|
|
285
|
-
}
|
|
286
|
-
if (typeof obj === "object" && obj.constructor === Object) {
|
|
287
|
-
const result = {};
|
|
288
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
289
|
-
result[snakeToCamel(key)] = keysToCamel(value);
|
|
290
|
-
}
|
|
291
|
-
return result;
|
|
292
|
-
}
|
|
293
|
-
return obj;
|
|
294
|
-
}
|
|
295
|
-
function keysToSnake(obj) {
|
|
296
|
-
if (obj === null || obj === void 0) {
|
|
297
|
-
return obj;
|
|
298
|
-
}
|
|
299
|
-
if (Array.isArray(obj)) {
|
|
300
|
-
return obj.map((item) => keysToSnake(item));
|
|
301
|
-
}
|
|
302
|
-
if (typeof obj === "object" && obj.constructor === Object) {
|
|
303
|
-
const result = {};
|
|
304
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
305
|
-
result[camelToSnake(key)] = keysToSnake(value);
|
|
306
|
-
}
|
|
307
|
-
return result;
|
|
308
|
-
}
|
|
309
|
-
return obj;
|
|
310
|
-
}
|
|
311
|
-
function parseDates(obj) {
|
|
312
|
-
if (obj === null || obj === void 0) {
|
|
313
|
-
return obj;
|
|
314
|
-
}
|
|
315
|
-
if (Array.isArray(obj)) {
|
|
316
|
-
return obj.map((item) => parseDates(item));
|
|
317
|
-
}
|
|
318
|
-
if (typeof obj === "object" && obj.constructor === Object) {
|
|
319
|
-
const result = {};
|
|
320
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
321
|
-
if ((key.endsWith("At") || key.endsWith("Date")) && typeof value === "string" && /^\d{4}-\d{2}-\d{2}T/.test(value)) {
|
|
322
|
-
result[key] = new Date(value);
|
|
323
|
-
} else {
|
|
324
|
-
result[key] = parseDates(value);
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
return result;
|
|
328
|
-
}
|
|
329
|
-
return obj;
|
|
330
|
-
}
|
|
331
|
-
function isTerminalStatus(status) {
|
|
332
|
-
return TERMINAL_JOB_STATUSES.has(status);
|
|
333
|
-
}
|
|
334
|
-
function enrichJobResult(jobResult) {
|
|
335
|
-
const computedProperties = {};
|
|
336
|
-
if (!Object.getOwnPropertyDescriptor(jobResult, "isTerminal")) {
|
|
337
|
-
computedProperties.isTerminal = {
|
|
338
|
-
get() {
|
|
339
|
-
return isTerminalStatus(this.status);
|
|
340
|
-
},
|
|
341
|
-
enumerable: true,
|
|
342
|
-
configurable: true
|
|
343
|
-
};
|
|
344
|
-
}
|
|
345
|
-
if (!Object.getOwnPropertyDescriptor(jobResult, "isDone")) {
|
|
346
|
-
computedProperties.isDone = {
|
|
347
|
-
get() {
|
|
348
|
-
return this.status === "done";
|
|
349
|
-
},
|
|
350
|
-
enumerable: true,
|
|
351
|
-
configurable: true
|
|
352
|
-
};
|
|
353
|
-
}
|
|
354
|
-
if (!Object.getOwnPropertyDescriptor(jobResult, "isFailed")) {
|
|
355
|
-
computedProperties.isFailed = {
|
|
356
|
-
get() {
|
|
357
|
-
return this.status === "failed";
|
|
358
|
-
},
|
|
359
|
-
enumerable: true,
|
|
360
|
-
configurable: true
|
|
361
|
-
};
|
|
362
|
-
}
|
|
363
|
-
if (Object.keys(computedProperties).length > 0) {
|
|
364
|
-
Object.defineProperties(jobResult, computedProperties);
|
|
1035
|
+
case 403:
|
|
1036
|
+
return new PermissionDeniedError(message, code, requestId, details, body);
|
|
1037
|
+
case 404:
|
|
1038
|
+
return new NotFoundError(message, code, requestId, details, body);
|
|
1039
|
+
case 409:
|
|
1040
|
+
return new ConflictError(message, code, requestId, details, body);
|
|
1041
|
+
case 429:
|
|
1042
|
+
return new RateLimitError(message, code, requestId, details, body, retryAfter);
|
|
1043
|
+
case 500:
|
|
1044
|
+
return new InternalServerError(message, code, requestId, details, body);
|
|
1045
|
+
case 502:
|
|
1046
|
+
case 503:
|
|
1047
|
+
return new ServiceUnavailableError(message, statusCode, code, requestId, details, body);
|
|
1048
|
+
case 504:
|
|
1049
|
+
return new GatewayTimeoutError(message, code, requestId, details, body);
|
|
1050
|
+
default:
|
|
1051
|
+
return new APIError(message, statusCode, code, requestId, details, body);
|
|
365
1052
|
}
|
|
366
|
-
return jobResult;
|
|
367
1053
|
}
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
1054
|
+
|
|
1055
|
+
// src/errors/job-errors.ts
|
|
1056
|
+
init_base();
|
|
1057
|
+
var JobFailedError = class extends KnowhereError {
|
|
1058
|
+
constructor(message, code, jobResult) {
|
|
1059
|
+
super(message);
|
|
1060
|
+
this.code = code;
|
|
1061
|
+
this.jobResult = jobResult;
|
|
1062
|
+
this.name = "JobFailedError";
|
|
374
1063
|
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
const match = filename.match(/\.([^.]+)$/);
|
|
385
|
-
return match ? match[1].toLowerCase() : "";
|
|
386
|
-
}
|
|
387
|
-
function jitter(value, percent = 0.2) {
|
|
388
|
-
const randomFactor = 1 + (Math.random() * 2 - 1) * percent;
|
|
389
|
-
return Math.round(value * randomFactor);
|
|
390
|
-
}
|
|
1064
|
+
code;
|
|
1065
|
+
jobResult;
|
|
1066
|
+
};
|
|
1067
|
+
|
|
1068
|
+
// src/errors/index.ts
|
|
1069
|
+
init_parsed_document_archive_error();
|
|
1070
|
+
|
|
1071
|
+
// src/lib/http-client.ts
|
|
1072
|
+
init_utils();
|
|
391
1073
|
|
|
392
1074
|
// src/lib/retry.ts
|
|
1075
|
+
init_constants();
|
|
1076
|
+
init_utils();
|
|
393
1077
|
function getErrorCode(error) {
|
|
394
1078
|
const errorWithResponse = error;
|
|
395
1079
|
return errorWithResponse?.response?.data?.error?.code ?? errorWithResponse?.response?.data?.code ?? errorWithResponse?.code;
|
|
@@ -815,6 +1499,8 @@ function isReadStream(obj) {
|
|
|
815
1499
|
}
|
|
816
1500
|
|
|
817
1501
|
// src/lib/polling.ts
|
|
1502
|
+
init_constants();
|
|
1503
|
+
init_utils();
|
|
818
1504
|
async function pollJobStatus(httpClient, jobId, options) {
|
|
819
1505
|
const pollInterval = options?.pollInterval ?? DEFAULT_POLL_INTERVAL;
|
|
820
1506
|
const pollTimeout = options?.pollTimeout ?? DEFAULT_POLL_TIMEOUT;
|
|
@@ -865,6 +1551,7 @@ async function pollJobStatus(httpClient, jobId, options) {
|
|
|
865
1551
|
var import_jszip = __toESM(require("jszip"));
|
|
866
1552
|
var import_fs2 = require("fs");
|
|
867
1553
|
var import_path = require("path");
|
|
1554
|
+
init_utils();
|
|
868
1555
|
async function parseResult(httpClient, resultUrl, options) {
|
|
869
1556
|
const zipBuffer = await httpClient.download(resultUrl);
|
|
870
1557
|
if (options?.verifyChecksum !== false) {
|
|
@@ -1367,6 +2054,7 @@ function isMissingFileError(error) {
|
|
|
1367
2054
|
}
|
|
1368
2055
|
|
|
1369
2056
|
// src/resources/jobs.ts
|
|
2057
|
+
init_utils();
|
|
1370
2058
|
var Jobs = class extends BaseResource {
|
|
1371
2059
|
pendingUploadJobs = /* @__PURE__ */ new Map();
|
|
1372
2060
|
/**
|
|
@@ -1607,7 +2295,7 @@ var Documents = class extends BaseResource {
|
|
|
1607
2295
|
};
|
|
1608
2296
|
|
|
1609
2297
|
// src/knowledge/knowledge.ts
|
|
1610
|
-
var
|
|
2298
|
+
var import_crypto3 = require("crypto");
|
|
1611
2299
|
|
|
1612
2300
|
// src/storage/asset-storage.ts
|
|
1613
2301
|
var import_jszip2 = __toESM(require("jszip"));
|
|
@@ -1871,220 +2559,16 @@ function isRecord(value) {
|
|
|
1871
2559
|
return typeof value === "object" && value !== null;
|
|
1872
2560
|
}
|
|
1873
2561
|
|
|
1874
|
-
// src/
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
var markdownContentType = "text/markdown; charset=utf-8";
|
|
1879
|
-
var csvContentType = "text/csv; charset=utf-8";
|
|
1880
|
-
var htmlContentType = "text/html; charset=utf-8";
|
|
1881
|
-
var binaryContentType = "application/octet-stream";
|
|
1882
|
-
async function syncParseResultToParsedDocumentStorage(params) {
|
|
1883
|
-
const documentId = params.documentId ?? params.result.documentId ?? params.result.jobId;
|
|
1884
|
-
const revisionKey = params.revisionKey ?? params.result.jobId;
|
|
1885
|
-
const objects = await collectResultLayoutObjects(params.result);
|
|
1886
|
-
for (const object of objects) {
|
|
1887
|
-
await params.storage.writeObject({
|
|
1888
|
-
documentId,
|
|
1889
|
-
revisionKey,
|
|
1890
|
-
...object
|
|
1891
|
-
});
|
|
1892
|
-
}
|
|
1893
|
-
const commit = {
|
|
1894
|
-
version: 1,
|
|
1895
|
-
documentId,
|
|
1896
|
-
revisionKey,
|
|
1897
|
-
source: params.source ?? "resultZip",
|
|
1898
|
-
committedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1899
|
-
};
|
|
1900
|
-
await writeParsedDocumentJsonObject(params.storage, {
|
|
1901
|
-
documentId,
|
|
1902
|
-
revisionKey,
|
|
1903
|
-
path: parsedDocumentCommitPath,
|
|
1904
|
-
value: commit
|
|
1905
|
-
});
|
|
1906
|
-
return {
|
|
1907
|
-
result: params.result,
|
|
1908
|
-
documentId,
|
|
1909
|
-
revisionKey,
|
|
1910
|
-
commit
|
|
1911
|
-
};
|
|
1912
|
-
}
|
|
1913
|
-
async function readParsedDocumentCommit(params) {
|
|
1914
|
-
const object = await params.storage.readObject({
|
|
1915
|
-
documentId: params.documentId,
|
|
1916
|
-
revisionKey: params.revisionKey,
|
|
1917
|
-
path: parsedDocumentCommitPath
|
|
1918
|
-
});
|
|
1919
|
-
if (!object) {
|
|
1920
|
-
return null;
|
|
1921
|
-
}
|
|
1922
|
-
const commit = readJsonObject(object);
|
|
1923
|
-
return commit.revisionKey === params.revisionKey && commit.documentId === params.documentId ? commit : null;
|
|
1924
|
-
}
|
|
1925
|
-
function readJsonObject(object) {
|
|
1926
|
-
return JSON.parse(Buffer.from(object.body).toString("utf8"));
|
|
1927
|
-
}
|
|
1928
|
-
async function collectResultLayoutObjects(result) {
|
|
1929
|
-
const objectsByPath = /* @__PURE__ */ new Map();
|
|
1930
|
-
const rawZipObjects = await collectRawZipObjects(result.rawZip);
|
|
1931
|
-
for (const object of rawZipObjects) {
|
|
1932
|
-
objectsByPath.set(object.path, object);
|
|
1933
|
-
}
|
|
1934
|
-
for (const object of collectGeneratedResultObjects(result)) {
|
|
1935
|
-
if (!objectsByPath.has(object.path)) {
|
|
1936
|
-
objectsByPath.set(object.path, object);
|
|
1937
|
-
}
|
|
1938
|
-
}
|
|
1939
|
-
return [...objectsByPath.values()].filter((object) => !isSdkMetadataPath(object.path));
|
|
1940
|
-
}
|
|
1941
|
-
async function collectRawZipObjects(rawZip) {
|
|
1942
|
-
try {
|
|
1943
|
-
const zip = await import_jszip3.default.loadAsync(rawZip);
|
|
1944
|
-
const objects = [];
|
|
1945
|
-
for (const entry of Object.values(zip.files)) {
|
|
1946
|
-
if (entry.dir || entry.name === "result.zip") {
|
|
1947
|
-
continue;
|
|
1948
|
-
}
|
|
1949
|
-
objects.push({
|
|
1950
|
-
path: normalizeResultPath(entry.name),
|
|
1951
|
-
body: new Uint8Array(await entry.async("nodebuffer")),
|
|
1952
|
-
contentType: inferContentTypeFromPath(entry.name)
|
|
1953
|
-
});
|
|
1954
|
-
}
|
|
1955
|
-
return objects;
|
|
1956
|
-
} catch {
|
|
1957
|
-
return [];
|
|
1958
|
-
}
|
|
1959
|
-
}
|
|
1960
|
-
function collectGeneratedResultObjects(result) {
|
|
1961
|
-
const objects = [
|
|
1962
|
-
createJsonObject("manifest.json", result.manifest),
|
|
1963
|
-
createJsonObject("chunks.json", keysToSnake(serializeChunks2(result.chunks)))
|
|
1964
|
-
];
|
|
1965
|
-
if (result.docNav) {
|
|
1966
|
-
objects.push(createJsonObject("doc_nav.json", result.docNav));
|
|
1967
|
-
}
|
|
1968
|
-
if (result.fullMarkdown) {
|
|
1969
|
-
objects.push(createTextObject("full.md", result.fullMarkdown, markdownContentType));
|
|
1970
|
-
}
|
|
1971
|
-
if (result.chunksSlim) {
|
|
1972
|
-
objects.push(createJsonObject("chunks_slim.json", { chunks: result.chunksSlim }));
|
|
1973
|
-
}
|
|
1974
|
-
if (result.hierarchy) {
|
|
1975
|
-
objects.push(createJsonObject("hierarchy.json", result.hierarchy));
|
|
1976
|
-
}
|
|
1977
|
-
if (result.tocHierarchies) {
|
|
1978
|
-
objects.push(createJsonObject("toc_hierarchies.json", result.tocHierarchies));
|
|
1979
|
-
}
|
|
1980
|
-
if (result.kbCsv) {
|
|
1981
|
-
objects.push(createTextObject("kb.csv", result.kbCsv, csvContentType));
|
|
1982
|
-
}
|
|
1983
|
-
if (result.hierarchyViewHtml) {
|
|
1984
|
-
objects.push(
|
|
1985
|
-
createTextObject("hierarchy_view.html", result.hierarchyViewHtml, htmlContentType)
|
|
1986
|
-
);
|
|
1987
|
-
}
|
|
1988
|
-
for (const chunk of result.imageChunks) {
|
|
1989
|
-
objects.push({
|
|
1990
|
-
path: normalizeResultPath(chunk.filePath),
|
|
1991
|
-
body: new Uint8Array(chunk.data),
|
|
1992
|
-
contentType: inferContentTypeFromPath(chunk.filePath),
|
|
1993
|
-
metadata: {
|
|
1994
|
-
chunkId: chunk.chunkId,
|
|
1995
|
-
chunkType: chunk.type,
|
|
1996
|
-
sourcePath: chunk.filePath
|
|
1997
|
-
}
|
|
1998
|
-
});
|
|
1999
|
-
}
|
|
2000
|
-
for (const chunk of result.tableChunks) {
|
|
2001
|
-
objects.push({
|
|
2002
|
-
path: normalizeResultPath(chunk.filePath),
|
|
2003
|
-
body: Buffer.from(chunk.html, "utf8"),
|
|
2004
|
-
contentType: htmlContentType,
|
|
2005
|
-
metadata: {
|
|
2006
|
-
chunkId: chunk.chunkId,
|
|
2007
|
-
chunkType: chunk.type,
|
|
2008
|
-
sourcePath: chunk.filePath
|
|
2009
|
-
}
|
|
2010
|
-
});
|
|
2011
|
-
}
|
|
2012
|
-
return objects;
|
|
2013
|
-
}
|
|
2014
|
-
function serializeChunks2(chunks) {
|
|
2015
|
-
return {
|
|
2016
|
-
chunks: chunks.map((chunk) => {
|
|
2017
|
-
const rawChunk = {
|
|
2018
|
-
chunkId: chunk.chunkId,
|
|
2019
|
-
type: chunk.type,
|
|
2020
|
-
contentSource: chunk.contentSource,
|
|
2021
|
-
content: chunk.content,
|
|
2022
|
-
path: chunk.path,
|
|
2023
|
-
metadata: chunk.metadata
|
|
2024
|
-
};
|
|
2025
|
-
if (chunk.type === "image" || chunk.type === "table") {
|
|
2026
|
-
return {
|
|
2027
|
-
...rawChunk,
|
|
2028
|
-
filePath: chunk.filePath,
|
|
2029
|
-
assetUrl: chunk.assetUrl
|
|
2030
|
-
};
|
|
2031
|
-
}
|
|
2032
|
-
return rawChunk;
|
|
2033
|
-
})
|
|
2034
|
-
};
|
|
2035
|
-
}
|
|
2036
|
-
async function writeParsedDocumentJsonObject(storage, params) {
|
|
2037
|
-
await storage.writeObject({
|
|
2038
|
-
documentId: params.documentId,
|
|
2039
|
-
revisionKey: params.revisionKey,
|
|
2040
|
-
path: params.path,
|
|
2041
|
-
body: Buffer.from(JSON.stringify(params.value, null, 2), "utf8"),
|
|
2042
|
-
contentType: jsonContentType
|
|
2043
|
-
});
|
|
2044
|
-
}
|
|
2045
|
-
function createJsonObject(path4, value) {
|
|
2046
|
-
return {
|
|
2047
|
-
path: path4,
|
|
2048
|
-
body: Buffer.from(JSON.stringify(value, null, 2), "utf8"),
|
|
2049
|
-
contentType: jsonContentType
|
|
2050
|
-
};
|
|
2051
|
-
}
|
|
2052
|
-
function createTextObject(path4, value, contentType) {
|
|
2053
|
-
return {
|
|
2054
|
-
path: path4,
|
|
2055
|
-
body: Buffer.from(value, "utf8"),
|
|
2056
|
-
contentType
|
|
2057
|
-
};
|
|
2058
|
-
}
|
|
2059
|
-
function inferContentTypeFromPath(filePath) {
|
|
2060
|
-
const lower = filePath.toLowerCase();
|
|
2061
|
-
if (lower.endsWith(".json")) return jsonContentType;
|
|
2062
|
-
if (lower.endsWith(".md")) return markdownContentType;
|
|
2063
|
-
if (lower.endsWith(".csv")) return csvContentType;
|
|
2064
|
-
if (lower.endsWith(".html") || lower.endsWith(".htm")) return htmlContentType;
|
|
2065
|
-
if (lower.endsWith(".png")) return "image/png";
|
|
2066
|
-
if (lower.endsWith(".jpg") || lower.endsWith(".jpeg")) return "image/jpeg";
|
|
2067
|
-
if (lower.endsWith(".gif")) return "image/gif";
|
|
2068
|
-
if (lower.endsWith(".webp")) return "image/webp";
|
|
2069
|
-
if (lower.endsWith(".svg")) return "image/svg+xml";
|
|
2070
|
-
return binaryContentType;
|
|
2071
|
-
}
|
|
2072
|
-
function normalizeResultPath(value) {
|
|
2073
|
-
const normalized = value.replaceAll("\\", "/").replace(/^\.\/+/, "");
|
|
2074
|
-
if (normalized.length === 0 || normalized.includes("\0") || normalized.startsWith("/") || normalized.split("/").some((part) => part.length === 0 || part === "." || part === "..")) {
|
|
2075
|
-
throw new Error(`Invalid parsed result path: ${value}`);
|
|
2076
|
-
}
|
|
2077
|
-
return normalized;
|
|
2078
|
-
}
|
|
2079
|
-
function isSdkMetadataPath(path4) {
|
|
2080
|
-
return path4 === ".knowhere-sdk" || path4.startsWith(".knowhere-sdk/");
|
|
2081
|
-
}
|
|
2562
|
+
// src/knowledge/knowledge.ts
|
|
2563
|
+
init_parsed_document_storage();
|
|
2564
|
+
init_utils();
|
|
2565
|
+
init_streamed_parsed_document_sync();
|
|
2082
2566
|
|
|
2083
2567
|
// src/knowledge/local-store.ts
|
|
2084
|
-
var
|
|
2085
|
-
var
|
|
2568
|
+
var import_crypto2 = require("crypto");
|
|
2569
|
+
var import_os2 = __toESM(require("os"));
|
|
2086
2570
|
var import_fs3 = require("fs");
|
|
2087
|
-
var
|
|
2571
|
+
var import_path3 = __toESM(require("path"));
|
|
2088
2572
|
var STORE_VERSION = 1;
|
|
2089
2573
|
var LOCAL_DOCUMENT_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
2090
2574
|
var LocalKnowledgeStore = class {
|
|
@@ -2092,8 +2576,8 @@ var LocalKnowledgeStore = class {
|
|
|
2092
2576
|
indexPath;
|
|
2093
2577
|
resultCache = /* @__PURE__ */ new Map();
|
|
2094
2578
|
constructor(cacheDirectory) {
|
|
2095
|
-
this.cacheDirectory = cacheDirectory ??
|
|
2096
|
-
this.indexPath =
|
|
2579
|
+
this.cacheDirectory = cacheDirectory ?? import_path3.default.join(import_os2.default.homedir(), ".knowhere-node-sdk", "knowledge");
|
|
2580
|
+
this.indexPath = import_path3.default.join(this.cacheDirectory, "index.json");
|
|
2097
2581
|
}
|
|
2098
2582
|
async saveResult(result, options) {
|
|
2099
2583
|
await import_fs3.promises.mkdir(this.cacheDirectory, { recursive: true });
|
|
@@ -2218,8 +2702,8 @@ var LocalKnowledgeStore = class {
|
|
|
2218
2702
|
return { document, result };
|
|
2219
2703
|
}
|
|
2220
2704
|
getResultDirectoryPath(localDocumentId) {
|
|
2221
|
-
const documentsDirectory =
|
|
2222
|
-
const resultDirectoryPath =
|
|
2705
|
+
const documentsDirectory = import_path3.default.resolve(this.cacheDirectory, "documents");
|
|
2706
|
+
const resultDirectoryPath = import_path3.default.resolve(documentsDirectory, localDocumentId);
|
|
2223
2707
|
if (!isPathInsideDirectory(resultDirectoryPath, documentsDirectory)) {
|
|
2224
2708
|
throw new Error(`Local Knowhere document ID resolves outside the cache: ${localDocumentId}`);
|
|
2225
2709
|
}
|
|
@@ -2253,7 +2737,7 @@ var LocalKnowledgeStore = class {
|
|
|
2253
2737
|
}
|
|
2254
2738
|
};
|
|
2255
2739
|
function validateLocalDocumentId(localDocumentId) {
|
|
2256
|
-
if (!LOCAL_DOCUMENT_ID_PATTERN.test(localDocumentId) || localDocumentId.includes("..") ||
|
|
2740
|
+
if (!LOCAL_DOCUMENT_ID_PATTERN.test(localDocumentId) || localDocumentId.includes("..") || import_path3.default.basename(localDocumentId) !== localDocumentId) {
|
|
2257
2741
|
throw new Error(
|
|
2258
2742
|
"Local Knowhere document ID must be a safe slug containing only letters, numbers, dots, underscores, or hyphens"
|
|
2259
2743
|
);
|
|
@@ -2261,11 +2745,11 @@ function validateLocalDocumentId(localDocumentId) {
|
|
|
2261
2745
|
return localDocumentId;
|
|
2262
2746
|
}
|
|
2263
2747
|
function isPathInsideDirectory(targetPath, parentDirectory) {
|
|
2264
|
-
const relativePath =
|
|
2265
|
-
return relativePath.length === 0 || !relativePath.startsWith("..") && !
|
|
2748
|
+
const relativePath = import_path3.default.relative(parentDirectory, targetPath);
|
|
2749
|
+
return relativePath.length === 0 || !relativePath.startsWith("..") && !import_path3.default.isAbsolute(relativePath);
|
|
2266
2750
|
}
|
|
2267
2751
|
function createLocalDocumentId(result) {
|
|
2268
|
-
const hash = (0,
|
|
2752
|
+
const hash = (0, import_crypto2.createHash)("sha256").update(result.jobId).update("\0").update(result.manifest.sourceFileName).digest("hex").slice(0, 16);
|
|
2269
2753
|
return `local_${hash}`;
|
|
2270
2754
|
}
|
|
2271
2755
|
function countChunkTypes(result) {
|
|
@@ -2419,29 +2903,32 @@ var Knowledge = class _Knowledge {
|
|
|
2419
2903
|
return this.importJobResult(params);
|
|
2420
2904
|
}
|
|
2421
2905
|
async syncParsedDocument(params) {
|
|
2906
|
+
params.signal?.throwIfAborted();
|
|
2422
2907
|
const normalized = normalizeDocumentReference(params);
|
|
2423
2908
|
const parsedStorageConfig = this.requireParsedStorageConfig();
|
|
2424
2909
|
if (normalized.documentId) {
|
|
2425
2910
|
return this.syncRemoteDocumentToParsedStorage({
|
|
2426
2911
|
documentId: normalized.documentId,
|
|
2427
2912
|
revisionKey: params.revisionKey,
|
|
2428
|
-
parsedStorageConfig
|
|
2913
|
+
parsedStorageConfig,
|
|
2914
|
+
signal: params.signal,
|
|
2915
|
+
retainResultArchive: params.retainResultArchive
|
|
2429
2916
|
});
|
|
2430
2917
|
}
|
|
2431
2918
|
if (normalized.jobId) {
|
|
2432
|
-
const
|
|
2433
|
-
|
|
2434
|
-
result
|
|
2919
|
+
const job = await this.client.jobs.get(normalized.jobId);
|
|
2920
|
+
if (!job.isDone || !job.resultUrl)
|
|
2921
|
+
throw new ValidationError("Completed job result archive is unavailable");
|
|
2922
|
+
return syncRemoteResultArchive({
|
|
2923
|
+
documentId: job.documentId ?? normalized.localDocumentId ?? normalized.jobId,
|
|
2924
|
+
revisionKey: params.revisionKey ?? normalized.jobId,
|
|
2925
|
+
jobId: normalized.jobId,
|
|
2926
|
+
resultUrl: job.resultUrl,
|
|
2435
2927
|
storage: parsedStorageConfig.storage,
|
|
2436
|
-
|
|
2437
|
-
|
|
2928
|
+
limits: parsedStorageConfig.limits,
|
|
2929
|
+
signal: params.signal,
|
|
2930
|
+
retainResultArchive: params.retainResultArchive
|
|
2438
2931
|
});
|
|
2439
|
-
return {
|
|
2440
|
-
documentId: synced2.documentId,
|
|
2441
|
-
revisionKey: synced2.revisionKey,
|
|
2442
|
-
completed: true,
|
|
2443
|
-
commit: synced2.commit
|
|
2444
|
-
};
|
|
2445
2932
|
}
|
|
2446
2933
|
if (!normalized.localDocumentId) {
|
|
2447
2934
|
throw new ValidationError("localDocumentId, documentId, or jobId is required");
|
|
@@ -3139,10 +3626,14 @@ var Knowledge = class _Knowledge {
|
|
|
3139
3626
|
parsedStorageConfig
|
|
3140
3627
|
});
|
|
3141
3628
|
} catch (error) {
|
|
3629
|
+
const previous = await parsedStorageConfig.storage.readSyncProgress({
|
|
3630
|
+
documentId,
|
|
3631
|
+
revisionKey
|
|
3632
|
+
});
|
|
3142
3633
|
await parsedStorageConfig.storage.writeSyncProgress({
|
|
3634
|
+
...previous,
|
|
3143
3635
|
documentId,
|
|
3144
3636
|
revisionKey,
|
|
3145
|
-
nextChunkPage: 1,
|
|
3146
3637
|
status: "failed",
|
|
3147
3638
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3148
3639
|
error: error instanceof Error ? error.message : String(error)
|
|
@@ -3152,6 +3643,7 @@ var Knowledge = class _Knowledge {
|
|
|
3152
3643
|
void Promise.resolve(scheduler.schedule(task)).catch(() => void 0);
|
|
3153
3644
|
}
|
|
3154
3645
|
async syncRemoteDocumentToParsedStorage(params) {
|
|
3646
|
+
params.signal?.throwIfAborted();
|
|
3155
3647
|
const firstPage = await this.client.documents.listChunks(params.documentId, {
|
|
3156
3648
|
page: 1,
|
|
3157
3649
|
pageSize: 1,
|
|
@@ -3159,55 +3651,67 @@ var Knowledge = class _Knowledge {
|
|
|
3159
3651
|
});
|
|
3160
3652
|
const revisionKey = params.revisionKey ?? getRemoteRevisionKey(firstPage);
|
|
3161
3653
|
if (params.revisionKey && getRemoteRevisionKey(firstPage) !== params.revisionKey) {
|
|
3162
|
-
|
|
3163
|
-
documentId: params.documentId,
|
|
3164
|
-
parsedStorageConfig: params.parsedStorageConfig
|
|
3165
|
-
});
|
|
3654
|
+
throw new ValidationError("Published document revision changed before parsed snapshot sync");
|
|
3166
3655
|
}
|
|
3167
3656
|
if (firstPage.jobId) {
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
});
|
|
3177
|
-
await params.parsedStorageConfig.storage.writeSyncProgress({
|
|
3657
|
+
const job = await this.client.jobs.get(firstPage.jobId).catch((error) => {
|
|
3658
|
+
if (error instanceof NotFoundError) return null;
|
|
3659
|
+
throw error;
|
|
3660
|
+
});
|
|
3661
|
+
if (job?.isDone && job.resultUrl) {
|
|
3662
|
+
if (job.documentId && job.documentId !== params.documentId)
|
|
3663
|
+
throw new ValidationError("Parsed job document identity differs from requested document");
|
|
3664
|
+
return syncRemoteResultArchive({
|
|
3178
3665
|
documentId: params.documentId,
|
|
3179
3666
|
revisionKey,
|
|
3180
|
-
|
|
3181
|
-
|
|
3667
|
+
jobId: firstPage.jobId,
|
|
3668
|
+
resultUrl: job.resultUrl,
|
|
3669
|
+
storage: params.parsedStorageConfig.storage,
|
|
3670
|
+
limits: params.parsedStorageConfig.limits,
|
|
3671
|
+
signal: params.signal,
|
|
3672
|
+
retainResultArchive: params.retainResultArchive,
|
|
3673
|
+
verifyRevision: async () => {
|
|
3674
|
+
const current = await this.client.documents.listChunks(params.documentId, {
|
|
3675
|
+
page: 1,
|
|
3676
|
+
pageSize: 1,
|
|
3677
|
+
includeAssetUrls: true
|
|
3678
|
+
});
|
|
3679
|
+
if (getRemoteRevisionKey(current) !== revisionKey || current.jobId !== firstPage.jobId)
|
|
3680
|
+
throw new ValidationError(
|
|
3681
|
+
"Published document revision changed during parsed snapshot sync"
|
|
3682
|
+
);
|
|
3683
|
+
}
|
|
3182
3684
|
});
|
|
3183
|
-
return {
|
|
3184
|
-
documentId: synced.documentId,
|
|
3185
|
-
revisionKey: synced.revisionKey,
|
|
3186
|
-
completed: true,
|
|
3187
|
-
commit: synced.commit
|
|
3188
|
-
};
|
|
3189
|
-
} catch {
|
|
3190
3685
|
}
|
|
3191
3686
|
}
|
|
3192
3687
|
return this.syncRemoteDocumentChunksToParsedStorage({
|
|
3193
3688
|
documentId: params.documentId,
|
|
3194
3689
|
revisionKey,
|
|
3195
3690
|
firstPage,
|
|
3196
|
-
parsedStorageConfig: params.parsedStorageConfig
|
|
3691
|
+
parsedStorageConfig: params.parsedStorageConfig,
|
|
3692
|
+
signal: params.signal
|
|
3197
3693
|
});
|
|
3198
3694
|
}
|
|
3199
3695
|
async syncRemoteDocumentChunksToParsedStorage(params) {
|
|
3696
|
+
params.signal?.throwIfAborted();
|
|
3200
3697
|
const limits = getParsedStorageLimits(params.parsedStorageConfig.limits);
|
|
3201
3698
|
const existingProgress = await params.parsedStorageConfig.storage.readSyncProgress({
|
|
3202
3699
|
documentId: params.documentId,
|
|
3203
3700
|
revisionKey: params.revisionKey
|
|
3204
3701
|
});
|
|
3205
|
-
let nextPage = existingProgress?.status === "running" ? existingProgress.nextChunkPage ?? 1 : 1;
|
|
3702
|
+
let nextPage = existingProgress?.status === "running" || existingProgress?.status === "failed" ? existingProgress.nextChunkPage ?? 1 : 1;
|
|
3206
3703
|
let response = nextPage === 1 && params.firstPage.pagination.pageSize === limits.remotePageSize ? params.firstPage : await this.client.documents.listChunks(params.documentId, {
|
|
3207
3704
|
page: nextPage,
|
|
3208
3705
|
pageSize: limits.remotePageSize,
|
|
3209
3706
|
includeAssetUrls: true
|
|
3210
3707
|
});
|
|
3708
|
+
validateRemoteReconstructionRevision(
|
|
3709
|
+
params.documentId,
|
|
3710
|
+
params.revisionKey,
|
|
3711
|
+
params.firstPage.jobId,
|
|
3712
|
+
response
|
|
3713
|
+
);
|
|
3714
|
+
params.signal?.throwIfAborted();
|
|
3211
3715
|
const totalPages = response.pagination.totalPages;
|
|
3212
3716
|
let syncedPages = 0;
|
|
3213
3717
|
const startedAt = Date.now();
|
|
@@ -3219,6 +3723,13 @@ var Knowledge = class _Knowledge {
|
|
|
3219
3723
|
includeAssetUrls: true
|
|
3220
3724
|
});
|
|
3221
3725
|
}
|
|
3726
|
+
params.signal?.throwIfAborted();
|
|
3727
|
+
validateRemoteReconstructionRevision(
|
|
3728
|
+
params.documentId,
|
|
3729
|
+
params.revisionKey,
|
|
3730
|
+
params.firstPage.jobId,
|
|
3731
|
+
response
|
|
3732
|
+
);
|
|
3222
3733
|
await params.parsedStorageConfig.storage.writeObject({
|
|
3223
3734
|
documentId: params.documentId,
|
|
3224
3735
|
revisionKey: params.revisionKey,
|
|
@@ -3266,7 +3777,23 @@ var Knowledge = class _Knowledge {
|
|
|
3266
3777
|
storage: params.parsedStorageConfig.storage,
|
|
3267
3778
|
documentId: params.documentId,
|
|
3268
3779
|
revisionKey: params.revisionKey,
|
|
3269
|
-
source: "remoteReconstruction"
|
|
3780
|
+
source: "remoteReconstruction",
|
|
3781
|
+
signal: params.signal,
|
|
3782
|
+
beforeCommit: async () => {
|
|
3783
|
+
params.signal?.throwIfAborted();
|
|
3784
|
+
const current = await this.client.documents.listChunks(params.documentId, {
|
|
3785
|
+
page: 1,
|
|
3786
|
+
pageSize: 1,
|
|
3787
|
+
includeAssetUrls: true
|
|
3788
|
+
});
|
|
3789
|
+
params.signal?.throwIfAborted();
|
|
3790
|
+
validateRemoteReconstructionRevision(
|
|
3791
|
+
params.documentId,
|
|
3792
|
+
params.revisionKey,
|
|
3793
|
+
params.firstPage.jobId,
|
|
3794
|
+
current
|
|
3795
|
+
);
|
|
3796
|
+
}
|
|
3270
3797
|
});
|
|
3271
3798
|
await params.parsedStorageConfig.storage.writeSyncProgress({
|
|
3272
3799
|
documentId: params.documentId,
|
|
@@ -3338,7 +3865,7 @@ function createLocalDocumentIdForRemote(documentId) {
|
|
|
3338
3865
|
if (SAFE_LOCAL_DOCUMENT_ID_PATTERN.test(documentId) && !documentId.includes("..") && !documentId.includes("/") && !documentId.includes("\\")) {
|
|
3339
3866
|
return documentId;
|
|
3340
3867
|
}
|
|
3341
|
-
const hash = (0,
|
|
3868
|
+
const hash = (0, import_crypto3.createHash)("sha256").update(documentId).digest("hex").slice(0, 16);
|
|
3342
3869
|
return `remote_${hash}`;
|
|
3343
3870
|
}
|
|
3344
3871
|
var defaultParsedStorageScheduler = {
|
|
@@ -3558,10 +4085,10 @@ function parseStoredResultChunks(params) {
|
|
|
3558
4085
|
}
|
|
3559
4086
|
function extractStoredChunkRecords(payload) {
|
|
3560
4087
|
if (Array.isArray(payload)) {
|
|
3561
|
-
return payload.filter(
|
|
4088
|
+
return payload.filter(isRecord3);
|
|
3562
4089
|
}
|
|
3563
|
-
if (
|
|
3564
|
-
return payload.chunks.filter(
|
|
4090
|
+
if (isRecord3(payload) && Array.isArray(payload.chunks)) {
|
|
4091
|
+
return payload.chunks.filter(isRecord3);
|
|
3565
4092
|
}
|
|
3566
4093
|
return [];
|
|
3567
4094
|
}
|
|
@@ -3581,7 +4108,7 @@ function readRecordNumber(record, ...keys) {
|
|
|
3581
4108
|
}
|
|
3582
4109
|
function readRecordMetadata(record) {
|
|
3583
4110
|
const metadata = record.metadata;
|
|
3584
|
-
return
|
|
4111
|
+
return isRecord3(metadata) ? keysToCamel(metadata) : {};
|
|
3585
4112
|
}
|
|
3586
4113
|
function isKnowledgeChunkType(value) {
|
|
3587
4114
|
return value === "text" || value === "image" || value === "table" || value === "page";
|
|
@@ -3680,7 +4207,7 @@ async function applyStoredPageAssetUrls(params) {
|
|
|
3680
4207
|
}
|
|
3681
4208
|
return Promise.all(
|
|
3682
4209
|
pageAssets.map(async (pageAsset) => {
|
|
3683
|
-
if (!
|
|
4210
|
+
if (!isRecord3(pageAsset)) {
|
|
3684
4211
|
return pageAsset;
|
|
3685
4212
|
}
|
|
3686
4213
|
const artifactRef = readRecordString(pageAsset, "artifactRef", "artifact_ref");
|
|
@@ -3709,7 +4236,7 @@ function getStoredPageAssets(metadata) {
|
|
|
3709
4236
|
return pageAssets?.map(normalizeStoredPageAsset);
|
|
3710
4237
|
}
|
|
3711
4238
|
function normalizeStoredPageAsset(pageAsset) {
|
|
3712
|
-
if (!
|
|
4239
|
+
if (!isRecord3(pageAsset)) {
|
|
3713
4240
|
return pageAsset;
|
|
3714
4241
|
}
|
|
3715
4242
|
const normalizedPageAsset = { ...pageAsset };
|
|
@@ -3787,7 +4314,7 @@ function parseContinuationCursor(value) {
|
|
|
3787
4314
|
}
|
|
3788
4315
|
try {
|
|
3789
4316
|
const parsed = JSON.parse(Buffer.from(value, "base64url").toString("utf8"));
|
|
3790
|
-
if (!
|
|
4317
|
+
if (!isRecord3(parsed)) {
|
|
3791
4318
|
return null;
|
|
3792
4319
|
}
|
|
3793
4320
|
const documentId = parsed.documentId;
|
|
@@ -3825,11 +4352,11 @@ function inferContentTypeFromPath2(filePath) {
|
|
|
3825
4352
|
if (extension === "html" || extension === "htm") return "text/html; charset=utf-8";
|
|
3826
4353
|
return "application/octet-stream";
|
|
3827
4354
|
}
|
|
3828
|
-
function
|
|
4355
|
+
function isRecord3(value) {
|
|
3829
4356
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3830
4357
|
}
|
|
3831
4358
|
function isDocumentChunkArray(value) {
|
|
3832
|
-
return Array.isArray(value) && value.every(
|
|
4359
|
+
return Array.isArray(value) && value.every(isRecord3);
|
|
3833
4360
|
}
|
|
3834
4361
|
function indexChunks(result) {
|
|
3835
4362
|
return result.chunks.map((chunk, index) => {
|
|
@@ -4132,17 +4659,24 @@ function toRemoteSearchResult(result, documentByServerId) {
|
|
|
4132
4659
|
sourceFileName: result.source.sourceFileName ?? void 0
|
|
4133
4660
|
};
|
|
4134
4661
|
}
|
|
4662
|
+
function validateRemoteReconstructionRevision(documentId, revisionKey, jobId, response) {
|
|
4663
|
+
if (response.documentId !== documentId || getRemoteRevisionKey(response) !== revisionKey || (response.jobId ?? void 0) !== (jobId ?? void 0)) {
|
|
4664
|
+
throw new ValidationError("Published document revision changed during remote reconstruction");
|
|
4665
|
+
}
|
|
4666
|
+
}
|
|
4135
4667
|
|
|
4136
4668
|
// src/client.ts
|
|
4669
|
+
init_constants();
|
|
4670
|
+
init_utils();
|
|
4137
4671
|
function inferFileName(file, explicitFileName) {
|
|
4138
4672
|
if (explicitFileName) {
|
|
4139
4673
|
return explicitFileName;
|
|
4140
4674
|
}
|
|
4141
4675
|
if (typeof file === "string") {
|
|
4142
|
-
return
|
|
4676
|
+
return import_path4.default.basename(file);
|
|
4143
4677
|
}
|
|
4144
4678
|
if (isReadStream2(file) && typeof file.path === "string") {
|
|
4145
|
-
return
|
|
4679
|
+
return import_path4.default.basename(file.path);
|
|
4146
4680
|
}
|
|
4147
4681
|
return void 0;
|
|
4148
4682
|
}
|
|
@@ -4288,9 +4822,9 @@ var Knowhere = class {
|
|
|
4288
4822
|
};
|
|
4289
4823
|
|
|
4290
4824
|
// src/storage/disk-parsed-document-storage.ts
|
|
4291
|
-
var
|
|
4825
|
+
var import_crypto4 = require("crypto");
|
|
4292
4826
|
var import_fs4 = require("fs");
|
|
4293
|
-
var
|
|
4827
|
+
var import_path5 = __toESM(require("path"));
|
|
4294
4828
|
var syncProgressPath = ".knowhere-sdk/sync-progress.json";
|
|
4295
4829
|
var DiskParsedDocumentStorage = class {
|
|
4296
4830
|
rootDirectory;
|
|
@@ -4319,7 +4853,7 @@ var DiskParsedDocumentStorage = class {
|
|
|
4319
4853
|
}
|
|
4320
4854
|
async writeObject(params) {
|
|
4321
4855
|
const objectPath = this.getObjectPath(params);
|
|
4322
|
-
await import_fs4.promises.mkdir(
|
|
4856
|
+
await import_fs4.promises.mkdir(import_path5.default.dirname(objectPath), { recursive: true });
|
|
4323
4857
|
await import_fs4.promises.writeFile(objectPath, params.body);
|
|
4324
4858
|
await this.writeObjectMetadata(objectPath, {
|
|
4325
4859
|
contentType: params.contentType,
|
|
@@ -4378,14 +4912,14 @@ var DiskParsedDocumentStorage = class {
|
|
|
4378
4912
|
}
|
|
4379
4913
|
getObjectPath(params) {
|
|
4380
4914
|
const revisionDirectory = this.getRevisionDirectory(params.documentId, params.revisionKey);
|
|
4381
|
-
const objectPath =
|
|
4915
|
+
const objectPath = import_path5.default.resolve(revisionDirectory, normalizeRelativeStoragePath(params.path));
|
|
4382
4916
|
if (!isPathInsideDirectory2(objectPath, revisionDirectory)) {
|
|
4383
4917
|
throw new Error(`Parsed document object path resolves outside storage: ${params.path}`);
|
|
4384
4918
|
}
|
|
4385
4919
|
return objectPath;
|
|
4386
4920
|
}
|
|
4387
4921
|
getRevisionDirectory(documentId, revisionKey) {
|
|
4388
|
-
return
|
|
4922
|
+
return import_path5.default.join(this.rootDirectory, hashPathPart(documentId), hashPathPart(revisionKey));
|
|
4389
4923
|
}
|
|
4390
4924
|
async readOptionalJson(params) {
|
|
4391
4925
|
const object = await this.readObject(params);
|
|
@@ -4421,7 +4955,7 @@ function hashPathPart(value) {
|
|
|
4421
4955
|
if (normalized.length === 0) {
|
|
4422
4956
|
throw new Error("Parsed document storage path part must be a non-empty value.");
|
|
4423
4957
|
}
|
|
4424
|
-
return (0,
|
|
4958
|
+
return (0, import_crypto4.createHash)("sha256").update(normalized).digest("hex").slice(0, 24);
|
|
4425
4959
|
}
|
|
4426
4960
|
function normalizeRelativeStoragePath(value) {
|
|
4427
4961
|
const normalized = value.replaceAll("\\", "/").replace(/^\.\/+/, "");
|
|
@@ -4431,8 +4965,8 @@ function normalizeRelativeStoragePath(value) {
|
|
|
4431
4965
|
return normalized;
|
|
4432
4966
|
}
|
|
4433
4967
|
function isPathInsideDirectory2(filePath, directory) {
|
|
4434
|
-
const relative =
|
|
4435
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
4968
|
+
const relative = import_path5.default.relative(directory, filePath);
|
|
4969
|
+
return relative === "" || !relative.startsWith("..") && !import_path5.default.isAbsolute(relative);
|
|
4436
4970
|
}
|
|
4437
4971
|
function toFileUrl(filePath) {
|
|
4438
4972
|
return `file://${filePath}`;
|
|
@@ -4440,6 +4974,9 @@ function toFileUrl(filePath) {
|
|
|
4440
4974
|
function isMissingFileError3(error) {
|
|
4441
4975
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
4442
4976
|
}
|
|
4977
|
+
|
|
4978
|
+
// src/index.ts
|
|
4979
|
+
init_parsed_document_storage();
|
|
4443
4980
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4444
4981
|
0 && (module.exports = {
|
|
4445
4982
|
APIError,
|
|
@@ -4461,6 +4998,7 @@ function isMissingFileError3(error) {
|
|
|
4461
4998
|
NODE_SDK_DOCUMENT_METADATA_DEFAULTS,
|
|
4462
4999
|
NetworkError,
|
|
4463
5000
|
NotFoundError,
|
|
5001
|
+
ParsedDocumentArchiveError,
|
|
4464
5002
|
PaymentRequiredError,
|
|
4465
5003
|
PermissionDeniedError,
|
|
4466
5004
|
PollingTimeoutError,
|