Skip to content

Commit 03279ed

Browse files
committed
Cleanup add other frameworks
1 parent 7d5fb2b commit 03279ed

27 files changed

Lines changed: 640 additions & 1158 deletions

File tree

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,3 @@ config/tsup.frameworks.config.bundled*
1515
publish-summary.json
1616
**/.svelte-kit
1717
**/*/*.tgz
18-
.envrc
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**
2+
* Recursively walks a response object and collects Transferable entries
3+
* (ArrayBuffer from typed arrays, raw ArrayBuffer).
4+
*
5+
* Depth-limited to 6 to cover the deepest nesting in this codebase:
6+
* response.data.result[annotId][mode].data.data (AnnotationAppearanceMap)
7+
*/
8+
9+
const MAX_DEPTH = 6;
10+
11+
function walk(value: unknown, seen: Set<ArrayBuffer>, depth: number): void {
12+
if (depth > MAX_DEPTH || value == null || typeof value !== 'object') {
13+
return;
14+
}
15+
16+
if (value instanceof ArrayBuffer) {
17+
seen.add(value);
18+
return;
19+
}
20+
21+
// SharedArrayBuffer is not transferable — skip
22+
if (typeof SharedArrayBuffer !== 'undefined' && value instanceof SharedArrayBuffer) {
23+
return;
24+
}
25+
26+
if (ArrayBuffer.isView(value)) {
27+
const buf = value.buffer;
28+
if (buf instanceof ArrayBuffer) {
29+
seen.add(buf);
30+
}
31+
return;
32+
}
33+
34+
if (Array.isArray(value)) {
35+
for (let i = 0; i < value.length; i++) {
36+
walk(value[i], seen, depth + 1);
37+
}
38+
return;
39+
}
40+
41+
for (const key of Object.keys(value as Record<string, unknown>)) {
42+
walk((value as Record<string, unknown>)[key], seen, depth + 1);
43+
}
44+
}
45+
46+
export function collectTransferables(value: unknown): Transferable[] {
47+
const seen = new Set<ArrayBuffer>();
48+
walk(value, seen, 0);
49+
return Array.from(seen);
50+
}

packages/engines/src/lib/extract-transferables.ts

Lines changed: 0 additions & 40 deletions
This file was deleted.

packages/engines/src/lib/orchestrator/pdf-engine.ts

Lines changed: 32 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,9 @@ import {
4747
ImageDataLike,
4848
IPdfiumExecutor,
4949
AnnotationAppearanceMap,
50+
RenderPriority as Priority,
5051
} from '@embedpdf/models';
51-
import { WorkerTaskQueue, Priority } from './task-queue';
52+
import { WorkerTaskQueue } from './task-queue';
5253
import type { ImageDataConverter } from '../converters/types';
5354

5455
// Re-export for convenience
@@ -375,38 +376,18 @@ export class PdfEngine<T = Blob> implements IPdfEngine<T> {
375376
page: PdfPageObject,
376377
options?: PdfRenderPageAnnotationOptions,
377378
): PdfTask<AnnotationAppearanceMap<T>> {
378-
const resultTask = new Task<AnnotationAppearanceMap<T>, PdfErrorReason>();
379-
380-
const renderHandle = this.workerQueue.enqueue(
381-
{
382-
execute: () => this.executor.renderPageAnnotationsRaw(doc, page, options),
383-
meta: { docId: doc.id, pageIndex: page.index, operation: 'renderPageAnnotationsRaw' },
384-
},
385-
{ priority: Priority.MEDIUM },
386-
);
387-
388-
// Wire up abort: when resultTask is aborted, also abort the queue task
389-
const originalAbort = resultTask.abort.bind(resultTask);
390-
resultTask.abort = (reason) => {
391-
renderHandle.abort(reason);
392-
originalAbort(reason);
393-
};
394-
395-
renderHandle.wait(
396-
(rawMap) => {
397-
if (resultTask.state.stage !== 0 /* Pending */) {
398-
return;
399-
}
400-
this.encodeAppearanceMap(rawMap, options, resultTask);
401-
},
402-
(error) => {
403-
if (resultTask.state.stage === 0 /* Pending */) {
404-
resultTask.fail(error);
405-
}
406-
},
407-
);
408-
409-
return resultTask;
379+
return this.workerQueue
380+
.enqueue(
381+
{
382+
execute: () => this.executor.renderPageAnnotationsRaw(doc, page, options),
383+
meta: { docId: doc.id, pageIndex: page.index, operation: 'renderPageAnnotationsRaw' },
384+
},
385+
{ priority: Priority.MEDIUM },
386+
)
387+
.map(
388+
(rawMap) => this.encodeAppearanceMap(rawMap, options),
389+
(err: unknown) => ({ code: PdfErrorCode.Unknown, message: String(err) }),
390+
);
410391
}
411392

