teamsync-pdf-viewer 2.2.1 → 2.2.3

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/CHANGELOG.md CHANGED
@@ -2,7 +2,74 @@
2
2
 
3
3
  All notable changes to `teamsync-pdf-viewer` are documented here.
4
4
 
5
- ## [2.2.1] — 2026-11-03
5
+ ## [2.2.3] — 2026-11-08
6
+
7
+ ### Performance & Loading Optimizations
8
+ - **Lazy Page-Dimension Scanning**:
9
+ - Deferred scanning page dimensions for pages 2 through $N$ until after Page 1 has completed its first canvas paint (`onFirstPageRendered`).
10
+ - Replaced eager 25-page parallel Promise batches with background idle slices (6 pages per slice via `requestIdleCallback`) to eliminate network contention on document open.
11
+ - Applied slice-level scroll offset compensation (`delta = newTop - oldTop`) in continuous mode to prevent layout jumps when non-uniform pages are measured.
12
+ - **Viewport-Gated Text & Link Extraction**:
13
+ - `fetchText()` and `fetchNativeLinks()` now run only for pages currently in view (`isInViewport`) or that have previously rendered.
14
+ - Off-screen virtualization buffer rows no longer issue concurrent network requests for text content, fonts, and annotation dictionaries on mount.
15
+ - Extracted text and links are cached in component state, eliminating redundant network reads when scrolling back into view.
16
+ - **Shared PDF.js Worker Lifecycle & Pre-Warming**:
17
+ - Added support for passing an explicit `worker?: pdfjsLib.PDFWorker` instance to `<TeamSyncViewer>`, `<DocumentViewer>`, and `createWebViewer()`.
18
+ - Added `createPdfWorker()`, `getSharedPdfWorker()`, and `destroySharedPdfWorker()` helpers in `src/core/pdfAssets.ts` for host idle warm-up.
19
+ - Reused a persistent shared worker singleton when none is passed, eliminating the 1.2 MB worker script re-evaluation overhead on every document load, retry, or split pane.
20
+ - Added self-healing recovery that automatically instantiates a fresh worker if `worker.destroyed` is detected.
21
+ - **Single-Pass Initial Fit Scale**:
22
+ - Pre-calculates target `fit-width` and `fit-page` scale as soon as Page 1 dimensions and container width are retrieved in `loadPdf`.
23
+ - Page 1 paints directly at the fitted scale on its initial canvas render, eliminating double-rendering and scale flicker.
24
+ - **Optimized HTTP/2 Network Defaults**:
25
+ - Defaulted `disableStream: true` in `resolveNetworkParams()`, aborting full-file HTTP 200 download streams after headers to prioritize HTTP 206 range reads for Page 1.
26
+ - Defaulted `rangeChunkSize: 524288` (512 KiB) to minimize round-trip overhead on high-latency links. Explicit host props continue to override defaults.
27
+ - **Load Telemetry Reporting**:
28
+ - Added `LoadProgressInfo` interface reporting `{ bytesLoaded, totalBytes, rangeRequests }`.
29
+ - Hooked `loadingTask.onProgress` to emit progress telemetry through `onLoadProgress` and the event bus (`loadProgress`).
30
+ - Included telemetry payload in `onFirstPageRendered` and `firstPageRendered` event to measure first-page render performance.
31
+
32
+ ## [2.2.2] — 2026-11-05
33
+
34
+ ### Added & Enhanced
35
+ - **AcroForm In-Place Updates & Round-Trip Export (F1)**:
36
+ - Form fields already present in a PDF are updated in-place during export via `form.getFields()` rather than failing with `FieldAlreadyExistsError` or skipping value updates.
37
+ - **Interactive Radio Group Export (F2)**:
38
+ - Radio options are exported into native interactive PDF radio groups using `form.createRadioGroup()` with calculated bounding boxes, Helvetica text labels, and selection state.
39
+ - **Hierarchical Checklist Export (F3)**:
40
+ - Multi-select checklist fields export with standardized hierarchical naming (`fieldName.OptionName`) and drawn text labels.
41
+ - **Clean Signature Page Stream & Flatten Option (F4, F5)**:
42
+ - Unsigned signature placeholders no longer burn permanent ink artifacts onto the PDF content stream unless `flatten: true` is explicitly configured in `getFileData()`.
43
+ - Added `field.readOnly` checkbox in `FormFieldEditorModal` locking fields against modification, and enforced `enableReadOnly()` on AcroForms.
44
+ - Added `{ flatten?: boolean }` export option to flatten interactive fields into static page content when desired.
45
+ - **Duplicate Field Key Collision Prevention (F6)**:
46
+ - Added duplicate name detection banner in the field configuration modal and deterministic suffix naming (`name_1`, `name_2`) during export to prevent collisions.
47
+ - **Electronic vs Digital Signature Clarification (F7, F10)**:
48
+ - Electronic signatures are explicitly labeled `"Signed electronically by ..."` without misrepresenting visual signatures as digital certificates.
49
+ - Removed misleading pseudo-random hex strings; digital certificate signatures now show genuine status indicators.
50
+ - Strict signature value validation rejecting raw strings (e.g. `[object Object]` or `hello`) while accepting structured signature objects and Base64 images.
51
+ - **Manager-Level Role Locking & Security (F8)**:
52
+ - `FormManager` enforces role assignment and read-only checks on `setValue()` and `setValues()`, blocking unauthorized edits unless `{ force: true }` is passed.
53
+ - **Proportional Option Font Scaling (F9)**:
54
+ - Replaced rigid 10px minimum clamp on radio and checklist options with proportional scaling down to 7px, eliminating overflow clipping and scrollbars on zoom-out.
55
+ - **Aligned Validation & Unassigned Role Policies (F11)**:
56
+ - Configurable `unassignedFieldsRole` (`'all' | 'none' | roleId`) ensuring completion counters and `validate()` agree. Validation errors now include role names (e.g., `(Buyer)`).
57
+ - **Native AcroForm & XFDF Form Ingestion (F12, F13)**:
58
+ - Introduced `extractAcroFormFields` to detect and parse existing PDF `Widget` annotations into interactive form field models.
59
+ - Introduced `parseXfdfFormFields` to parse XFDF `<widget>` and `<field>` tags directly into `FormManager` without creating dead grey outline annotations.
60
+ - **Form Role Metadata (F14)**:
61
+ - Added `partyType` (`'signer' | 'viewer' | 'notary'`), `signingOrder`, and custom `metadata` to `FormRole`.
62
+ - **Programmatic Tab Navigation & Granular Events (F15, F18)**:
63
+ - Added `instance.UI.setActiveTab(tab)` and `instance.UI.getActiveTab()` with `tabChanged` event emission.
64
+ - Added granular event hooks: `fieldValueChanged`, `signatureApplied`, `signatureCleared`, `fieldAdded`, `fieldRemoved`, `fieldUpdated`.
65
+ - **Role Field Highlighting (F16)**:
66
+ - Added `instance.highlightRoleFields(roleId)` with accent glow across matching fields.
67
+ - **Adopted Signature Caching & 1-Click Sign All (F17)**:
68
+ - Added session-level adopted signature persistence with 1-click application across all pending signature fields for the active role.
69
+ - **Prop Synchronization & Undo Isolation (F19)**:
70
+ - Props passed to `<TeamSyncViewer>` (`formFields`, `formData`) synchronize cleanly without resetting state or polluting undo history stacks.
71
+ - **Dynamic Schema Versioning (F20)**:
72
+ - Exported field templates now dynamically reflect library version `2.2.2`.
6
73
 
