@papyrus-sdk/engine-pdfjs 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,12 +1,13 @@
1
1
  import { BaseDocumentEngine } from '@papyrus-sdk/core';
2
- import { DocumentSource, TextSelection, TextItem, OutlineItem } from '@papyrus-sdk/types';
2
+ import { DocumentLoadInput, TextSelection, TextItem, OutlineItem, PageDestination } from '@papyrus-sdk/types';
3
3
 
4
4
  declare class PDFJSEngine extends BaseDocumentEngine {
5
5
  private pdfDoc;
6
6
  private currentPage;
7
7
  private zoom;
8
8
  private rotation;
9
- load(source: DocumentSource): Promise<void>;
9
+ private renderTasks;
10
+ load(input: DocumentLoadInput): Promise<void>;
10
11
  getPageCount(): number;
11
12
  getCurrentPage(): number;
12
13
  goToPage(page: number): void;
@@ -28,11 +29,18 @@ declare class PDFJSEngine extends BaseDocumentEngine {
28
29
  renderTextLayer(pageIndex: number, container: any, scale: number): Promise<void>;
29
30
  getTextContent(pageIndex: number): Promise<TextItem[]>;
30
31
  getOutline(): Promise<OutlineItem[]>;
31
- getPageIndex(dest: any): Promise<number | null>;
32
+ getPageIndex(dest: PageDestination): Promise<number | null>;
32
33
  destroy(): void;
33
34
  private isUriSource;
34
35
  private isDataSource;
35
36
  private isFileLike;
37
+ private normalizeLoadInput;
38
+ private isLoadRequest;
39
+ private resolveSource;
40
+ private parseDataUri;
41
+ private decodeBase64;
42
+ private looksLikeUri;
43
+ private isLikelyBase64;
36
44
  }
37
45
 
38
46
  export { PDFJSEngine };
package/dist/index.d.ts CHANGED
@@ -1,12 +1,13 @@
1
1
  import { BaseDocumentEngine } from '@papyrus-sdk/core';
2
- import { DocumentSource, TextSelection, TextItem, OutlineItem } from '@papyrus-sdk/types';
2
+ import { DocumentLoadInput, TextSelection, TextItem, OutlineItem, PageDestination } from '@papyrus-sdk/types';
3
3
 
4
4
  declare class PDFJSEngine extends BaseDocumentEngine {
5
5
  private pdfDoc;
6
6
  private currentPage;
7
7
  private zoom;
8
8
  private rotation;
9
- load(source: DocumentSource): Promise<void>;
9
+ private renderTasks;
10
+ load(input: DocumentLoadInput): Promise<void>;
10
11
  getPageCount(): number;
11
12
  getCurrentPage(): number;
12
13
  goToPage(page: number): void;
@@ -28,11 +29,18 @@ declare class PDFJSEngine extends BaseDocumentEngine {
28
29
  renderTextLayer(pageIndex: number, container: any, scale: number): Promise<void>;
29
30
  getTextContent(pageIndex: number): Promise<TextItem[]>;
30
31
  getOutline(): Promise<OutlineItem[]>;
31
- getPageIndex(dest: any): Promise<number | null>;
32
+ getPageIndex(dest: PageDestination): Promise<number | null>;
32
33
  destroy(): void;
33
34
  private isUriSource;
34
35
  private isDataSource;
35
36
  private isFileLike;
37
+ private normalizeLoadInput;
38
+ private isLoadRequest;
39
+ private resolveSource;
40
+ private parseDataUri;
41
+ private decodeBase64;
42
+ private looksLikeUri;
43
+ private isLikelyBase64;
36
44
  }
37
45
 
38
46
  export { PDFJSEngine };
package/dist/index.js CHANGED
@@ -30,21 +30,15 @@ var PDFJSEngine = class extends import_core.BaseDocumentEngine {
30
30
  this.currentPage = 1;
31
31
  this.zoom = 1;
32
32
  this.rotation = 0;
33
+ this.renderTasks = /* @__PURE__ */ new WeakMap();
33
34
  }
34
- async load(source) {
35
+ async load(input) {
35
36
  try {
36
- let data;
37
- if (typeof source === "string") {
38
- data = source;
39
- } else if (this.isUriSource(source)) {
40
- data = source.uri;
41
- } else if (this.isDataSource(source)) {
42
- data = source.data;
43
- } else if (this.isFileLike(source)) {
44
- data = await source.arrayBuffer();
45
- } else {
46
- data = source;
37
+ const { source, type } = this.normalizeLoadInput(input);
38
+ if (type && type !== "pdf") {
39
+ throw new Error(`[PDFJSEngine] Tipo de documento n\xE3o suportado: ${type}`);
47
40
  }
41
+ const data = await this.resolveSource(source);
48
42
  this.pdfDoc = await pdfjsLib.getDocument(data).promise;
49
43
  this.currentPage = 1;
50
44
  } catch (error) {
@@ -97,7 +91,21 @@ var PDFJSEngine = class extends import_core.BaseDocumentEngine {
97
91
  canvas.width = viewport.width;
98
92
  const context = canvas.getContext("2d");
99
93
  if (!context) return;
100
- await page.render({ canvasContext: context, viewport }).promise;
94
+ const previousTask = this.renderTasks.get(canvas);
95
+ if (previousTask?.cancel) {
96
+ try {
97
+ previousTask.cancel();
98
+ } catch {
99
+ }
100
+ }
101
+ const renderTask = page.render({ canvasContext: context, viewport });
102
+ this.renderTasks.set(canvas, renderTask);
103
+ try {
104
+ await renderTask.promise;
105
+ } catch (error) {
106
+ if (error?.name === "RenderingCancelledException") return;
107
+ throw error;
108
+ }
101
109
  }
102
110
  async renderTextLayer(pageIndex, container, scale) {
103
111
  const element = container;
@@ -159,10 +167,23 @@ var PDFJSEngine = class extends import_core.BaseDocumentEngine {
159
167
  }
160
168
  async getPageIndex(dest) {
161
169
  if (!this.pdfDoc || !dest) return null;
170
+ if (typeof dest !== "string") {
171
+ if (dest.kind === "pageIndex") return dest.value;
172
+ if (dest.kind === "pageNumber") return Math.max(0, dest.value - 1);
173
+ if (dest.kind === "named") {
174
+ try {
175
+ const named = await this.pdfDoc.getDestination(dest.value);
176
+ return await this.pdfDoc.getPageIndex(named[0]);
177
+ } catch {
178
+ return null;
179
+ }
180
+ }
181
+ return null;
182
+ }
162
183
  try {
163
- const d = typeof dest === "string" ? await this.pdfDoc.getDestination(dest) : dest;
184
+ const d = await this.pdfDoc.getDestination(dest);
164
185
  return await this.pdfDoc.getPageIndex(d[0]);
165
- } catch (e) {
186
+ } catch {
166
187
  return null;
167
188
  }
168
189
  }
@@ -181,6 +202,63 @@ var PDFJSEngine = class extends import_core.BaseDocumentEngine {
181
202
  isFileLike(source) {
182
203
  return typeof source === "object" && source !== null && typeof source.arrayBuffer === "function";
183
204
  }
205
+ normalizeLoadInput(input) {
206
+ if (this.isLoadRequest(input)) {
207
+ return { source: input.source, type: input.type };
208
+ }
209
+ return { source: input };
210
+ }
211
+ isLoadRequest(input) {
212
+ return typeof input === "object" && input !== null && "source" in input && "type" in input;
213
+ }
214
+ async resolveSource(source) {
215
+ if (typeof source === "string") {
216
+ const dataUri = this.parseDataUri(source);
217
+ if (dataUri) {
218
+ return dataUri.isBase64 ? this.decodeBase64(dataUri.data) : dataUri.data;
219
+ }
220
+ if (this.looksLikeUri(source)) {
221
+ return source;
222
+ }
223
+ if (this.isLikelyBase64(source)) {
224
+ return this.decodeBase64(source);
225
+ }
226
+ return source;
227
+ }
228
+ if (this.isUriSource(source)) return source.uri;
229
+ if (this.isDataSource(source)) return source.data;
230
+ if (this.isFileLike(source)) return await source.arrayBuffer();
231
+ return source;
232
+ }
233
+ parseDataUri(value) {
234
+ const match = /^data:([^;,]+)?(;base64)?,(.*)$/.exec(value);
235
+ if (!match) return null;
236
+ const isBase64 = Boolean(match[2]);
237
+ const data = match[3] ?? "";
238
+ return { isBase64, data };
239
+ }
240
+ decodeBase64(value) {
241
+ const clean = value.replace(/\s/g, "");
242
+ if (typeof atob !== "function") {
243
+ throw new Error("[PDFJSEngine] atob n\xE3o est\xE1 dispon\xEDvel para decodificar base64.");
244
+ }
245
+ const binary = atob(clean);
246
+ const len = binary.length;
247
+ const bytes = new Uint8Array(len);
248
+ for (let i = 0; i < len; i += 1) {
249
+ bytes[i] = binary.charCodeAt(i);
250
+ }
251
+ return bytes;
252
+ }
253
+ looksLikeUri(value) {
254
+ return value.startsWith("http://") || value.startsWith("https://") || value.startsWith("/") || value.startsWith("./") || value.startsWith("../") || value.startsWith("file://");
255
+ }
256
+ isLikelyBase64(value) {
257
+ if (this.looksLikeUri(value)) return false;
258
+ if (value.includes(".")) return false;
259
+ if (value.length < 16) return false;
260
+ return /^[A-Za-z0-9+/=]+$/.test(value);
261
+ }
184
262
  };
185
263
  // Annotate the CommonJS export names for ESM import in node:
186
264
  0 && (module.exports = {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../index.ts"],"sourcesContent":["\r\nimport { BaseDocumentEngine } from '@papyrus-sdk/core';\r\nimport { DocumentSource, TextItem, OutlineItem, FileLike, TextSelection } from '@papyrus-sdk/types';\r\n\r\ndeclare const pdfjsLib: any;\r\n\r\nexport class PDFJSEngine extends BaseDocumentEngine {\r\n private pdfDoc: any = null;\r\n private currentPage: number = 1;\r\n private zoom: number = 1.0;\r\n private rotation: number = 0;\r\n\r\n async load(source: DocumentSource): Promise<void> {\r\n try {\r\n let data: any;\r\n if (typeof source === 'string') {\r\n data = source;\r\n } else if (this.isUriSource(source)) {\r\n data = source.uri;\r\n } else if (this.isDataSource(source)) {\r\n data = source.data;\r\n } else if (this.isFileLike(source)) {\r\n data = await source.arrayBuffer();\r\n } else {\r\n data = source;\r\n }\r\n\r\n this.pdfDoc = await pdfjsLib.getDocument(data).promise;\r\n this.currentPage = 1;\r\n } catch (error) { \r\n console.error(\"[PDFJSEngine] Erro ao carregar:\", error);\r\n throw error; \r\n }\r\n }\r\n\r\n getPageCount(): number { return this.pdfDoc ? this.pdfDoc.numPages : 0; }\r\n getCurrentPage(): number { return this.currentPage; }\r\n goToPage(page: number): void { if (page >= 1 && page <= this.getPageCount()) this.currentPage = page; }\r\n setZoom(zoom: number): void { this.zoom = Math.max(0.1, Math.min(5.0, zoom)); }\r\n getZoom(): number { return this.zoom; }\r\n \r\n rotate(direction: 'clockwise' | 'counterclockwise'): void {\r\n if (direction === 'clockwise') this.rotation = (this.rotation + 90) % 360;\r\n else { this.rotation = (this.rotation - 90) % 360; if (this.rotation < 0) this.rotation += 360; }\r\n }\r\n \r\n getRotation(): number { return this.rotation; }\r\n\r\n async getPageDimensions(pageIndex: number): Promise<{ width: number, height: number }> {\r\n if (!this.pdfDoc) return { width: 0, height: 0 };\r\n const page = await this.pdfDoc.getPage(pageIndex + 1);\r\n const viewport = page.getViewport({ scale: 1 });\r\n return { width: viewport.width, height: viewport.height };\r\n }\r\n\r\n async selectText(\r\n pageIndex: number,\r\n rect: { x: number; y: number; width: number; height: number }\r\n ): Promise<TextSelection | null> {\r\n void pageIndex;\r\n void rect;\r\n return null;\r\n }\r\n\r\n async renderPage(pageIndex: number, target: any, scale: number): Promise<void> {\r\n const canvas = target as HTMLCanvasElement;\r\n if (!this.pdfDoc || !canvas) return;\r\n \r\n const page = await this.pdfDoc.getPage(pageIndex + 1);\r\n const viewport = page.getViewport({ scale: scale * this.zoom, rotation: this.rotation });\r\n \r\n canvas.height = viewport.height; \r\n canvas.width = viewport.width;\r\n \r\n const context = canvas.getContext('2d');\r\n if (!context) return;\r\n\r\n await page.render({ canvasContext: context, viewport }).promise;\r\n }\r\n\r\n async renderTextLayer(pageIndex: number, container: any, scale: number): Promise<void> {\r\n const element = container as HTMLElement;\r\n if (!this.pdfDoc || !element) return;\r\n \r\n const page = await this.pdfDoc.getPage(pageIndex + 1);\r\n const viewport = page.getViewport({ scale: scale * this.zoom, rotation: this.rotation });\r\n const textContentSource = await page.getTextContent();\r\n \r\n element.style.width = `${viewport.width}px`;\r\n element.style.height = `${viewport.height}px`;\r\n element.style.setProperty('--scale-factor', viewport.scale.toString());\r\n \r\n await pdfjsLib.renderTextLayer({\r\n textContentSource,\r\n container: element,\r\n viewport,\r\n textDivs: []\r\n }).promise;\r\n }\r\n\r\n async getTextContent(pageIndex: number): Promise<TextItem[]> {\r\n if (!this.pdfDoc) return [];\r\n const page = await this.pdfDoc.getPage(pageIndex + 1);\r\n const content = await page.getTextContent();\r\n return content.items.map((item: any) => ({\r\n str: item.str, \r\n dir: item.dir, \r\n width: item.width, \r\n height: item.height,\r\n transform: item.transform, \r\n fontName: item.fontName,\r\n }));\r\n }\r\n\r\n async getOutline(): Promise<OutlineItem[]> {\r\n if (!this.pdfDoc) return [];\r\n const outline = await this.pdfDoc.getOutline();\r\n if (!outline || outline.length === 0) return [];\r\n\r\n const mapOutline = async (items: any[]): Promise<OutlineItem[]> => {\r\n const mapped = await Promise.all(\r\n items.map(async (item) => {\r\n const title = item.title || '';\r\n let pageIndex = -1;\r\n\r\n if (item.dest) {\r\n try {\r\n const dest = typeof item.dest === 'string' ? await this.pdfDoc.getDestination(item.dest) : item.dest;\r\n if (dest && dest[0]) {\r\n pageIndex = await this.pdfDoc.getPageIndex(dest[0]);\r\n }\r\n } catch {\r\n pageIndex = -1;\r\n }\r\n }\r\n\r\n const children = item.items ? await mapOutline(item.items) : [];\r\n const outlineItem: OutlineItem = { title, pageIndex };\r\n if (children.length > 0) outlineItem.children = children;\r\n return outlineItem;\r\n })\r\n );\r\n\r\n return mapped;\r\n };\r\n\r\n return mapOutline(outline);\r\n }\r\n\r\n async getPageIndex(dest: any): Promise<number | null> {\r\n if (!this.pdfDoc || !dest) return null;\r\n try {\r\n const d = typeof dest === 'string' ? await this.pdfDoc.getDestination(dest) : dest;\r\n return await this.pdfDoc.getPageIndex(d[0]);\r\n } catch (e) { return null; }\r\n }\r\n\r\n destroy(): void { if (this.pdfDoc) { this.pdfDoc.destroy(); this.pdfDoc = null; } }\r\n\r\n private isUriSource(source: DocumentSource): source is { uri: string } {\r\n return typeof source === 'object' && source !== null && 'uri' in source;\r\n }\r\n\r\n private isDataSource(source: DocumentSource): source is { data: ArrayBuffer | Uint8Array } {\r\n return typeof source === 'object' && source !== null && 'data' in source;\r\n }\r\n\r\n private isFileLike(source: DocumentSource): source is FileLike {\r\n return typeof source === 'object' && source !== null && typeof (source as FileLike).arrayBuffer === 'function';\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../index.ts"],"sourcesContent":["\r\nimport { BaseDocumentEngine } from '@papyrus-sdk/core';\r\nimport { DocumentLoadInput, DocumentLoadRequest, DocumentSource, DocumentType, TextItem, OutlineItem, FileLike, TextSelection, PageDestination } from '@papyrus-sdk/types';\r\n\r\ndeclare const pdfjsLib: any;\r\n\r\nexport class PDFJSEngine extends BaseDocumentEngine {\r\n private pdfDoc: any = null;\r\n private currentPage: number = 1;\r\n private zoom: number = 1.0;\r\n private rotation: number = 0;\r\n private renderTasks = new WeakMap<HTMLCanvasElement, any>();\r\n\r\n async load(input: DocumentLoadInput): Promise<void> {\r\n try {\r\n const { source, type } = this.normalizeLoadInput(input);\r\n if (type && type !== 'pdf') {\r\n throw new Error(`[PDFJSEngine] Tipo de documento não suportado: ${type}`);\r\n }\r\n\r\n const data = await this.resolveSource(source);\r\n\r\n this.pdfDoc = await pdfjsLib.getDocument(data).promise;\r\n this.currentPage = 1;\r\n } catch (error) { \r\n console.error(\"[PDFJSEngine] Erro ao carregar:\", error);\r\n throw error; \r\n }\r\n }\r\n\r\n getPageCount(): number { return this.pdfDoc ? this.pdfDoc.numPages : 0; }\r\n getCurrentPage(): number { return this.currentPage; }\r\n goToPage(page: number): void { if (page >= 1 && page <= this.getPageCount()) this.currentPage = page; }\r\n setZoom(zoom: number): void { this.zoom = Math.max(0.1, Math.min(5.0, zoom)); }\r\n getZoom(): number { return this.zoom; }\r\n \r\n rotate(direction: 'clockwise' | 'counterclockwise'): void {\r\n if (direction === 'clockwise') this.rotation = (this.rotation + 90) % 360;\r\n else { this.rotation = (this.rotation - 90) % 360; if (this.rotation < 0) this.rotation += 360; }\r\n }\r\n \r\n getRotation(): number { return this.rotation; }\r\n\r\n async getPageDimensions(pageIndex: number): Promise<{ width: number, height: number }> {\r\n if (!this.pdfDoc) return { width: 0, height: 0 };\r\n const page = await this.pdfDoc.getPage(pageIndex + 1);\r\n const viewport = page.getViewport({ scale: 1 });\r\n return { width: viewport.width, height: viewport.height };\r\n }\r\n\r\n async selectText(\r\n pageIndex: number,\r\n rect: { x: number; y: number; width: number; height: number }\r\n ): Promise<TextSelection | null> {\r\n void pageIndex;\r\n void rect;\r\n return null;\r\n }\r\n\r\n async renderPage(pageIndex: number, target: any, scale: number): Promise<void> {\r\n const canvas = target as HTMLCanvasElement;\r\n if (!this.pdfDoc || !canvas) return;\r\n \r\n const page = await this.pdfDoc.getPage(pageIndex + 1);\r\n const viewport = page.getViewport({ scale: scale * this.zoom, rotation: this.rotation });\r\n \r\n canvas.height = viewport.height; \r\n canvas.width = viewport.width;\r\n \r\n const context = canvas.getContext('2d');\r\n if (!context) return;\r\n\r\n const previousTask = this.renderTasks.get(canvas);\r\n if (previousTask?.cancel) {\r\n try { previousTask.cancel(); } catch { /* ignore */ }\r\n }\r\n\r\n const renderTask = page.render({ canvasContext: context, viewport });\r\n this.renderTasks.set(canvas, renderTask);\r\n try {\r\n await renderTask.promise;\r\n } catch (error: any) {\r\n if (error?.name === 'RenderingCancelledException') return;\r\n throw error;\r\n }\r\n }\r\n\r\n async renderTextLayer(pageIndex: number, container: any, scale: number): Promise<void> {\r\n const element = container as HTMLElement;\r\n if (!this.pdfDoc || !element) return;\r\n \r\n const page = await this.pdfDoc.getPage(pageIndex + 1);\r\n const viewport = page.getViewport({ scale: scale * this.zoom, rotation: this.rotation });\r\n const textContentSource = await page.getTextContent();\r\n \r\n element.style.width = `${viewport.width}px`;\r\n element.style.height = `${viewport.height}px`;\r\n element.style.setProperty('--scale-factor', viewport.scale.toString());\r\n \r\n await pdfjsLib.renderTextLayer({\r\n textContentSource,\r\n container: element,\r\n viewport,\r\n textDivs: []\r\n }).promise;\r\n }\r\n\r\n async getTextContent(pageIndex: number): Promise<TextItem[]> {\r\n if (!this.pdfDoc) return [];\r\n const page = await this.pdfDoc.getPage(pageIndex + 1);\r\n const content = await page.getTextContent();\r\n return content.items.map((item: any) => ({\r\n str: item.str, \r\n dir: item.dir, \r\n width: item.width, \r\n height: item.height,\r\n transform: item.transform, \r\n fontName: item.fontName,\r\n }));\r\n }\r\n\r\n async getOutline(): Promise<OutlineItem[]> {\r\n if (!this.pdfDoc) return [];\r\n const outline = await this.pdfDoc.getOutline();\r\n if (!outline || outline.length === 0) return [];\r\n\r\n const mapOutline = async (items: any[]): Promise<OutlineItem[]> => {\r\n const mapped = await Promise.all(\r\n items.map(async (item) => {\r\n const title = item.title || '';\r\n let pageIndex = -1;\r\n\r\n if (item.dest) {\r\n try {\r\n const dest = typeof item.dest === 'string' ? await this.pdfDoc.getDestination(item.dest) : item.dest;\r\n if (dest && dest[0]) {\r\n pageIndex = await this.pdfDoc.getPageIndex(dest[0]);\r\n }\r\n } catch {\r\n pageIndex = -1;\r\n }\r\n }\r\n\r\n const children = item.items ? await mapOutline(item.items) : [];\r\n const outlineItem: OutlineItem = { title, pageIndex };\r\n if (children.length > 0) outlineItem.children = children;\r\n return outlineItem;\r\n })\r\n );\r\n\r\n return mapped;\r\n };\r\n\r\n return mapOutline(outline);\r\n }\r\n\r\n async getPageIndex(dest: PageDestination): Promise<number | null> {\r\n if (!this.pdfDoc || !dest) return null;\r\n if (typeof dest !== 'string') {\r\n if (dest.kind === 'pageIndex') return dest.value;\r\n if (dest.kind === 'pageNumber') return Math.max(0, dest.value - 1);\r\n if (dest.kind === 'named') {\r\n try {\r\n const named = await this.pdfDoc.getDestination(dest.value);\r\n return await this.pdfDoc.getPageIndex(named[0]);\r\n } catch {\r\n return null;\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n try {\r\n const d = await this.pdfDoc.getDestination(dest);\r\n return await this.pdfDoc.getPageIndex(d[0]);\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n destroy(): void { if (this.pdfDoc) { this.pdfDoc.destroy(); this.pdfDoc = null; } }\r\n\r\n private isUriSource(source: DocumentSource): source is { uri: string } {\r\n return typeof source === 'object' && source !== null && 'uri' in source;\r\n }\r\n\r\n private isDataSource(source: DocumentSource): source is { data: ArrayBuffer | Uint8Array } {\r\n return typeof source === 'object' && source !== null && 'data' in source;\r\n }\r\n\r\n private isFileLike(source: DocumentSource): source is FileLike {\r\n return typeof source === 'object' && source !== null && typeof (source as FileLike).arrayBuffer === 'function';\r\n }\r\n\r\n private normalizeLoadInput(input: DocumentLoadInput): { source: DocumentSource; type?: DocumentType } {\r\n if (this.isLoadRequest(input)) {\r\n return { source: input.source, type: input.type };\r\n }\r\n return { source: input };\r\n }\r\n\r\n private isLoadRequest(input: DocumentLoadInput): input is DocumentLoadRequest {\r\n return typeof input === 'object' && input !== null && 'source' in input && 'type' in input;\r\n }\r\n\r\n private async resolveSource(source: DocumentSource): Promise<any> {\r\n if (typeof source === 'string') {\r\n const dataUri = this.parseDataUri(source);\r\n if (dataUri) {\r\n return dataUri.isBase64 ? this.decodeBase64(dataUri.data) : dataUri.data;\r\n }\r\n if (this.looksLikeUri(source)) {\r\n return source;\r\n }\r\n if (this.isLikelyBase64(source)) {\r\n return this.decodeBase64(source);\r\n }\r\n return source;\r\n }\r\n if (this.isUriSource(source)) return source.uri;\r\n if (this.isDataSource(source)) return source.data;\r\n if (this.isFileLike(source)) return await source.arrayBuffer();\r\n return source;\r\n }\r\n\r\n private parseDataUri(value: string): { isBase64: boolean; data: string } | null {\r\n const match = /^data:([^;,]+)?(;base64)?,(.*)$/.exec(value);\r\n if (!match) return null;\r\n const isBase64 = Boolean(match[2]);\r\n const data = match[3] ?? '';\r\n return { isBase64, data };\r\n }\r\n\r\n private decodeBase64(value: string): Uint8Array {\r\n const clean = value.replace(/\\s/g, '');\r\n if (typeof atob !== 'function') {\r\n throw new Error('[PDFJSEngine] atob não está disponível para decodificar base64.');\r\n }\r\n const binary = atob(clean);\r\n const len = binary.length;\r\n const bytes = new Uint8Array(len);\r\n for (let i = 0; i < len; i += 1) {\r\n bytes[i] = binary.charCodeAt(i);\r\n }\r\n return bytes;\r\n }\r\n\r\n private looksLikeUri(value: string): boolean {\r\n return (\r\n value.startsWith('http://') ||\r\n value.startsWith('https://') ||\r\n value.startsWith('/') ||\r\n value.startsWith('./') ||\r\n value.startsWith('../') ||\r\n value.startsWith('file://')\r\n );\r\n }\r\n\r\n private isLikelyBase64(value: string): boolean {\r\n if (this.looksLikeUri(value)) return false;\r\n if (value.includes('.')) return false;\r\n if (value.length < 16) return false;\r\n return /^[A-Za-z0-9+/=]+$/.test(value);\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
package/dist/index.mjs CHANGED
@@ -7,21 +7,15 @@ var PDFJSEngine = class extends BaseDocumentEngine {
7
7
  this.currentPage = 1;
8
8
  this.zoom = 1;
9
9
  this.rotation = 0;
10
+ this.renderTasks = /* @__PURE__ */ new WeakMap();
10
11
  }
11
- async load(source) {
12
+ async load(input) {
12
13
  try {
13
- let data;
14
- if (typeof source === "string") {
15
- data = source;
16
- } else if (this.isUriSource(source)) {
17
- data = source.uri;
18
- } else if (this.isDataSource(source)) {
19
- data = source.data;
20
- } else if (this.isFileLike(source)) {
21
- data = await source.arrayBuffer();
22
- } else {
23
- data = source;
14
+ const { source, type } = this.normalizeLoadInput(input);
15
+ if (type && type !== "pdf") {
16
+ throw new Error(`[PDFJSEngine] Tipo de documento n\xE3o suportado: ${type}`);
24
17
  }
18
+ const data = await this.resolveSource(source);
25
19
  this.pdfDoc = await pdfjsLib.getDocument(data).promise;
26
20
  this.currentPage = 1;
27
21
  } catch (error) {
@@ -74,7 +68,21 @@ var PDFJSEngine = class extends BaseDocumentEngine {
74
68
  canvas.width = viewport.width;
75
69
  const context = canvas.getContext("2d");
76
70
  if (!context) return;
77
- await page.render({ canvasContext: context, viewport }).promise;
71
+ const previousTask = this.renderTasks.get(canvas);
72
+ if (previousTask?.cancel) {
73
+ try {
74
+ previousTask.cancel();
75
+ } catch {
76
+ }
77
+ }
78
+ const renderTask = page.render({ canvasContext: context, viewport });
79
+ this.renderTasks.set(canvas, renderTask);
80
+ try {
81
+ await renderTask.promise;
82
+ } catch (error) {
83
+ if (error?.name === "RenderingCancelledException") return;
84
+ throw error;
85
+ }
78
86
  }
79
87
  async renderTextLayer(pageIndex, container, scale) {
80
88
  const element = container;
@@ -136,10 +144,23 @@ var PDFJSEngine = class extends BaseDocumentEngine {
136
144
  }
137
145
  async getPageIndex(dest) {
138
146
  if (!this.pdfDoc || !dest) return null;
147
+ if (typeof dest !== "string") {
148
+ if (dest.kind === "pageIndex") return dest.value;
149
+ if (dest.kind === "pageNumber") return Math.max(0, dest.value - 1);
150
+ if (dest.kind === "named") {
151
+ try {
152
+ const named = await this.pdfDoc.getDestination(dest.value);
153
+ return await this.pdfDoc.getPageIndex(named[0]);
154
+ } catch {
155
+ return null;
156
+ }
157
+ }
158
+ return null;
159
+ }
139
160
  try {
140
- const d = typeof dest === "string" ? await this.pdfDoc.getDestination(dest) : dest;
161
+ const d = await this.pdfDoc.getDestination(dest);
141
162
  return await this.pdfDoc.getPageIndex(d[0]);
142
- } catch (e) {
163
+ } catch {
143
164
  return null;
144
165
  }
145
166
  }
@@ -158,6 +179,63 @@ var PDFJSEngine = class extends BaseDocumentEngine {
158
179
  isFileLike(source) {
159
180
  return typeof source === "object" && source !== null && typeof source.arrayBuffer === "function";
160
181
  }
182
+ normalizeLoadInput(input) {
183
+ if (this.isLoadRequest(input)) {
184
+ return { source: input.source, type: input.type };
185
+ }
186
+ return { source: input };
187
+ }
188
+ isLoadRequest(input) {
189
+ return typeof input === "object" && input !== null && "source" in input && "type" in input;
190
+ }
191
+ async resolveSource(source) {
192
+ if (typeof source === "string") {
193
+ const dataUri = this.parseDataUri(source);
194
+ if (dataUri) {
195
+ return dataUri.isBase64 ? this.decodeBase64(dataUri.data) : dataUri.data;
196
+ }
197
+ if (this.looksLikeUri(source)) {
198
+ return source;
199
+ }
200
+ if (this.isLikelyBase64(source)) {
201
+ return this.decodeBase64(source);
202
+ }
203
+ return source;
204
+ }
205
+ if (this.isUriSource(source)) return source.uri;
206
+ if (this.isDataSource(source)) return source.data;
207
+ if (this.isFileLike(source)) return await source.arrayBuffer();
208
+ return source;
209
+ }
210
+ parseDataUri(value) {
211
+ const match = /^data:([^;,]+)?(;base64)?,(.*)$/.exec(value);
212
+ if (!match) return null;
213
+ const isBase64 = Boolean(match[2]);
214
+ const data = match[3] ?? "";
215
+ return { isBase64, data };
216
+ }
217
+ decodeBase64(value) {
218
+ const clean = value.replace(/\s/g, "");
219
+ if (typeof atob !== "function") {
220
+ throw new Error("[PDFJSEngine] atob n\xE3o est\xE1 dispon\xEDvel para decodificar base64.");
221
+ }
222
+ const binary = atob(clean);
223
+ const len = binary.length;
224
+ const bytes = new Uint8Array(len);
225
+ for (let i = 0; i < len; i += 1) {
226
+ bytes[i] = binary.charCodeAt(i);
227
+ }
228
+ return bytes;
229
+ }
230
+ looksLikeUri(value) {
231
+ return value.startsWith("http://") || value.startsWith("https://") || value.startsWith("/") || value.startsWith("./") || value.startsWith("../") || value.startsWith("file://");
232
+ }
233
+ isLikelyBase64(value) {
234
+ if (this.looksLikeUri(value)) return false;
235
+ if (value.includes(".")) return false;
236
+ if (value.length < 16) return false;
237
+ return /^[A-Za-z0-9+/=]+$/.test(value);
238
+ }
161
239
  };
162
240
  export {
163
241
  PDFJSEngine
@@ -1 +1 @@
1
- {"version":3,"sources":["../index.ts"],"sourcesContent":["\r\nimport { BaseDocumentEngine } from '@papyrus-sdk/core';\r\nimport { DocumentSource, TextItem, OutlineItem, FileLike, TextSelection } from '@papyrus-sdk/types';\r\n\r\ndeclare const pdfjsLib: any;\r\n\r\nexport class PDFJSEngine extends BaseDocumentEngine {\r\n private pdfDoc: any = null;\r\n private currentPage: number = 1;\r\n private zoom: number = 1.0;\r\n private rotation: number = 0;\r\n\r\n async load(source: DocumentSource): Promise<void> {\r\n try {\r\n let data: any;\r\n if (typeof source === 'string') {\r\n data = source;\r\n } else if (this.isUriSource(source)) {\r\n data = source.uri;\r\n } else if (this.isDataSource(source)) {\r\n data = source.data;\r\n } else if (this.isFileLike(source)) {\r\n data = await source.arrayBuffer();\r\n } else {\r\n data = source;\r\n }\r\n\r\n this.pdfDoc = await pdfjsLib.getDocument(data).promise;\r\n this.currentPage = 1;\r\n } catch (error) { \r\n console.error(\"[PDFJSEngine] Erro ao carregar:\", error);\r\n throw error; \r\n }\r\n }\r\n\r\n getPageCount(): number { return this.pdfDoc ? this.pdfDoc.numPages : 0; }\r\n getCurrentPage(): number { return this.currentPage; }\r\n goToPage(page: number): void { if (page >= 1 && page <= this.getPageCount()) this.currentPage = page; }\r\n setZoom(zoom: number): void { this.zoom = Math.max(0.1, Math.min(5.0, zoom)); }\r\n getZoom(): number { return this.zoom; }\r\n \r\n rotate(direction: 'clockwise' | 'counterclockwise'): void {\r\n if (direction === 'clockwise') this.rotation = (this.rotation + 90) % 360;\r\n else { this.rotation = (this.rotation - 90) % 360; if (this.rotation < 0) this.rotation += 360; }\r\n }\r\n \r\n getRotation(): number { return this.rotation; }\r\n\r\n async getPageDimensions(pageIndex: number): Promise<{ width: number, height: number }> {\r\n if (!this.pdfDoc) return { width: 0, height: 0 };\r\n const page = await this.pdfDoc.getPage(pageIndex + 1);\r\n const viewport = page.getViewport({ scale: 1 });\r\n return { width: viewport.width, height: viewport.height };\r\n }\r\n\r\n async selectText(\r\n pageIndex: number,\r\n rect: { x: number; y: number; width: number; height: number }\r\n ): Promise<TextSelection | null> {\r\n void pageIndex;\r\n void rect;\r\n return null;\r\n }\r\n\r\n async renderPage(pageIndex: number, target: any, scale: number): Promise<void> {\r\n const canvas = target as HTMLCanvasElement;\r\n if (!this.pdfDoc || !canvas) return;\r\n \r\n const page = await this.pdfDoc.getPage(pageIndex + 1);\r\n const viewport = page.getViewport({ scale: scale * this.zoom, rotation: this.rotation });\r\n \r\n canvas.height = viewport.height; \r\n canvas.width = viewport.width;\r\n \r\n const context = canvas.getContext('2d');\r\n if (!context) return;\r\n\r\n await page.render({ canvasContext: context, viewport }).promise;\r\n }\r\n\r\n async renderTextLayer(pageIndex: number, container: any, scale: number): Promise<void> {\r\n const element = container as HTMLElement;\r\n if (!this.pdfDoc || !element) return;\r\n \r\n const page = await this.pdfDoc.getPage(pageIndex + 1);\r\n const viewport = page.getViewport({ scale: scale * this.zoom, rotation: this.rotation });\r\n const textContentSource = await page.getTextContent();\r\n \r\n element.style.width = `${viewport.width}px`;\r\n element.style.height = `${viewport.height}px`;\r\n element.style.setProperty('--scale-factor', viewport.scale.toString());\r\n \r\n await pdfjsLib.renderTextLayer({\r\n textContentSource,\r\n container: element,\r\n viewport,\r\n textDivs: []\r\n }).promise;\r\n }\r\n\r\n async getTextContent(pageIndex: number): Promise<TextItem[]> {\r\n if (!this.pdfDoc) return [];\r\n const page = await this.pdfDoc.getPage(pageIndex + 1);\r\n const content = await page.getTextContent();\r\n return content.items.map((item: any) => ({\r\n str: item.str, \r\n dir: item.dir, \r\n width: item.width, \r\n height: item.height,\r\n transform: item.transform, \r\n fontName: item.fontName,\r\n }));\r\n }\r\n\r\n async getOutline(): Promise<OutlineItem[]> {\r\n if (!this.pdfDoc) return [];\r\n const outline = await this.pdfDoc.getOutline();\r\n if (!outline || outline.length === 0) return [];\r\n\r\n const mapOutline = async (items: any[]): Promise<OutlineItem[]> => {\r\n const mapped = await Promise.all(\r\n items.map(async (item) => {\r\n const title = item.title || '';\r\n let pageIndex = -1;\r\n\r\n if (item.dest) {\r\n try {\r\n const dest = typeof item.dest === 'string' ? await this.pdfDoc.getDestination(item.dest) : item.dest;\r\n if (dest && dest[0]) {\r\n pageIndex = await this.pdfDoc.getPageIndex(dest[0]);\r\n }\r\n } catch {\r\n pageIndex = -1;\r\n }\r\n }\r\n\r\n const children = item.items ? await mapOutline(item.items) : [];\r\n const outlineItem: OutlineItem = { title, pageIndex };\r\n if (children.length > 0) outlineItem.children = children;\r\n return outlineItem;\r\n })\r\n );\r\n\r\n return mapped;\r\n };\r\n\r\n return mapOutline(outline);\r\n }\r\n\r\n async getPageIndex(dest: any): Promise<number | null> {\r\n if (!this.pdfDoc || !dest) return null;\r\n try {\r\n const d = typeof dest === 'string' ? await this.pdfDoc.getDestination(dest) : dest;\r\n return await this.pdfDoc.getPageIndex(d[0]);\r\n } catch (e) { return null; }\r\n }\r\n\r\n destroy(): void { if (this.pdfDoc) { this.pdfDoc.destroy(); this.pdfDoc = null; } }\r\n\r\n private isUriSource(source: DocumentSource): source is { uri: string } {\r\n return typeof source === 'object' && source !== null && 'uri' in source;\r\n }\r\n\r\n private isDataSource(source: DocumentSource): source is { data: ArrayBuffer | Uint8Array } {\r\n return typeof source === 'object' && source !== null && 'data' in source;\r\n }\r\n\r\n private isFileLike(source: DocumentSource): source is FileLike {\r\n return typeof source === 'object' && source !== null && typeof (source as FileLike).arrayBuffer === 'function';\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../index.ts"],"sourcesContent":["\r\nimport { BaseDocumentEngine } from '@papyrus-sdk/core';\r\nimport { DocumentLoadInput, DocumentLoadRequest, DocumentSource, DocumentType, TextItem, OutlineItem, FileLike, TextSelection, PageDestination } from '@papyrus-sdk/types';\r\n\r\ndeclare const pdfjsLib: any;\r\n\r\nexport class PDFJSEngine extends BaseDocumentEngine {\r\n private pdfDoc: any = null;\r\n private currentPage: number = 1;\r\n private zoom: number = 1.0;\r\n private rotation: number = 0;\r\n private renderTasks = new WeakMap<HTMLCanvasElement, any>();\r\n\r\n async load(input: DocumentLoadInput): Promise<void> {\r\n try {\r\n const { source, type } = this.normalizeLoadInput(input);\r\n if (type && type !== 'pdf') {\r\n throw new Error(`[PDFJSEngine] Tipo de documento não suportado: ${type}`);\r\n }\r\n\r\n const data = await this.resolveSource(source);\r\n\r\n this.pdfDoc = await pdfjsLib.getDocument(data).promise;\r\n this.currentPage = 1;\r\n } catch (error) { \r\n console.error(\"[PDFJSEngine] Erro ao carregar:\", error);\r\n throw error; \r\n }\r\n }\r\n\r\n getPageCount(): number { return this.pdfDoc ? this.pdfDoc.numPages : 0; }\r\n getCurrentPage(): number { return this.currentPage; }\r\n goToPage(page: number): void { if (page >= 1 && page <= this.getPageCount()) this.currentPage = page; }\r\n setZoom(zoom: number): void { this.zoom = Math.max(0.1, Math.min(5.0, zoom)); }\r\n getZoom(): number { return this.zoom; }\r\n \r\n rotate(direction: 'clockwise' | 'counterclockwise'): void {\r\n if (direction === 'clockwise') this.rotation = (this.rotation + 90) % 360;\r\n else { this.rotation = (this.rotation - 90) % 360; if (this.rotation < 0) this.rotation += 360; }\r\n }\r\n \r\n getRotation(): number { return this.rotation; }\r\n\r\n async getPageDimensions(pageIndex: number): Promise<{ width: number, height: number }> {\r\n if (!this.pdfDoc) return { width: 0, height: 0 };\r\n const page = await this.pdfDoc.getPage(pageIndex + 1);\r\n const viewport = page.getViewport({ scale: 1 });\r\n return { width: viewport.width, height: viewport.height };\r\n }\r\n\r\n async selectText(\r\n pageIndex: number,\r\n rect: { x: number; y: number; width: number; height: number }\r\n ): Promise<TextSelection | null> {\r\n void pageIndex;\r\n void rect;\r\n return null;\r\n }\r\n\r\n async renderPage(pageIndex: number, target: any, scale: number): Promise<void> {\r\n const canvas = target as HTMLCanvasElement;\r\n if (!this.pdfDoc || !canvas) return;\r\n \r\n const page = await this.pdfDoc.getPage(pageIndex + 1);\r\n const viewport = page.getViewport({ scale: scale * this.zoom, rotation: this.rotation });\r\n \r\n canvas.height = viewport.height; \r\n canvas.width = viewport.width;\r\n \r\n const context = canvas.getContext('2d');\r\n if (!context) return;\r\n\r\n const previousTask = this.renderTasks.get(canvas);\r\n if (previousTask?.cancel) {\r\n try { previousTask.cancel(); } catch { /* ignore */ }\r\n }\r\n\r\n const renderTask = page.render({ canvasContext: context, viewport });\r\n this.renderTasks.set(canvas, renderTask);\r\n try {\r\n await renderTask.promise;\r\n } catch (error: any) {\r\n if (error?.name === 'RenderingCancelledException') return;\r\n throw error;\r\n }\r\n }\r\n\r\n async renderTextLayer(pageIndex: number, container: any, scale: number): Promise<void> {\r\n const element = container as HTMLElement;\r\n if (!this.pdfDoc || !element) return;\r\n \r\n const page = await this.pdfDoc.getPage(pageIndex + 1);\r\n const viewport = page.getViewport({ scale: scale * this.zoom, rotation: this.rotation });\r\n const textContentSource = await page.getTextContent();\r\n \r\n element.style.width = `${viewport.width}px`;\r\n element.style.height = `${viewport.height}px`;\r\n element.style.setProperty('--scale-factor', viewport.scale.toString());\r\n \r\n await pdfjsLib.renderTextLayer({\r\n textContentSource,\r\n container: element,\r\n viewport,\r\n textDivs: []\r\n }).promise;\r\n }\r\n\r\n async getTextContent(pageIndex: number): Promise<TextItem[]> {\r\n if (!this.pdfDoc) return [];\r\n const page = await this.pdfDoc.getPage(pageIndex + 1);\r\n const content = await page.getTextContent();\r\n return content.items.map((item: any) => ({\r\n str: item.str, \r\n dir: item.dir, \r\n width: item.width, \r\n height: item.height,\r\n transform: item.transform, \r\n fontName: item.fontName,\r\n }));\r\n }\r\n\r\n async getOutline(): Promise<OutlineItem[]> {\r\n if (!this.pdfDoc) return [];\r\n const outline = await this.pdfDoc.getOutline();\r\n if (!outline || outline.length === 0) return [];\r\n\r\n const mapOutline = async (items: any[]): Promise<OutlineItem[]> => {\r\n const mapped = await Promise.all(\r\n items.map(async (item) => {\r\n const title = item.title || '';\r\n let pageIndex = -1;\r\n\r\n if (item.dest) {\r\n try {\r\n const dest = typeof item.dest === 'string' ? await this.pdfDoc.getDestination(item.dest) : item.dest;\r\n if (dest && dest[0]) {\r\n pageIndex = await this.pdfDoc.getPageIndex(dest[0]);\r\n }\r\n } catch {\r\n pageIndex = -1;\r\n }\r\n }\r\n\r\n const children = item.items ? await mapOutline(item.items) : [];\r\n const outlineItem: OutlineItem = { title, pageIndex };\r\n if (children.length > 0) outlineItem.children = children;\r\n return outlineItem;\r\n })\r\n );\r\n\r\n return mapped;\r\n };\r\n\r\n return mapOutline(outline);\r\n }\r\n\r\n async getPageIndex(dest: PageDestination): Promise<number | null> {\r\n if (!this.pdfDoc || !dest) return null;\r\n if (typeof dest !== 'string') {\r\n if (dest.kind === 'pageIndex') return dest.value;\r\n if (dest.kind === 'pageNumber') return Math.max(0, dest.value - 1);\r\n if (dest.kind === 'named') {\r\n try {\r\n const named = await this.pdfDoc.getDestination(dest.value);\r\n return await this.pdfDoc.getPageIndex(named[0]);\r\n } catch {\r\n return null;\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n try {\r\n const d = await this.pdfDoc.getDestination(dest);\r\n return await this.pdfDoc.getPageIndex(d[0]);\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n destroy(): void { if (this.pdfDoc) { this.pdfDoc.destroy(); this.pdfDoc = null; } }\r\n\r\n private isUriSource(source: DocumentSource): source is { uri: string } {\r\n return typeof source === 'object' && source !== null && 'uri' in source;\r\n }\r\n\r\n private isDataSource(source: DocumentSource): source is { data: ArrayBuffer | Uint8Array } {\r\n return typeof source === 'object' && source !== null && 'data' in source;\r\n }\r\n\r\n private isFileLike(source: DocumentSource): source is FileLike {\r\n return typeof source === 'object' && source !== null && typeof (source as FileLike).arrayBuffer === 'function';\r\n }\r\n\r\n private normalizeLoadInput(input: DocumentLoadInput): { source: DocumentSource; type?: DocumentType } {\r\n if (this.isLoadRequest(input)) {\r\n return { source: input.source, type: input.type };\r\n }\r\n return { source: input };\r\n }\r\n\r\n private isLoadRequest(input: DocumentLoadInput): input is DocumentLoadRequest {\r\n return typeof input === 'object' && input !== null && 'source' in input && 'type' in input;\r\n }\r\n\r\n private async resolveSource(source: DocumentSource): Promise<any> {\r\n if (typeof source === 'string') {\r\n const dataUri = this.parseDataUri(source);\r\n if (dataUri) {\r\n return dataUri.isBase64 ? this.decodeBase64(dataUri.data) : dataUri.data;\r\n }\r\n if (this.looksLikeUri(source)) {\r\n return source;\r\n }\r\n if (this.isLikelyBase64(source)) {\r\n return this.decodeBase64(source);\r\n }\r\n return source;\r\n }\r\n if (this.isUriSource(source)) return source.uri;\r\n if (this.isDataSource(source)) return source.data;\r\n if (this.isFileLike(source)) return await source.arrayBuffer();\r\n return source;\r\n }\r\n\r\n private parseDataUri(value: string): { isBase64: boolean; data: string } | null {\r\n const match = /^data:([^;,]+)?(;base64)?,(.*)$/.exec(value);\r\n if (!match) return null;\r\n const isBase64 = Boolean(match[2]);\r\n const data = match[3] ?? '';\r\n return { isBase64, data };\r\n }\r\n\r\n private decodeBase64(value: string): Uint8Array {\r\n const clean = value.replace(/\\s/g, '');\r\n if (typeof atob !== 'function') {\r\n throw new Error('[PDFJSEngine] atob não está disponível para decodificar base64.');\r\n }\r\n const binary = atob(clean);\r\n const len = binary.length;\r\n const bytes = new Uint8Array(len);\r\n for (let i = 0; i < len; i += 1) {\r\n bytes[i] = binary.charCodeAt(i);\r\n }\r\n return bytes;\r\n }\r\n\r\n private looksLikeUri(value: string): boolean {\r\n return (\r\n value.startsWith('http://') ||\r\n value.startsWith('https://') ||\r\n value.startsWith('/') ||\r\n value.startsWith('./') ||\r\n value.startsWith('../') ||\r\n value.startsWith('file://')\r\n );\r\n }\r\n\r\n private isLikelyBase64(value: string): boolean {\r\n if (this.looksLikeUri(value)) return false;\r\n if (value.includes('.')) return false;\r\n if (value.length < 16) return false;\r\n return /^[A-Za-z0-9+/=]+$/.test(value);\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@papyrus-sdk/engine-pdfjs",
3
- "version": "0.1.0",
4
- "main": "dist/index.cjs",
3
+ "version": "0.1.2",
4
+ "main": "dist/index.js",
5
5
  "module": "dist/index.mjs",
6
6
  "types": "dist/index.d.ts",
7
7
  "exports": {
8
8
  ".": {
9
9
  "types": "./dist/index.d.ts",
10
10
  "import": "./dist/index.mjs",
11
- "require": "./dist/index.cjs"
11
+ "require": "./dist/index.js"
12
12
  }
13
13
  },
14
14
  "files": [
@@ -18,8 +18,8 @@
18
18
  "access": "public"
19
19
  },
20
20
  "dependencies": {
21
- "@papyrus-sdk/core": "0.1.0",
22
- "@papyrus-sdk/types": "0.1.0"
21
+ "@papyrus-sdk/core": "0.1.2",
22
+ "@papyrus-sdk/types": "0.1.2"
23
23
  },
24
24
  "scripts": {
25
25
  "build": "tsup index.ts --dts --format cjs,esm --out-dir dist --clean --sourcemap"