412393
renderPageAnnotationsRaw(
@@ -433,51 +414,24 @@ export class PdfEngine<T = Blob> implements IPdfEngine<T> {
433414
pageIndex?: number,
434415
priority: Priority = Priority.CRITICAL,
435416
): PdfTask<T> {
436-
const resultTask = new Task<T, PdfErrorReason>();
437-
438-
// Step 1: Add HIGH/MEDIUM priority task to render raw bytes
439-
const renderHandle = this.workerQueue.enqueue(
440-
{
441-
execute: () => renderFn(),
442-
meta: { docId, pageIndex, operation: 'render' },
443-
},
444-
{ priority },
445-
);
446-
447-
// Wire up abort: when resultTask is aborted, also abort the queue task
448-
const originalAbort = resultTask.abort.bind(resultTask);
449-
resultTask.abort = (reason) => {
450-
renderHandle.abort(reason); // Cancel the queue task!
451-
originalAbort(reason);
452-
};
453-
454-
renderHandle.wait(
455-
(rawImageData) => {
456-
// Check if resultTask was already aborted before encoding
457-
if (resultTask.state.stage !== 0 /* Pending */) {
458-
return;
459-
}
460-
this.encodeImage(rawImageData, options, resultTask);
461-
},
462-
(error) => {
463-
// Only forward error if resultTask is still pending
464-
if (resultTask.state.stage === 0 /* Pending */) {
465-
resultTask.fail(error);
466-
}
467-
},
468-
);
469-
470-
return resultTask;
417+
return this.workerQueue
418+
.enqueue(
419+
{
420+
execute: () => renderFn(),
421+
meta: { docId, pageIndex, operation: 'render' },
422+
},
423+
{ priority },
424+
)
425+
.map(
426+
(rawImageData) => this.encodeImage(rawImageData, options),
427+
(err: unknown) => ({ code: PdfErrorCode.Unknown, message: String(err) }),
428+
);
471429
}
472430

473431
/**
474432
* Encode image using encoder pool or inline
475433
*/
476-
private encodeImage(
477-
rawImageData: ImageDataLike,
478-
options: any,
479-
resultTask: Task<T, PdfErrorReason>,
480-
): void {
434+
private encodeImage(rawImageData: ImageDataLike, options: any): Promise<T> {
481435
const imageType = options?.imageType ?? 'image/webp';
482436
const quality = options?.quality;
483437

@@ -488,25 +442,16 @@ export class PdfEngine<T = Blob> implements IPdfEngine<T> {
488442
height: rawImageData.height,
489443
};
490444

491-
const sizeLabel = `${rawImageData.width}x${rawImageData.height}`;
492-
this.logger.perf(LOG_SOURCE, 'encodeImage', 'encode', 'Begin', sizeLabel);
493-
this.options
494-
.imageConverter(() => plainImageData, imageType, quality)
495-
.then((result) => {
496-
this.logger.perf(LOG_SOURCE, 'encodeImage', 'encode', 'End', sizeLabel);
497-
resultTask.resolve(result);
498-
})
499-
.catch((error) => resultTask.reject({ code: PdfErrorCode.Unknown, message: String(error) }));
445+
return this.options.imageConverter(() => plainImageData, imageType, quality);
500446
}
501447

502448
/**
503449
* Encode a full annotation appearance map to the output type T.
504450
*/
505-
private encodeAppearanceMap(
451+
private async encodeAppearanceMap(
506452
rawMap: AnnotationAppearanceMap<ImageDataLike>,
507453
options: PdfRenderPageAnnotationOptions | undefined,
508-
resultTask: Task<AnnotationAppearanceMap<T>, PdfErrorReason>,
509-
): void {
454+
): Promise<AnnotationAppearanceMap<T>> {
510455
const imageType = options?.imageType ?? 'image/webp';
511456
const quality = options?.imageQuality;
512457

@@ -542,17 +487,8 @@ export class PdfEngine<T = Blob> implements IPdfEngine<T> {
542487
}
543488
}
544489

545-
Promise.all(jobs)
546-
.then(() => {
547-
if (resultTask.state.stage === 0 /* Pending */) {
548-
resultTask.resolve(encodedMap);
549-
}
550-
})
551-
.catch((error) => {
552-
if (resultTask.state.stage === 0 /* Pending */) {
553-
resultTask.reject({ code: PdfErrorCode.Unknown, message: String(error) });
554-
}
555-
});
490+
await Promise.all(jobs);
491+
return encodedMap;
556492
}
557493

558494
// ========== Annotations ==========

packages/engines/src/lib/orchestrator/pdfium-native-runner.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Logger, NoopLogger, Task, TaskError, PdfErrorCode } from '@embedpdf/models';
22
import { PdfiumNative } from '../pdfium/engine';
33
import { init } from '@embedpdf/pdfium';
4-
import { extractTransferables } from '../extract-transferables';
4+
import { collectTransferables } from '../collect-transferables';
55

66
const LOG_SOURCE = 'PdfiumNativeRunner';
77
const LOG_CATEGORY = 'Worker';
@@ -256,7 +256,7 @@ export class PdfiumNativeRunner {
256256
*/
257257
private respond(response: WorkerResponse): void {
258258
this.logger.debug(LOG_SOURCE, LOG_CATEGORY, 'Sending response:', response.type);
259-
self.postMessage(response, { transfer: extractTransferables(response) });
259+
self.postMessage(response, { transfer: collectTransferables(response) });
260260
}
261261

262262
/**

packages/engines/src/lib/orchestrator/task-queue.ts

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,8 @@
1-
import { Task, TaskError, Logger, NoopLogger } from '@embedpdf/models';
1+
import { Task, Logger, NoopLogger, RenderPriority } from '@embedpdf/models';
22

33
const LOG_SOURCE = 'TaskQueue';
44
const LOG_CATEGORY = 'Queue';
55

6-
export enum Priority {
7-
CRITICAL = 3,
8-
HIGH = 2,
9-
MEDIUM = 1,
10-
LOW = 0,
11-
}
12-
136
// ============================================================================
147
// Type Utilities
158
// ============================================================================
@@ -35,14 +28,14 @@ export type ExtractTaskProgress<T> = T extends Task<any, any, infer P> ? P : nev
3528

3629
export interface QueuedTask<T extends Task<any, any, any>> {
3730
id: string;
38-
priority: Priority;
31+
priority: RenderPriority;
3932
meta?: Record<string, unknown>;
4033
executeFactory: () => T; // Factory function - called when it's time to execute!
4134
cancelled?: boolean;
4235
}
4336

4437
export interface EnqueueOptions {
45-
priority?: Priority;
38+
priority?: RenderPriority;
4639
meta?: Record<string, unknown>;
4740
fifo?: boolean;
4841
}
@@ -152,7 +145,7 @@ export class WorkerTaskQueue {
152145
* const task = queue.enqueue({
153146
* execute: () => this.executor.getMetadata(doc), // Factory - not called yet!
154147
* meta: { operation: 'getMetadata' }
155-
* }, { priority: Priority.LOW });
148+
* }, { priority: RenderPriority.LOW });
156149
*
157150
* The returned task has the SAME type as executor.getMetadata() would return!
158151
*/
@@ -164,7 +157,7 @@ export class WorkerTaskQueue {
164157
options: EnqueueOptions = {},
165158
): T {
166159
const id = this.generateId();
167-
const priority = options.priority ?? Priority.MEDIUM;
160+
const priority = options.priority ?? RenderPriority.MEDIUM;
168161

169162
// Create a proxy task that we return to the user
170163
// This task bridges to the real task that will be created later

packages/engines/src/lib/webworker/runner.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
PdfErrorCode,
1010
TaskReturn,
1111
} from '@embedpdf/models';
12-
import { extractTransferables } from '../extract-transferables';
12+
import { collectTransferables } from '../collect-transferables';
1313

1414
/**
1515
* Request body that represent method calls of PdfEngine, it contains the
@@ -473,6 +473,6 @@ export class EngineRunner {
473473
*/
474474
respond(response: Response) {
475475
this.logger.debug(LOG_SOURCE, LOG_CATEGORY, 'runner respond: ', response);
476-
self.postMessage(response, { transfer: extractTransferables(response) });
476+
self.postMessage(response, { transfer: collectTransferables(response) });
477477
}
478478
}

packages/models/src/pdf.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2919,6 +2919,17 @@ export interface PdfOpenDocumentUrlOptions {
29192919
normalizeRotation?: boolean;
29202920
}
29212921

2922+
/**
2923+
* Scheduling priority for render operations (higher = more urgent).
2924+
* Used by the orchestrator engine's task queue.
2925+
*/
2926+
export enum RenderPriority {
2927+
LOW = 0,
2928+
MEDIUM = 1,
2929+
HIGH = 2,
2930+
CRITICAL = 3,
2931+
}
2932+
29222933
export interface PdfRenderOptions {
29232934
/**
29242935
* Scale factor
@@ -2941,9 +2952,9 @@ export interface PdfRenderOptions {
29412952
*/
29422953
imageQuality?: number;
29432954
/**
2944-
* Scheduling priority (higher = more urgent). Only used by the orchestrator engine.
2955+
* Scheduling priority.
29452956
*/
2946-
priority?: number;
2957+
priority?: RenderPriority;
29472958
}
29482959

29492960
export interface ConvertToBlobOptions {

0 commit comments

Comments
 (0)