@dvvebond/core 0.2.12
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/LICENSE.md +21 -0
- package/README.md +214 -0
- package/dist/chunk-15K8U1wQ.mjs +18 -0
- package/dist/index.d.mts +22131 -0
- package/dist/index.mjs +61480 -0
- package/dist/index.mjs.map +1 -0
- package/dist/parsing-worker-host-COnJliNW.mjs +3 -0
- package/dist/parsing-worker-host-CcJO1eh7.mjs +550 -0
- package/dist/parsing-worker-host-CcJO1eh7.mjs.map +1 -0
- package/package.json +127 -0
|
@@ -0,0 +1,550 @@
|
|
|
1
|
+
//#region src/worker/messages.ts
|
|
2
|
+
/**
|
|
3
|
+
* Generate a unique message ID.
|
|
4
|
+
*/
|
|
5
|
+
function generateMessageId() {
|
|
6
|
+
return `msg-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Generate a unique task ID.
|
|
10
|
+
*/
|
|
11
|
+
function generateTaskId() {
|
|
12
|
+
return `task-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Check if a message is a response.
|
|
16
|
+
*/
|
|
17
|
+
function isResponse(message) {
|
|
18
|
+
return typeof message === "object" && message !== null && "type" in message && message.type === "response";
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Check if a message is a progress update.
|
|
22
|
+
*/
|
|
23
|
+
function isProgress(message) {
|
|
24
|
+
return typeof message === "object" && message !== null && "type" in message && message.type === "progress";
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Create a request message.
|
|
28
|
+
*/
|
|
29
|
+
function createRequest(requestType, data) {
|
|
30
|
+
return {
|
|
31
|
+
type: "request",
|
|
32
|
+
id: generateMessageId(),
|
|
33
|
+
requestType,
|
|
34
|
+
data
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Create a WorkerError from an Error.
|
|
39
|
+
*/
|
|
40
|
+
function createWorkerError(error, code) {
|
|
41
|
+
return {
|
|
42
|
+
code: code ?? error.name,
|
|
43
|
+
message: error.message,
|
|
44
|
+
stack: error.stack
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region src/worker/parsing-types.ts
|
|
50
|
+
/**
|
|
51
|
+
* Check if a message is a parsing progress message.
|
|
52
|
+
*/
|
|
53
|
+
function isParsingProgress(message) {
|
|
54
|
+
return typeof message === "object" && message !== null && "type" in message && message.type === "parsingProgress";
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Check if a message is a parsing worker response.
|
|
58
|
+
*/
|
|
59
|
+
function isParsingResponse(message) {
|
|
60
|
+
return typeof message === "object" && message !== null && "type" in message && message.type === "response" && "requestType" in message && [
|
|
61
|
+
"parseDocument",
|
|
62
|
+
"extractText",
|
|
63
|
+
"cancelParsing"
|
|
64
|
+
].includes(message.requestType);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Create a parsing progress message.
|
|
68
|
+
*/
|
|
69
|
+
function createParsingProgress(taskId, progress) {
|
|
70
|
+
return {
|
|
71
|
+
type: "parsingProgress",
|
|
72
|
+
taskId,
|
|
73
|
+
progress,
|
|
74
|
+
timestamp: Date.now()
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
//#endregion
|
|
79
|
+
//#region src/worker/parsing-utils.ts
|
|
80
|
+
/**
|
|
81
|
+
* Detect the current runtime environment.
|
|
82
|
+
*/
|
|
83
|
+
function detectEnvironment() {
|
|
84
|
+
if (typeof globalThis !== "undefined" && "Bun" in globalThis) return "bun";
|
|
85
|
+
if (typeof globalThis !== "undefined" && "Deno" in globalThis) return "deno";
|
|
86
|
+
if (typeof globalThis !== "undefined" && typeof globalThis.process?.versions?.node === "string") return "node";
|
|
87
|
+
if (typeof window !== "undefined" && typeof document !== "undefined") return "browser";
|
|
88
|
+
if (typeof self !== "undefined" && typeof self.importScripts === "function") return "browser";
|
|
89
|
+
return "unknown";
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Check if Web Workers are supported in the current environment.
|
|
93
|
+
*/
|
|
94
|
+
function isWorkerSupported() {
|
|
95
|
+
switch (detectEnvironment()) {
|
|
96
|
+
case "browser": return typeof Worker !== "undefined";
|
|
97
|
+
case "node": return false;
|
|
98
|
+
case "bun": return typeof Worker !== "undefined";
|
|
99
|
+
case "deno": return typeof Worker !== "undefined";
|
|
100
|
+
default: return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Check if we're currently running inside a Web Worker.
|
|
105
|
+
*/
|
|
106
|
+
function isWorkerContext() {
|
|
107
|
+
return typeof self !== "undefined" && typeof self.importScripts === "function" && typeof window === "undefined";
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Create a Worker instance with proper error handling.
|
|
111
|
+
*
|
|
112
|
+
* @throws Error if workers are not supported or creation fails
|
|
113
|
+
*/
|
|
114
|
+
function createWorkerInstance(options) {
|
|
115
|
+
if (!isWorkerSupported()) throw new Error(`Web Workers are not supported in ${detectEnvironment()} environment. Use the synchronous parsing API instead.`);
|
|
116
|
+
const { workerUrl, name, module = true } = options;
|
|
117
|
+
if (!workerUrl) throw new Error("Worker URL is required. Provide workerUrl pointing to the bundled parsing worker script.");
|
|
118
|
+
try {
|
|
119
|
+
return new Worker(workerUrl, {
|
|
120
|
+
type: module ? "module" : "classic",
|
|
121
|
+
name: name ?? `parsing-worker-${Date.now()}`
|
|
122
|
+
});
|
|
123
|
+
} catch (error) {
|
|
124
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
125
|
+
throw new Error(`Failed to create parsing worker: ${message}`, { cause: error });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Extract transferable objects from data for efficient worker communication.
|
|
130
|
+
*
|
|
131
|
+
* Identifies ArrayBuffer instances that can be transferred (zero-copy)
|
|
132
|
+
* instead of copied between threads.
|
|
133
|
+
*/
|
|
134
|
+
function extractTransferables(data) {
|
|
135
|
+
const transferables = [];
|
|
136
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
137
|
+
function collect(value) {
|
|
138
|
+
if (value === null || typeof value !== "object") return;
|
|
139
|
+
if (seen.has(value)) return;
|
|
140
|
+
seen.add(value);
|
|
141
|
+
if (value instanceof ArrayBuffer) {
|
|
142
|
+
transferables.push(value);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if (ArrayBuffer.isView(value) && value.buffer instanceof ArrayBuffer) {
|
|
146
|
+
if (value.byteOffset === 0 && value.byteLength === value.buffer.byteLength) transferables.push(value.buffer);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
if (Array.isArray(value)) {
|
|
150
|
+
for (const item of value) collect(item);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
for (const key of Object.keys(value)) collect(value[key]);
|
|
154
|
+
}
|
|
155
|
+
collect(data);
|
|
156
|
+
return transferables;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Generate a unique ID for messages.
|
|
160
|
+
*/
|
|
161
|
+
function generateParsingMessageId() {
|
|
162
|
+
return `parse-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Generate a unique task ID for parsing operations.
|
|
166
|
+
*/
|
|
167
|
+
function generateParsingTaskId() {
|
|
168
|
+
return `parsing-task-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Default timeouts for parsing operations (in milliseconds).
|
|
172
|
+
*/
|
|
173
|
+
const DEFAULT_PARSING_TIMEOUTS = {
|
|
174
|
+
init: 1e4,
|
|
175
|
+
small: 3e4,
|
|
176
|
+
medium: 6e4,
|
|
177
|
+
large: 3e5,
|
|
178
|
+
textPerPage: 5e3
|
|
179
|
+
};
|
|
180
|
+
/**
|
|
181
|
+
* Calculate appropriate timeout based on document size.
|
|
182
|
+
*/
|
|
183
|
+
function calculateParsingTimeout(sizeBytes) {
|
|
184
|
+
const sizeMB = sizeBytes / (1024 * 1024);
|
|
185
|
+
if (sizeMB < 1) return DEFAULT_PARSING_TIMEOUTS.small;
|
|
186
|
+
if (sizeMB < 10) return DEFAULT_PARSING_TIMEOUTS.medium;
|
|
187
|
+
return DEFAULT_PARSING_TIMEOUTS.large;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Create a deferred promise for async coordination.
|
|
191
|
+
*/
|
|
192
|
+
function createDeferred() {
|
|
193
|
+
let resolve;
|
|
194
|
+
let reject;
|
|
195
|
+
let isPending = true;
|
|
196
|
+
return {
|
|
197
|
+
promise: new Promise((res, rej) => {
|
|
198
|
+
resolve = (value) => {
|
|
199
|
+
isPending = false;
|
|
200
|
+
res(value);
|
|
201
|
+
};
|
|
202
|
+
reject = (reason) => {
|
|
203
|
+
isPending = false;
|
|
204
|
+
rej(reason);
|
|
205
|
+
};
|
|
206
|
+
}),
|
|
207
|
+
resolve,
|
|
208
|
+
reject,
|
|
209
|
+
get isPending() {
|
|
210
|
+
return isPending;
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
//#endregion
|
|
216
|
+
//#region src/worker/parsing-worker-host.ts
|
|
217
|
+
/**
|
|
218
|
+
* Main thread interface for parsing worker communication.
|
|
219
|
+
*
|
|
220
|
+
* ParsingWorkerHost manages the lifecycle of a parsing worker and provides
|
|
221
|
+
* a Promise-based API for document parsing operations. It handles:
|
|
222
|
+
* - Worker creation and initialization
|
|
223
|
+
* - Message passing with request/response correlation
|
|
224
|
+
* - Progress event handling with 500ms throttling
|
|
225
|
+
* - Cancellation support
|
|
226
|
+
* - Graceful shutdown and cleanup
|
|
227
|
+
*/
|
|
228
|
+
/**
|
|
229
|
+
* ParsingWorkerHost manages a Web Worker for PDF parsing operations.
|
|
230
|
+
*
|
|
231
|
+
* @example
|
|
232
|
+
* ```typescript
|
|
233
|
+
* const host = new ParsingWorkerHost({
|
|
234
|
+
* workerUrl: '/parsing-worker.js',
|
|
235
|
+
* onProgress: (progress) => console.log(`${progress.percent}%`),
|
|
236
|
+
* });
|
|
237
|
+
*
|
|
238
|
+
* await host.initialize();
|
|
239
|
+
*
|
|
240
|
+
* const result = await host.parse(pdfBytes);
|
|
241
|
+
* console.log(`Parsed ${result.info.pageCount} pages`);
|
|
242
|
+
*
|
|
243
|
+
* const text = await host.extractText(result.documentId);
|
|
244
|
+
* console.log(text.pages[0].text);
|
|
245
|
+
*
|
|
246
|
+
* await host.terminate();
|
|
247
|
+
* ```
|
|
248
|
+
*/
|
|
249
|
+
var ParsingWorkerHost = class {
|
|
250
|
+
_worker = null;
|
|
251
|
+
_state = "idle";
|
|
252
|
+
_options;
|
|
253
|
+
_pendingRequests = /* @__PURE__ */ new Map();
|
|
254
|
+
_taskProgressHandlers = /* @__PURE__ */ new Map();
|
|
255
|
+
_initPromise = null;
|
|
256
|
+
constructor(options) {
|
|
257
|
+
this._options = {
|
|
258
|
+
workerUrl: options.workerUrl,
|
|
259
|
+
name: options.name ?? `parsing-worker-host-${Date.now()}`,
|
|
260
|
+
verbose: options.verbose ?? false,
|
|
261
|
+
initTimeout: options.initTimeout ?? 1e4,
|
|
262
|
+
defaultTimeout: options.defaultTimeout ?? 6e4,
|
|
263
|
+
onProgress: options.onProgress,
|
|
264
|
+
onError: options.onError,
|
|
265
|
+
onStateChange: options.onStateChange
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Current worker state.
|
|
270
|
+
*/
|
|
271
|
+
get state() {
|
|
272
|
+
return this._state;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Whether the worker is ready to accept requests.
|
|
276
|
+
*/
|
|
277
|
+
get isReady() {
|
|
278
|
+
return this._state === "ready" || this._state === "busy";
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Whether the worker has been terminated.
|
|
282
|
+
*/
|
|
283
|
+
get isTerminated() {
|
|
284
|
+
return this._state === "terminated";
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Number of pending requests.
|
|
288
|
+
*/
|
|
289
|
+
get pendingCount() {
|
|
290
|
+
return this._pendingRequests.size;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Worker name.
|
|
294
|
+
*/
|
|
295
|
+
get name() {
|
|
296
|
+
return this._options.name;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Initialize the worker.
|
|
300
|
+
*
|
|
301
|
+
* Creates the Web Worker instance and waits for it to be ready.
|
|
302
|
+
* This method is idempotent — calling it multiple times returns the same promise.
|
|
303
|
+
*
|
|
304
|
+
* @throws Error if workers are not supported, creation fails, or initialization times out
|
|
305
|
+
*/
|
|
306
|
+
async initialize() {
|
|
307
|
+
if (this._initPromise) return this._initPromise;
|
|
308
|
+
if (this._state === "terminated") throw new Error("Cannot initialize a terminated worker");
|
|
309
|
+
this._initPromise = this._doInitialize();
|
|
310
|
+
return this._initPromise;
|
|
311
|
+
}
|
|
312
|
+
async _doInitialize() {
|
|
313
|
+
this._setState("initializing");
|
|
314
|
+
try {
|
|
315
|
+
this._worker = createWorkerInstance({
|
|
316
|
+
workerUrl: this._options.workerUrl,
|
|
317
|
+
name: this._options.name,
|
|
318
|
+
module: true
|
|
319
|
+
});
|
|
320
|
+
this._worker.onmessage = this._handleMessage.bind(this);
|
|
321
|
+
this._worker.onerror = this._handleError.bind(this);
|
|
322
|
+
await this._sendRequest("init", {
|
|
323
|
+
verbose: this._options.verbose,
|
|
324
|
+
name: this._options.name
|
|
325
|
+
}, this._options.initTimeout);
|
|
326
|
+
this._setState("ready");
|
|
327
|
+
} catch (error) {
|
|
328
|
+
this._setState("error");
|
|
329
|
+
this._cleanup();
|
|
330
|
+
throw error;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Terminate the worker.
|
|
335
|
+
*
|
|
336
|
+
* @param graceful - If true, wait for pending operations to complete
|
|
337
|
+
* @param timeout - Timeout for graceful shutdown in milliseconds
|
|
338
|
+
*/
|
|
339
|
+
async terminate(graceful = true, timeout = 5e3) {
|
|
340
|
+
if (this._state === "terminated") return;
|
|
341
|
+
if (graceful && this._worker && this.isReady) try {
|
|
342
|
+
await Promise.race([this._sendRequest("terminate", void 0, timeout), new Promise((_, reject) => setTimeout(() => reject(/* @__PURE__ */ new Error("Terminate timeout")), timeout))]);
|
|
343
|
+
} catch {}
|
|
344
|
+
this._forceTerminate();
|
|
345
|
+
}
|
|
346
|
+
_forceTerminate() {
|
|
347
|
+
for (const pending of this._pendingRequests.values()) {
|
|
348
|
+
if (pending.timeoutId) clearTimeout(pending.timeoutId);
|
|
349
|
+
pending.deferred.reject(/* @__PURE__ */ new Error("Worker terminated"));
|
|
350
|
+
}
|
|
351
|
+
this._pendingRequests.clear();
|
|
352
|
+
this._taskProgressHandlers.clear();
|
|
353
|
+
if (this._worker) {
|
|
354
|
+
this._worker.terminate();
|
|
355
|
+
this._worker = null;
|
|
356
|
+
}
|
|
357
|
+
this._setState("terminated");
|
|
358
|
+
this._initPromise = null;
|
|
359
|
+
}
|
|
360
|
+
_cleanup() {
|
|
361
|
+
for (const pending of this._pendingRequests.values()) if (pending.timeoutId) clearTimeout(pending.timeoutId);
|
|
362
|
+
this._pendingRequests.clear();
|
|
363
|
+
this._taskProgressHandlers.clear();
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Parse a PDF document.
|
|
367
|
+
*
|
|
368
|
+
* @param bytes - PDF file bytes
|
|
369
|
+
* @param options - Parse options
|
|
370
|
+
* @returns Parsed document information
|
|
371
|
+
*/
|
|
372
|
+
async parse(bytes, options) {
|
|
373
|
+
await this._ensureInitialized();
|
|
374
|
+
const taskId = generateParsingTaskId();
|
|
375
|
+
const timeout = options?.timeout ?? calculateParsingTimeout(bytes.length);
|
|
376
|
+
if (options?.onProgress) this._taskProgressHandlers.set(taskId, options.onProgress);
|
|
377
|
+
try {
|
|
378
|
+
const response = await this._sendRequest("parseDocument", {
|
|
379
|
+
bytes,
|
|
380
|
+
taskId,
|
|
381
|
+
options: {
|
|
382
|
+
lenient: options?.lenient,
|
|
383
|
+
password: options?.password,
|
|
384
|
+
bruteForceRecovery: options?.bruteForceRecovery,
|
|
385
|
+
progressInterval: options?.progressInterval
|
|
386
|
+
}
|
|
387
|
+
}, timeout, taskId, [bytes.buffer]);
|
|
388
|
+
if (response.status === "cancelled") throw new Error("Operation cancelled");
|
|
389
|
+
if (response.status === "error" || !response.data) throw new Error(response.error?.message ?? "Failed to parse document");
|
|
390
|
+
return response.data;
|
|
391
|
+
} finally {
|
|
392
|
+
this._taskProgressHandlers.delete(taskId);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Parse a PDF document with cancellation support.
|
|
397
|
+
*/
|
|
398
|
+
parseCancellable(bytes, options) {
|
|
399
|
+
const taskId = generateParsingTaskId();
|
|
400
|
+
return {
|
|
401
|
+
promise: this.parse(bytes, {
|
|
402
|
+
...options,
|
|
403
|
+
taskId
|
|
404
|
+
}),
|
|
405
|
+
taskId,
|
|
406
|
+
cancel: () => this.cancel(taskId)
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Extract text from a parsed document.
|
|
411
|
+
*
|
|
412
|
+
* @param documentId - Document ID from parse result
|
|
413
|
+
* @param options - Extraction options
|
|
414
|
+
* @returns Extracted text per page
|
|
415
|
+
*/
|
|
416
|
+
async extractText(documentId, options) {
|
|
417
|
+
await this._ensureInitialized();
|
|
418
|
+
const taskId = generateParsingTaskId();
|
|
419
|
+
const timeout = options?.timeout ?? this._options.defaultTimeout;
|
|
420
|
+
if (options?.onProgress) this._taskProgressHandlers.set(taskId, options.onProgress);
|
|
421
|
+
try {
|
|
422
|
+
const response = await this._sendRequest("extractText", {
|
|
423
|
+
documentId,
|
|
424
|
+
taskId,
|
|
425
|
+
pageIndices: options?.pages,
|
|
426
|
+
includePositions: options?.includePositions
|
|
427
|
+
}, timeout, taskId);
|
|
428
|
+
if (response.status === "cancelled") throw new Error("Operation cancelled");
|
|
429
|
+
if (response.status === "error" || !response.data) throw new Error(response.error?.message ?? "Failed to extract text");
|
|
430
|
+
return response.data;
|
|
431
|
+
} finally {
|
|
432
|
+
this._taskProgressHandlers.delete(taskId);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Cancel an active parsing operation.
|
|
437
|
+
*
|
|
438
|
+
* @param taskId - Task ID to cancel
|
|
439
|
+
* @returns Whether the task was successfully cancelled
|
|
440
|
+
*/
|
|
441
|
+
async cancel(taskId) {
|
|
442
|
+
if (!this.isReady) return false;
|
|
443
|
+
try {
|
|
444
|
+
const response = await this._sendRequest("cancelParsing", { taskId }, 5e3);
|
|
445
|
+
return response.status === "success" && response.data?.wasCancelled;
|
|
446
|
+
} catch {
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
async _ensureInitialized() {
|
|
451
|
+
if (this._state === "terminated") throw new Error("Worker has been terminated");
|
|
452
|
+
if (!this.isReady) await this.initialize();
|
|
453
|
+
}
|
|
454
|
+
_sendRequest(requestType, data, timeout, taskId, transferables) {
|
|
455
|
+
if (this._state === "terminated") return Promise.reject(/* @__PURE__ */ new Error("Worker has been terminated"));
|
|
456
|
+
if (!this._worker) return Promise.reject(/* @__PURE__ */ new Error("Worker not initialized"));
|
|
457
|
+
const messageId = generateMessageId();
|
|
458
|
+
const actualTaskId = taskId ?? generateTaskId();
|
|
459
|
+
const deferred = createDeferred();
|
|
460
|
+
const timeoutId = setTimeout(() => {
|
|
461
|
+
const pending$1 = this._pendingRequests.get(messageId);
|
|
462
|
+
if (pending$1) {
|
|
463
|
+
this._pendingRequests.delete(messageId);
|
|
464
|
+
this._updateBusyState();
|
|
465
|
+
pending$1.deferred.reject(/* @__PURE__ */ new Error(`Request timeout after ${timeout}ms: ${requestType}`));
|
|
466
|
+
}
|
|
467
|
+
}, timeout);
|
|
468
|
+
const pending = {
|
|
469
|
+
messageId,
|
|
470
|
+
taskId: actualTaskId,
|
|
471
|
+
deferred,
|
|
472
|
+
timeoutId
|
|
473
|
+
};
|
|
474
|
+
this._pendingRequests.set(messageId, pending);
|
|
475
|
+
if (this._state === "ready") this._setState("busy");
|
|
476
|
+
const request = {
|
|
477
|
+
type: "request",
|
|
478
|
+
id: messageId,
|
|
479
|
+
requestType,
|
|
480
|
+
data
|
|
481
|
+
};
|
|
482
|
+
try {
|
|
483
|
+
if (transferables && transferables.length > 0) this._worker.postMessage(request, transferables);
|
|
484
|
+
else this._worker.postMessage(request);
|
|
485
|
+
} catch (error) {
|
|
486
|
+
clearTimeout(timeoutId);
|
|
487
|
+
this._pendingRequests.delete(messageId);
|
|
488
|
+
this._updateBusyState();
|
|
489
|
+
return Promise.reject(error);
|
|
490
|
+
}
|
|
491
|
+
return deferred.promise;
|
|
492
|
+
}
|
|
493
|
+
_handleMessage(event) {
|
|
494
|
+
const message = event.data;
|
|
495
|
+
if (isParsingProgress(message)) this._handleProgress(message);
|
|
496
|
+
else if (isParsingResponse(message)) this._handleResponse(message);
|
|
497
|
+
else if (typeof message === "object" && message !== null && "type" in message) {
|
|
498
|
+
if (message.type === "response") this._handleResponse(message);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
_handleResponse(response) {
|
|
502
|
+
const pending = this._pendingRequests.get(response.id);
|
|
503
|
+
if (!pending) return;
|
|
504
|
+
if (pending.timeoutId) clearTimeout(pending.timeoutId);
|
|
505
|
+
this._pendingRequests.delete(response.id);
|
|
506
|
+
this._updateBusyState();
|
|
507
|
+
if (response.status === "error" && response.error) pending.deferred.reject(new Error(response.error.message));
|
|
508
|
+
else pending.deferred.resolve(response);
|
|
509
|
+
}
|
|
510
|
+
_handleProgress(progress) {
|
|
511
|
+
const taskHandler = this._taskProgressHandlers.get(progress.taskId);
|
|
512
|
+
if (taskHandler) taskHandler(progress.progress);
|
|
513
|
+
if (this._options.onProgress) this._options.onProgress(progress.progress);
|
|
514
|
+
}
|
|
515
|
+
_handleError(event) {
|
|
516
|
+
const error = {
|
|
517
|
+
code: "INTERNAL_ERROR",
|
|
518
|
+
message: event.message ?? "Unknown worker error",
|
|
519
|
+
recoverable: false
|
|
520
|
+
};
|
|
521
|
+
if (this._options.onError) this._options.onError(error);
|
|
522
|
+
if (this._state !== "initializing") {
|
|
523
|
+
for (const pending of this._pendingRequests.values()) {
|
|
524
|
+
if (pending.timeoutId) clearTimeout(pending.timeoutId);
|
|
525
|
+
pending.deferred.reject(new Error(error.message));
|
|
526
|
+
}
|
|
527
|
+
this._pendingRequests.clear();
|
|
528
|
+
this._setState("error");
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
_updateBusyState() {
|
|
532
|
+
if (this._state === "busy" && this._pendingRequests.size === 0) this._setState("ready");
|
|
533
|
+
}
|
|
534
|
+
_setState(newState) {
|
|
535
|
+
const previousState = this._state;
|
|
536
|
+
if (previousState === newState) return;
|
|
537
|
+
this._state = newState;
|
|
538
|
+
if (this._options.onStateChange) this._options.onStateChange(newState, previousState);
|
|
539
|
+
}
|
|
540
|
+
};
|
|
541
|
+
/**
|
|
542
|
+
* Create a new ParsingWorkerHost instance.
|
|
543
|
+
*/
|
|
544
|
+
function createParsingWorkerHost(options) {
|
|
545
|
+
return new ParsingWorkerHost(options);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
//#endregion
|
|
549
|
+
export { isResponse as _, createDeferred as a, generateParsingMessageId as c, isWorkerSupported as d, createParsingProgress as f, isProgress as g, generateTaskId as h, calculateParsingTimeout as i, generateParsingTaskId as l, createWorkerError as m, createParsingWorkerHost as n, detectEnvironment as o, createRequest as p, DEFAULT_PARSING_TIMEOUTS as r, extractTransferables as s, ParsingWorkerHost as t, isWorkerContext as u };
|
|
550
|
+
//# sourceMappingURL=parsing-worker-host-CcJO1eh7.mjs.map
|