7
74
  ### Security
8
75
  - **Cryptographically Secure Identifier Generation**: Replaced pseudo-random number generator routines with cryptographically secure random values (`crypto.randomUUID()` and `crypto.getRandomValues()`) across fallback blob URLs, manual redactions, and form roles, resolving CodeQL alert CWE-338.
package/README.md CHANGED
@@ -78,7 +78,7 @@ Explore detailed SDK guides, parameter options, code snippets, and architecture
78
78
 
79
79
  ---
80
80
 
81
- ## ✨ Uncompromised Feature Set
81
+ ## ✨ Feature Set
82
82
 
83
83
  Everything you need to build collaborative, secure document workflows.
84
84
 
@@ -31,6 +31,8 @@ export declare class AnnotationManager {
31
31
  private readOnly;
32
32
  private canEditOthers;
33
33
  private resolver;
34
+ private formManager;
35
+ setFormManager(fm: any): void;
34
36
  setDocument(doc: PDFDocumentProxy | null): void;
35
37
  hasDocument(): boolean;
36
38
  setCurrentUser(name: string, id?: string): void;
@@ -1,4 +1,5 @@
1
1
  import { Annotation } from './types';
2
+ import { FormField, FormDataRecord } from '../forms/types';
2
3
  import { GeometryResolver } from './geometry';
3
4
  export declare const XFDF_NS = "http://ns.adobe.com/xfdf/";
4
5
  export interface XfdfExportOptions {
@@ -16,3 +17,10 @@ export declare function annotationToXfdfFragment(a: Annotation, resolve: Geometr
16
17
  /** Serialize annotations to a complete XFDF document. */
17
18
  export declare function annotationsToXfdf(annotations: Annotation[], resolve: GeometryResolver, opts?: XfdfExportOptions): Promise<string>;
18
19
  export declare function parseXfdf(xml: string, resolve: GeometryResolver): Promise<Annotation[]>;
20
+ /**
21
+ * Extracts form field definitions (<widget>) and field values (<fields>) from an XFDF document (F13).
22
+ */
23
+ export declare function parseXfdfFormFields(xml: string, resolve?: GeometryResolver, roleMapper?: (customData: Record<string, string>) => string | undefined): Promise<{
24
+ fields: FormField[];
25
+ values: FormDataRecord;
26
+ }>;
@@ -1,7 +1,7 @@
1
1
  import { default as React } from 'react';
2
2
  import { Annotation } from '../annotations/types';
3
3
  import { AnnotationManager } from '../annotations/AnnotationManager';
4
- import { Redaction, WatermarkOptions, SDKPermissions, PdfAssetPaths, TransientHighlight, InitialScale, LinkClickEvent, WebViewerInstance } from '../core/types';
4
+ import { Redaction, WatermarkOptions, SDKPermissions, PdfAssetPaths, TransientHighlight, InitialScale, LinkClickEvent, WebViewerInstance, LoadProgressInfo } from '../core/types';
5
5
  import { FormManager } from '../forms/FormManager';
6
6
  import * as pdfjsLib from 'pdfjs-dist';
7
7
  export interface DocumentLoadErrorInfo {
@@ -23,14 +23,16 @@ interface DocumentViewerProps {
23
23
  httpHeaders?: Record<string, string>;
24
24
  /** Alias for `httpHeaders` providing an alternative headers option. */
25
25
  customHeaders?: Record<string, string>;
26
- /** Maximum number of bytes fetched per HTTP 206 range request. Default is 65536. */
26
+ /** Maximum number of bytes fetched per HTTP 206 range request. Default is 524288 (512 KB). */
27
27
  rangeChunkSize?: number;
28
- /** Disable chunked streaming of PDF file data. Default false. */
28
+ /** Disable chunked streaming of PDF file data. Default true. */
29
29
  disableStream?: boolean;
30
30
  /** Disable automatic background pre-fetching of remaining PDF file chunks. Default false. */
31
31
  disableAutoFetch?: boolean;
32
32
  /** Disable HTTP 206 range requests entirely, forcing full PDF download. Default false. */
33
33
  disableRange?: boolean;
34
+ /** Optional dedicated or pre-warmed pdf.js worker instance. Defaults to shared worker singleton. */
35
+ worker?: pdfjsLib.PDFWorker;
34
36
  /** Password for password-protected PDFs. */
35
37
  password?: string;
36
38
  /** pdf.js asset locations, applied right before the document is opened. */
@@ -51,7 +53,9 @@ interface DocumentViewerProps {
51
53
  onDocumentLoaded?: (doc: pdfjsLib.PDFDocumentProxy, url: string) => void;
52
54
  onLoadError?: (error: Error, info: DocumentLoadErrorInfo) => void;
53
55
  /** Fires once per loaded document, after the first page canvas has been painted. */
54
- onFirstPageRendered?: (pageNumber: number) => void;
56
+ onFirstPageRendered?: (pageNumber: number, telemetry?: LoadProgressInfo) => void;
57
+ /** Telemetry callback reporting download progress and range requests. */
58
+ onLoadProgress?: (info: LoadProgressInfo) => void;
55
59
  /** Fires whenever any page canvas has finished rendering. */
56
60
  onPageRendered?: (pageNumber: number) => void;
57
61
  onPageChange?: (pageNumber: number, numPages: number) => void;
@@ -90,6 +94,7 @@ interface DocumentViewerProps {
90
94
  formManager?: FormManager;
91
95
  setActiveTab?: (tab: string) => void;
92
96
  onDownloadFilledPdf?: () => void;
97
+ highlightedRoleId?: string | null;
93
98
  }
94
- export default function DocumentViewer({ leftSidebarOpen, rightSidebarOpen, activeTab, annotationManager, initialDoc, loadNonce, withCredentials, httpHeaders, customHeaders, rangeChunkSize, disableStream, disableAutoFetch, disableRange, password, assets, sidebars, redactions, regexRedactions, scale, setScale, sidebarTab, setSidebarTab, onAnnotationsChange, onRedactionsChange, onRedactionsApplied, onDocumentLoaded, onLoadError, onFirstPageRendered, onPageRendered, onPageChange, pageTransition, pageLayout, rotation, setRotation, watermark, watermarkText, enableAnnotations: _enableAnnotations, initialPage, page, transientHighlights, permissions, hideAnnotationsUntilPageRendered, enableTextSelection, defaultTool, showSelectionTooltip, initialScale, initialWidthRatio, responsive, instance, targetViewer, resolveLinkUrl, onLinkClick, formManager, setActiveTab, onDownloadFilledPdf, }: DocumentViewerProps): React.JSX.Element;
99
+ export default function DocumentViewer({ leftSidebarOpen, rightSidebarOpen, activeTab, annotationManager, initialDoc, loadNonce, withCredentials, httpHeaders, customHeaders, rangeChunkSize, disableStream, disableAutoFetch, disableRange, password, assets, sidebars, redactions, regexRedactions, scale, setScale, sidebarTab, setSidebarTab, onAnnotationsChange, onRedactionsChange, onRedactionsApplied, onDocumentLoaded, onLoadError, onFirstPageRendered, onLoadProgress, onPageRendered, onPageChange, pageTransition, pageLayout, rotation, setRotation, watermark, watermarkText, enableAnnotations: _enableAnnotations, initialPage, page, transientHighlights, permissions, hideAnnotationsUntilPageRendered, enableTextSelection, defaultTool, showSelectionTooltip, initialScale, initialWidthRatio, responsive, instance, targetViewer, resolveLinkUrl, onLinkClick, formManager, setActiveTab, onDownloadFilledPdf, highlightedRoleId, worker, }: DocumentViewerProps): React.JSX.Element;
95
100
  export {};
@@ -3,6 +3,7 @@ import { FormField, FormRole } from '../forms/types';
3
3
  interface FormFieldEditorModalProps {
4
4
  field: FormField;
5
5
  roles?: FormRole[];
6
+ existingFields?: FormField[];
6
7
  onAddRole?: (role: FormRole) => void;
7
8
  onSave: (updated: Partial<FormField>) => void;
8
9
  onClose: () => void;
@@ -14,6 +14,7 @@ interface FormFieldLayerProps {
14
14
  canFillForms?: boolean;
15
15
  showFlowOrder?: boolean;
16
16
  selectedRoleFilter?: string | null;
17
+ highlightedRoleId?: string | null;
17
18
  }
18
19
  export declare const FormFieldLayer: React.FC<FormFieldLayerProps>;
19
20
  export {};
@@ -6,6 +6,7 @@ interface FormSignatureModalProps {
6
6
  role?: FormRole;
7
7
  currentUser?: ViewerUser | null;
8
8
  currentValue?: FormSignatureValue | any;
9
+ adoptedSignature?: FormSignatureValue | null;
9
10
  defaultSignerName?: string;
10
11
  onSave: (value: FormSignatureValue) => void;
11
12
  onClear?: () => void;
@@ -49,7 +49,9 @@ interface PageRendererProps {
49
49
  canFillForms?: boolean;
50
50
  showFlowOrder?: boolean;
51
51
  selectedRoleFilter?: string | null;
52
+ highlightedRoleId?: string | null;
53
+ isInViewport?: boolean;
52
54
  }
53
- declare function PageRendererComponent({ pageNum, pdfDoc, scale, rotation, containerWidth: _containerWidth, containerHeight: _containerHeight, scrollTop: _scrollTop, scrollLeft: _scrollLeft, pageTop, pageLeft, basePageWidth, basePageHeight, activeTab, activeTool, annotations, selectedAnnotationId, activeSearchResult, transientHighlights, onMouseDown, onMouseMove, onMouseUp, onAnnotationClick, onAnnotationDoubleClick, onStartResize, onStartMove, onAnnotationMouseEnter, onClearSelection, watermark, watermarkText, redactions, onDiscardRedaction, onRendered, hideAnnotationsUntilPageRendered, onLinkClick, formManager, activeFormTool, setActiveFormTool, canFillForms, showFlowOrder, selectedRoleFilter }: PageRendererProps): React.JSX.Element;
55
+ declare function PageRendererComponent({ pageNum, pdfDoc, scale, rotation, containerWidth: _containerWidth, containerHeight: _containerHeight, scrollTop: _scrollTop, scrollLeft: _scrollLeft, pageTop, pageLeft, basePageWidth, basePageHeight, activeTab, activeTool, annotations, selectedAnnotationId, activeSearchResult, transientHighlights, onMouseDown, onMouseMove, onMouseUp, onAnnotationClick, onAnnotationDoubleClick, onStartResize, onStartMove, onAnnotationMouseEnter, onClearSelection, watermark, watermarkText, redactions, onDiscardRedaction, onRendered, hideAnnotationsUntilPageRendered, onLinkClick, formManager, activeFormTool, setActiveFormTool, canFillForms, showFlowOrder, selectedRoleFilter, highlightedRoleId, isInViewport: propIsInViewport }: PageRendererProps): React.JSX.Element;
54
56
  declare const PageRenderer: React.MemoExoticComponent<typeof PageRendererComponent>;
55
57
  export default PageRenderer;
@@ -1,7 +1,8 @@
1
1
  import { default as React } from 'react';
2
2
  import { DocumentLoadErrorInfo } from './DocumentViewer';
3
3
  import { WebViewerInstance } from '../core/ViewerInstance';
4
- import { WebViewerOptions, Redaction, TransientHighlight, LinkClickEvent } from '../core/types';
4
+ import { FormField, FormDataRecord } from '../forms/types';
5
+ import { WebViewerOptions, Redaction, TransientHighlight, LinkClickEvent, LoadProgressInfo } from '../core/types';
5
6
  import { Annotation } from '../annotations/types';
6
7
  import { OfficeConverterConfig, OfficeFileType } from '../office';
7
8
  export interface TeamSyncViewerProps extends Omit<WebViewerOptions, 'path'> {
@@ -18,11 +19,16 @@ export interface TeamSyncViewerProps extends Omit<WebViewerOptions, 'path'> {
18
19
  * the previous one was a presigned link that expired.
19
20
  */
20
21
  onDocumentLoadError?: (error: Error, retry: (newUrl?: string) => void, info: DocumentLoadErrorInfo) => void;
21
- /** Fires once per document, after the first page canvas has been painted. */
22
+ /** Fires once per document, after the first page canvas has been painted. Includes load telemetry. */
22
23
  onFirstPageRendered?: (info: {
23
24
  url: string;
24
25
  pageNumber: number;
26
+ bytesLoaded?: number;
27
+ totalBytes?: number;
28
+ rangeRequests?: number;
25
29
  }) => void;
30
+ /** Telemetry callback reporting download progress and range requests. */
31
+ onLoadProgress?: (info: LoadProgressInfo) => void;
26
32
  /** Fires whenever any page canvas has finished rendering. */
27
33
  onPageRendered?: (info: {
28
34
  url: string;
@@ -97,6 +103,16 @@ export interface TeamSyncViewerProps extends Omit<WebViewerOptions, 'path'> {
97
103
  error: Error;
98
104
  url?: string;
99
105
  }) => void;
106
+ /** Initial active UI mode tab: 'View' | 'Annotate' | 'Forms' (default 'View') (F15). */
107
+ initialTab?: string;
108
+ /** Initial form fields definition (F19). */
109
+ initialFormFields?: FormField[];
110
+ /** Initial form data values (F19). */
111
+ initialFormData?: FormDataRecord;
112
+ /** Fires when active UI tab changes (F15). */
113
+ onTabChanged?: (info: {
114
+ tab: string;
115
+ }) => void;
100
116
  className?: string;
101
117
  style?: React.CSSProperties;
102
118
  }
@@ -47,6 +47,10 @@ export interface LoadDocumentOptions {
47
47
  withCredentials?: boolean;
48
48
  /** Password for password-protected PDFs. */
49
49
  password?: string;
50
+ /**
51
+ * Optional dedicated or pre-warmed pdf.js PDFWorker instance.
52
+ */
53
+ worker?: pdfjsLib.PDFWorker;
50
54
  }
51
55
  /** Callbacks the React component installs so the instance can reach live state. */
52
56
  export interface ViewerBinding {
@@ -65,6 +69,7 @@ export interface ViewerBinding {
65
69
  }): void;
66
70
  getTransientHighlights(): TransientHighlight[];
67
71
  setTransientHighlights(highlights: TransientHighlight[]): void;
72
+ getActiveTab?(): string;
68
73
  }
69
74
  export declare class WebViewerInstance {
70
75
  private static instances;
@@ -89,7 +94,15 @@ export declare class WebViewerInstance {
89
94
  private unmountRoot;
90
95
  private destroyed;
91
96
  private targetViewerTarget;
97
+ private currentActiveTab;
92
98
  constructor(bus: ViewerBus, annotationManager?: AnnotationManager, id?: string, formManager?: FormManager);
99
+ /**
100
+ * Visually highlights form fields belonging to a specific role with an accent glow (F16).
101
+ * Pass null to clear active highlights.
102
+ */
103
+ highlightRoleFields(roleId: string | null): void;
104
+ /** Returns current active tab in the viewer (F15). */
105
+ getActiveTab(): string;
93
106
  /** Sets the target viewer instance, ref, getter, or ID to receive cross-document links. */
94
107
  setTargetViewer(target: WebViewerInstance | React.RefObject<WebViewerInstance | null> | (() => WebViewerInstance | null) | string | null): void;
95
108
  /** Resolves the target viewer instance if configured. */
@@ -266,6 +279,10 @@ export declare class WebViewerInstance {
266
279
  */
267
280
  copySelectedText(): Promise<boolean>;
268
281
  readonly UI: {
282
+ /** Sets active UI mode tab: 'View' | 'Annotate' | 'Forms' (F15). */
283
+ setActiveTab: (tab: "View" | "Annotate" | "Forms" | string) => void;
284
+ /** Returns currently active tab (F15). */
285
+ getActiveTab: () => string;
269
286
  /** Theming is not implemented; kept for API compatibility. */
270
287
  setTheme: (_theme: string) => void;
271
288
  goToPage: (pageNumber: number) => void;
@@ -16,11 +16,15 @@ export interface ExportInput {
16
16
  signerName?: string;
17
17
  formFields?: FormField[];
18
18
  formData?: FormDataRecord;
19
+ /** Whether to lock and flatten form fields into static page content on export (F5). */
20
+ flatten?: boolean;
19
21
  }
20
22
  export interface ExportOptions {
21
23
  /** Bake exactly these annotations instead of the live list. */
22
24
  explicitAnnotations?: Annotation[];
23
25
  /** Accepted for API compatibility; annotations are always taken from the live list / explicitAnnotations. */
24
26
  xfdfString?: string;
27
+ /** Whether to lock and flatten form fields into static page content on export (F5). */
28
+ flatten?: boolean;
25
29
  }
26
30
  export declare function buildPdfBytes(input: ExportInput, options?: ExportOptions): Promise<Uint8Array>;
@@ -1,4 +1,25 @@
1
1
  import { DocumentInitParameters } from 'pdfjs-dist/types/src/display/api';
2
+ /**
3
+ * © 2026 AngelBot Ai Pvt Ltd. All rights reserved.
4
+ * pdf.js asset configuration.
5
+ *
6
+ * The library never bundles or inlines the pdf.js worker (that produced a 5 MB bundle with a
7
+ * `data:` URL worker, which strict Content-Security-Policies reject). Hosts serve the worker,
8
+ * CMaps, standard fonts and wasm decoders from their own origin and tell us where they live.
9
+ *
10
+ * Next.js example (copy from node_modules/pdfjs-dist into public/pdfjs/):
11
+ * configurePdfAssets({
12
+ * workerSrc: '/pdfjs/pdf.worker.min.mjs',
13
+ * cMapUrl: '/pdfjs/cmaps/',
14
+ * standardFontDataUrl: '/pdfjs/standard_fonts/',
15
+ * wasmUrl: '/pdfjs/wasm/',
16
+ * });
17
+ *
18
+ * Vite example:
19
+ * import workerSrc from 'pdfjs-dist/build/pdf.worker.min.mjs?url';
20
+ * configurePdfAssets({ workerSrc });
21
+ */
22
+ import * as pdfjsLib from 'pdfjs-dist';
2
23
  export interface PdfAssetPaths {
3
24
  /** URL of `pdf.worker.min.mjs` matching the installed pdfjs-dist version. REQUIRED. */
4
25
  workerSrc?: string;
@@ -25,3 +46,22 @@ export declare function assertWorkerConfigured(): void;
25
46
  export declare function getDocumentParams(): Partial<DocumentInitParameters>;
26
47
  /** pdfjs-dist version this build was compiled against (useful for worker-version mismatch checks). */
27
48
  export declare const pdfjsVersion: string;
49
+ export type PDFWorker = pdfjsLib.PDFWorker;
50
+ /**
51
+ * Creates a new dedicated pdf.js worker instance.
52
+ * Useful for host applications that pre-warm the worker thread during idle periods.
53
+ */
54
+ export declare function createPdfWorker(params?: {
55
+ name?: string;
56
+ port?: any;
57
+ verbosity?: number;
58
+ }): pdfjsLib.PDFWorker;
59
+ /**
60
+ * Returns a shared library-level pdf.js worker singleton.
61
+ * Self-healing: if the worker was destroyed or terminated, instantiates a fresh worker instance.
62
+ */
63
+ export declare function getSharedPdfWorker(): pdfjsLib.PDFWorker | undefined;
64
+ /**
65
+ * Destroys the shared library-level pdf.js worker singleton, releasing its worker thread.
66
+ */
67
+ export declare function destroySharedPdfWorker(): void;
@@ -6,7 +6,8 @@ import { PdfAssetPaths } from './pdfAssets';
6
6
  import { WebViewerInstance } from './ViewerInstance';
7
7
  import { OfficeConverterConfig, OfficeFileType } from '../office/types';
8
8
  import { FormManager } from '../forms/FormManager';
9
- import { FormField, FormDataRecord, FormRole, FormFeatureOptions } from '../forms/types';
9
+ import { FormField, FormDataRecord, FormRole, FormFeatureOptions, FormFieldValueChangedEvent, FormSignatureAppliedEvent, FormSignatureClearedEvent, FormFieldAddedEvent, FormFieldRemovedEvent, FormFieldUpdatedEvent } from '../forms/types';
10
+ import type * as pdfjsLib from 'pdfjs-dist';
10
11
  export type { PdfAssetPaths, WebViewerInstance, OfficeConverterConfig, OfficeFileType, FormManager, FormField, FormDataRecord, FormRole, FormFeatureOptions, };
11
12
  export interface SearchBounds {
12
13
  x: number;
@@ -79,6 +80,12 @@ export type ToolMode = 'select' | 'pan' | 'rectangle' | 'ellipse' | 'line' | 'ar
79
80
  * Options accepted by `createWebViewer()` (and the deprecated `WebViewer()` alias).
80
81
  * Every option is also available as a prop on `<TeamSyncViewer>`.
81
82
  */
83
+ /** Loading telemetry reported during PDF document retrieval. */
84
+ export interface LoadProgressInfo {
85
+ bytesLoaded: number;
86
+ totalBytes: number;
87
+ rangeRequests?: number;
88
+ }
82
89
  export interface WebViewerOptions {
83
90
  /** @deprecated Only meaningful for the iframe package (`public/webviewer.js`). */
84
91
  path?: string;
@@ -157,12 +164,12 @@ export interface WebViewerOptions {
157
164
  customHeaders?: Record<string, string>;
158
165
  /**
159
166
  * Maximum number of bytes fetched per HTTP 206 range request.
160
- * Default is 65536 (= 64 KB).
167
+ * Default is 524288 (= 512 KB), optimizing round-trip latency over HTTP/2.
161
168
  */
162
169
  rangeChunkSize?: number;
163
170
  /**
164
171
  * Disable chunked streaming of PDF file data.
165
- * Default is false.
172
+ * Default is true, prioritizing initial page range requests over full-file download streams.
166
173
  */
167
174
  disableStream?: boolean;
168
175
  /**
@@ -177,6 +184,12 @@ export interface WebViewerOptions {
177
184
  * Default is false.
178
185
  */
179
186
  disableRange?: boolean;
187
+ /**
188
+ * Optional dedicated or pre-warmed pdf.js PDFWorker instance.
189
+ * If omitted, a persistent shared library-level worker singleton is used to avoid
190
+ * recreating a 1.2 MB worker thread on every document open or retry.
191
+ */
192
+ worker?: pdfjsLib.PDFWorker;
180
193
  /** Render the top toolbar. Default true. */
181
194
  toolbar?: boolean;
182
195
  /** Render the left (thumbnails) and right (comments/search) panels. Default true. */
@@ -269,7 +282,11 @@ export interface ViewerEventMap {
269
282
  firstPageRendered: {
270
283
  url: string;
271
284
  pageNumber: number;
285
+ bytesLoaded?: number;
286
+ totalBytes?: number;
287
+ rangeRequests?: number;
272
288
  };
289
+ loadProgress: LoadProgressInfo;
273
290
  pageRendered: {
274
291
  url: string;
275
292
  pageNumber: number;
@@ -302,6 +319,30 @@ export interface ViewerEventMap {
302
319
  text: string;
303
320
  };
304
321
  linkClicked: LinkClickEvent;
322
+ /** Fires when active UI tab changes (View / Annotate / Forms). */
323
+ tabChanged: {
324
+ tab: string;
325
+ };
326
+ /** Granular form field value change event (F18). */
327
+ fieldValueChanged: FormFieldValueChangedEvent;
328
+ /** Granular signature applied event (F18). */
329
+ signatureApplied: FormSignatureAppliedEvent;
330
+ /** Granular signature cleared event (F18). */
331
+ signatureCleared: FormSignatureClearedEvent;
332
+ /** Form field schema added (F18). */
333
+ fieldAdded: FormFieldAddedEvent;
334
+ /** Form field schema removed (F18). */
335
+ fieldRemoved: FormFieldRemovedEvent;
336
+ /** Form field schema updated (F18). */
337
+ fieldUpdated: FormFieldUpdatedEvent;
338
+ /** Full form data changed event. */
339
+ formDataChanged: {
340
+ data: Record<string, any>;
341
+ };
342
+ /** Full form fields schema changed event. */
343
+ formFieldsChanged: {
344
+ fields: FormField[];
345
+ };
305
346
  /** Fires when an Office document begins conversion. */
306
347
  officeConverting: {
307
348
  fileType: OfficeFileType;
@@ -1,4 +1,4 @@
1
- import { FormField, FormDataRecord, FormValidationResult, FormRole, FormFeatureOptions } from './types';
1
+ import { FormField, FormDataRecord, FormValidationResult, FormRole, FormFeatureOptions, FormSignatureValue, FormFieldValueChangedEvent, FormSignatureAppliedEvent, FormSignatureClearedEvent, FormFieldAddedEvent, FormFieldRemovedEvent, FormFieldUpdatedEvent } from './types';
2
2
  import { ViewerUser } from '../core/types';
3
3
  export declare const DEFAULT_FORM_OPTIONS: FormFeatureOptions;
4
4
  export declare const DEFAULT_ROLES: FormRole[];
@@ -25,10 +25,31 @@ export declare class FormManager {
25
25
  private activeFieldListeners;
26
26
  private optionsListeners;
27
27
  private userListeners;
28
+ private fieldValueListeners;
29
+ private signatureAppliedListeners;
30
+ private signatureClearedListeners;
31
+ private fieldAddedListeners;
32
+ private fieldRemovedListeners;
33
+ private fieldUpdatedListeners;
34
+ private adoptedSignature;
28
35
  private readOnly;
29
36
  constructor(initialFields?: FormField[], initialValues?: FormDataRecord, initialRoles?: FormRole[], initialOptions?: Partial<FormFeatureOptions>, initialUser?: ViewerUser | null);
30
37
  onFieldsChange(listener: FormFieldsChangeListener): () => void;
31
38
  onDataChange(listener: FormDataChangeListener): () => void;
39
+ onFieldValueChanged(listener: (event: FormFieldValueChangedEvent) => void): () => void;
40
+ onSignatureApplied(listener: (event: FormSignatureAppliedEvent) => void): () => void;
41
+ onSignatureCleared(listener: (event: FormSignatureClearedEvent) => void): () => void;
42
+ onFieldAdded(listener: (event: FormFieldAddedEvent) => void): () => void;
43
+ onFieldRemoved(listener: (event: FormFieldRemovedEvent) => void): () => void;
44
+ onFieldUpdated(listener: (event: FormFieldUpdatedEvent) => void): () => void;
45
+ private notifyFieldValueChanged;
46
+ private notifySignatureApplied;
47
+ private notifySignatureCleared;
48
+ private notifyFieldAdded;
49
+ private notifyFieldRemoved;
50
+ private notifyFieldUpdated;
51
+ getAdoptedSignature(): FormSignatureValue | null;
52
+ setAdoptedSignature(sig: FormSignatureValue | null): void;
32
53
  private notifyFieldsChange;
33
54
  private notifyDataChange;
34
55
  private pushHistory;
@@ -40,15 +61,28 @@ export declare class FormManager {
40
61
  getFieldsForPage(pageIndex: number): FormField[];
41
62
  getField(id: string): FormField | undefined;
42
63
  getFieldByName(name: string): FormField | undefined;
43
- setFields(fields: FormField[]): void;
64
+ setFields(fields: FormField[], recordHistory?: boolean): void;
44
65
  addField(field: FormField): void;
45
66
  updateField(id: string, updates: Partial<Omit<FormField, 'id'>>, recordHistory?: boolean): boolean;
46
67
  deleteField(id: string): boolean;
68
+ /** Alias for deleteField (F18). */
69
+ removeField(id: string): boolean;
47
70
  clearFields(): void;
48
71
  getValues(): FormDataRecord;
49
72
  getValue(name: string): any;
50
- setValue(name: string, value: any): void;
51
- setValues(newValues: FormDataRecord): void;
73
+ /**
74
+ * Checks whether a form field can currently be modified based on form read-only state,
75
+ * field-level read-only setting, and the active role assignment (F8).
76
+ */
77
+ canEditField(fieldOrName: FormField | string): boolean;
78
+ setValue(name: string, value: any, options?: {
79
+ force?: boolean;
80
+ source?: 'user' | 'code';
81
+ }): boolean;
82
+ setValues(newValues: FormDataRecord, options?: {
83
+ force?: boolean;
84
+ source?: 'user' | 'code';
85
+ }): void;
52
86
  clearValues(): void;
53
87
  setReadOnly(readOnly: boolean): void;
54
88
  isReadOnly(): boolean;
@@ -0,0 +1,6 @@
1
+ import { FormField, FormDataRecord } from './types';
2
+ import { GeometryResolver } from '../annotations/geometry';
3
+ export declare function extractAcroFormFields(pdfDoc: any, resolver?: GeometryResolver): Promise<{
4
+ fields: FormField[];
5
+ values: FormDataRecord;
6
+ }>;
@@ -98,6 +98,37 @@ export interface FormRole {
98
98
  color: string;
99
99
  /** Optional human-readable description for the role */
100
100
  description?: string;
101
+ /** Optional party type classification (e.g. 'internal', 'external', 'signer', 'viewer') */
102
+ partyType?: 'internal' | 'external' | string;
103
+ /** Optional signing order or sequence index in a multi-party workflow */
104
+ signingOrder?: number;
105
+ /** Optional custom host-specific metadata attributes */
106
+ metadata?: Record<string, any>;
107
+ }
108
+ export interface FormFieldValueChangedEvent {
109
+ fieldName: string;
110
+ oldValue: any;
111
+ newValue: any;
112
+ source: 'user' | 'code';
113
+ }
114
+ export interface FormSignatureAppliedEvent {
115
+ fieldName: string;
116
+ signature: FormSignatureValue;
117
+ signerName?: string;
118
+ }
119
+ export interface FormSignatureClearedEvent {
120
+ fieldName: string;
121
+ }
122
+ export interface FormFieldAddedEvent {
123
+ field: FormField;
124
+ }
125
+ export interface FormFieldRemovedEvent {
126
+ fieldId: string;
127
+ fieldName: string;
128
+ }
129
+ export interface FormFieldUpdatedEvent {
130
+ field: FormField;
131
+ changes: Partial<FormField>;
101
132
  }
102
133
  export type FormDataRecord = Record<string, any>;
103
134
  export interface FormValidationResult {
@@ -176,4 +207,11 @@ export interface FormFeatureOptions {
176
207
  * Controls which fields and signature flags are active for the current user.
177
208
  */
178
209
  currentRole?: string | null;
210
+ /**
211
+ * Defines which role unassigned fields (fields with no roleId) belong to during validation:
212
+ * - 'all': unassigned fields are required for everyone (default)
213
+ * - 'none': unassigned fields are never treated as required for any specific role
214
+ * - string: role ID that unassigned fields belong to
215
+ */
216
+ unassignedFieldsRole?: 'all' | 'none' | string;
179
217
  }
@@ -51,4 +51,6 @@ export type { OfficeConverterConfig, OfficeConversionConfig, OfficeConversionSta
51
51
  export { VERSION } from './version';
52
52
  export { FormManager, DEFAULT_FORM_OPTIONS, DEFAULT_ROLES } from './forms/FormManager';
53
53
  export type { FormFieldsChangeEvent, FormFieldsChangeListener, FormDataChangeListener } from './forms/FormManager';
54
- export type { FormField, FormFieldType, DateTimeFormat, SignatureType, FormSignatureValue, FormRole, FormDataRecord, FormValidationResult, FormToolType, FormFeatureOptions, } from './forms/types';
54
+ export { extractAcroFormFields } from './forms/acroFormIngestion';
55
+ export { parseXfdfFormFields } from './annotations/xfdf';
56
+ export type { FormField, FormFieldType, DateTimeFormat, SignatureType, FormSignatureValue, FormRole, FormDataRecord, FormValidationResult, FormToolType, FormFeatureOptions, FormFieldValueChangedEvent, FormSignatureAppliedEvent, FormSignatureClearedEvent, FormFieldAddedEvent, FormFieldRemovedEvent, FormFieldUpdatedEvent, } from './forms/types';
@@ -32,6 +32,10 @@ export declare function clampScale(scale: number, minScale?: number, maxScale?:
32
32
  * optionally scaled by a width ratio (e.g. 0.7 for 70% of available width).
33
33
  */
34
34
  export declare function calculateFitWidthScale(availableWidth: number, pageWidth: number, ratio?: number, minScale?: number, maxScale?: number): number;
35
+ /**
36
+ * Calculates the target scale to fit a given page (both width and height) inside an available container viewport.
37
+ */
38
+ export declare function calculateFitPageScale(availableWidth: number, availableHeight: number, pageWidth: number, pageHeight: number, minScale?: number, maxScale?: number): number;
35
39
  /**
36
40
  * Calculates the safe rasterization scale for PDF.js viewport rendering so that
37
41
  * canvas dimensions and texture memory stay strictly within hardware limits.
@@ -1 +1,2 @@
1
1
  export declare const VERSION: string;
2
+ export declare const LIB_VERSION: string;