teamsync-pdf-viewer 1.7.1 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  All notable changes to `teamsync-pdf-viewer` are documented here.
4
4
 
5
+ ## [1.8.0] — 2026-09-17
6
+
7
+ ### Added
8
+ - **Native Microsoft Office Document Viewing**:
9
+ - View Microsoft Word (`.docx`, `.doc`), Excel (`.xlsx`, `.xls`), and PowerPoint (`.pptx`, `.ppt`) documents natively inside `<TeamSyncViewer>`.
10
+ - Transparent document type detection via magic byte signatures and file extension inspection (`officeDetector.ts`).
11
+ - Animated conversion loading overlay (`OfficeLoadingOverlay.tsx`) with real-time status indication.
12
+ - Local drag-and-drop and toolbar file picker conversion fallback.
13
+ - **Enterprise Hybrid Office Architecture**:
14
+ - **Edge CDN Pre-Conversion & Caching**: Fast 200–400ms cached vector PDF delivery via `/api/convert?file=...` with zero server CPU load on repeat views.
15
+ - **Client-Side On-The-Fly Fallback**: Multipart form upload proxy for local user file drops and selection via `POST /api/convert`.
16
+ - **Zero Leaked Secrets**: Gotenberg credentials injected server-side; client bundles never expose backend credentials.
17
+ - **Host SDK Office Module**:
18
+ - Exported `useOfficeDocument` React hook for host applications to manage loading, pre-conversion, and error states before mounting the viewer.
19
+ - Exported `preloadOfficeDocument(fileOrUrl, config, fileName)` async helper for routers, loaders, and prefetching.
20
+ - Exported `officeConverter` client service supporting remote URL conversion (`convertOfficeUrl`) and multipart file uploads (`convertOfficeFile`).
21
+ - Added dedicated `./office` subpath export in `package.json` alongside root exports.
22
+ - Exported office detection utilities: `isOfficeDocumentUrl`, `isOfficeFile`, `detectOfficeType`, `isOfficeExtension`, `SUPPORTED_OFFICE_EXTENSIONS`.
23
+ - Exported TypeScript types: `OfficeConversionConfig`, `OfficeConversionState`, `OfficeFileType`, `OfficeDocumentOptions`, `UseOfficeDocumentResult`.
24
+ - **Top-Level SDK Version Export & About Modal Synchronization**:
25
+ - Exported `VERSION` constant from `teamsync-pdf-viewer` public API.
26
+ - Automated build-time version synchronization script (`scripts/sync-version.mjs`) ensuring parity across package and git tags.
27
+ - Dynamic About modal reflecting the active release tag with a direct link to GitHub release notes.
28
+ - Edge release endpoint (`/api/version`) caching GitHub release metadata at the CDN edge.
29
+
5
30
  ## [1.7.1] — 2026-09-15
6
31
 
7
32
  ### Fixed
package/README.md CHANGED
@@ -71,6 +71,7 @@ Explore detailed SDK guides, parameter options, code snippets, and architecture
71
71
  - 🎨 **[Annotations & Markup Guide](docs/wiki/Annotations-&-Markup-Guide.md)**: Freehand drawing, vector shapes, callouts & links.
72
72
  - 🛡️ **[Redactions & PII Sanitization Guide](docs/wiki/Redactions-&-PII-Sanitization.md)**: Binary redactions, regex PII scanning & discard options.
73
73
  - 💧 **[Forensic Watermarking Guide](docs/wiki/Forensic-Watermarking.md)**: Dynamic single and tiled watermark setup.
74
+ - 📄 **[Viewing Office Documents Guide](docs/wiki/Viewing-Office-Documents.md)**: Word (.docx), PowerPoint (.pptx), Excel (.xlsx) high-fidelity viewing & conversion.
74
75
  - 🔌 **[Plugin Architecture Guide](docs/wiki/Plugin-Architecture.md)**: Writing custom extension plugins.
75
76
 
76
77
  ---
@@ -3,6 +3,7 @@ import { DocumentLoadErrorInfo } from './DocumentViewer';
3
3
  import { WebViewerInstance } from '../core/ViewerInstance';
4
4
  import { WebViewerOptions, Redaction, TransientHighlight, LinkClickEvent } from '../core/types';
5
5
  import { Annotation } from '../annotations/types';
6
+ import { OfficeConverterConfig, OfficeFileType } from '../office';
6
7
  export interface TeamSyncViewerProps extends Omit<WebViewerOptions, 'path'> {
7
8
  /** URL of the PDF to display. Alias of `initialDoc`; `fileUrl` wins when both are set. */
8
9
  fileUrl?: string;
@@ -74,6 +75,28 @@ export interface TeamSyncViewerProps extends Omit<WebViewerOptions, 'path'> {
74
75
  * Call `event.preventDefault()` to suppress default behavior.
75
76
  */
76
77
  onLinkClick?: (event: LinkClickEvent) => boolean | void | Promise<void>;
78
+ /**
79
+ * Configuration for viewing Microsoft Office documents (.docx, .doc, .pptx, .ppt, .xlsx, .xls).
80
+ */
81
+ officeConverter?: OfficeConverterConfig;
82
+ /** Fires when an Office document starts converting to PDF. */
83
+ onOfficeConverting?: (info: {
84
+ fileType: OfficeFileType;
85
+ url?: string;
86
+ fileName?: string;
87
+ }) => void;
88
+ /** Fires when an Office document has successfully converted to PDF. */
89
+ onOfficeConverted?: (info: {
90
+ fileType: OfficeFileType;
91
+ url?: string;
92
+ fromCache: boolean;
93
+ }) => void;
94
+ /** Fires when an Office document conversion encounters an error. */
95
+ onOfficeConversionError?: (info: {
96
+ fileType: OfficeFileType;
97
+ error: Error;
98
+ url?: string;
99
+ }) => void;
77
100
  className?: string;
78
101
  style?: React.CSSProperties;
79
102
  }
@@ -4,7 +4,8 @@ import { Annotation } from '../annotations/types';
4
4
  import { AnnotationChangedEvent } from '../annotations/AnnotationManager';
5
5
  import { PdfAssetPaths } from './pdfAssets';
6
6
  import { WebViewerInstance } from './ViewerInstance';
7
- export type { PdfAssetPaths, WebViewerInstance };
7
+ import { OfficeConverterConfig, OfficeFileType } from '../office/types';
8
+ export type { PdfAssetPaths, WebViewerInstance, OfficeConverterConfig, OfficeFileType };
8
9
  export interface SearchBounds {
9
10
  x: number;
10
11
  y: number;
@@ -134,7 +135,14 @@ export interface WebViewerOptions {
134
135
  onRedactionsChange?: (redactions: Redaction[]) => void;
135
136
  /** Fires once per user click of Apply in the confirmation modal with all applied redactions. */
136
137
  onRedactionsApplied?: (redactions: Redaction[]) => void;
137
- /** Unique identifier for this viewer instance, allowing other viewers to target it by name. */
138
+ /**
139
+ * Configuration for viewing Microsoft Office documents (.docx, .doc, .pptx, .ppt, .xlsx, .xls).
140
+ * Supports headless backend conversion (Gotenberg / LibreOffice daemon) or custom conversion hooks.
141
+ */
142
+ officeConverter?: OfficeConverterConfig;
143
+ /**
144
+ * Unique identifier for this viewer instance, allowing other viewers to target it by name.
145
+ */
138
146
  id?: string;
139
147
  /**
140
148
  * Target viewer instance, ref, getter, or instance ID to open cross-document links in.
@@ -228,6 +236,24 @@ export interface ViewerEventMap {
228
236
  text: string;
229
237
  };
230
238
  linkClicked: LinkClickEvent;
239
+ /** Fires when an Office document begins conversion. */
240
+ officeConverting: {
241
+ fileType: OfficeFileType;
242
+ url?: string;
243
+ fileName?: string;
244
+ };
245
+ /** Fires when an Office document finishes conversion successfully. */
246
+ officeConverted: {
247
+ fileType: OfficeFileType;
248
+ url?: string;
249
+ fromCache: boolean;
250
+ };
251
+ /** Fires when an Office document conversion fails. */
252
+ officeConversionError: {
253
+ fileType: OfficeFileType;
254
+ error: Error;
255
+ url?: string;
256
+ };
231
257
  destroy: Record<string, never>;
232
258
  }
233
259
  export type ViewerEventType = keyof ViewerEventMap;
@@ -40,3 +40,11 @@ export type { ScrollCompensationParams, ScrollPosition } from './utils/zoomUtils
40
40
  export { estimatePageDimensions, computeRowLayout, DEFAULT_FALLBACK_DIMS, hasDimensionMismatch } from './utils/layoutUtils';
41
41
  export type { PageDimension, RowLayout } from './utils/layoutUtils';
42
42
  export * from './plugins/types';
43
+ export * from './office';
44
+ export { officeConverter, convertOfficeDocument, convertOfficeFile, convertOfficeUrl, } from './office/officeConverter';
45
+ export { useOfficeDocument, preloadOfficeDocument, } from './office/useOfficeDocument';
46
+ export type { UseOfficeDocumentOptions, UseOfficeDocumentResult, } from './office/useOfficeDocument';
47
+ export { isOfficeDocumentUrl, isOfficeFile, detectOfficeType, isOfficeExtension, SUPPORTED_OFFICE_EXTENSIONS, } from './office/officeDetector';
48
+ export { OfficeLoadingOverlay } from './office/OfficeLoadingOverlay';
49
+ export type { OfficeConverterConfig, OfficeConversionConfig, OfficeConversionState, OfficeFileType, OfficeDocumentOptions, OfficeDocumentInfo, } from './office/types';
50
+ export { VERSION } from './version';
@@ -0,0 +1,9 @@
1
+ import { default as React } from 'react';
2
+ import { OfficeFileType } from './types';
3
+ export interface OfficeLoadingOverlayProps {
4
+ fileType: OfficeFileType;
5
+ fileName?: string;
6
+ error?: Error | null;
7
+ onRetry?: () => void;
8
+ }
9
+ export declare const OfficeLoadingOverlay: React.FC<OfficeLoadingOverlayProps>;
@@ -0,0 +1,5 @@
1
+ export * from './types';
2
+ export * from './officeDetector';
3
+ export * from './officeConverter';
4
+ export * from './OfficeLoadingOverlay';
5
+ export * from './useOfficeDocument';
@@ -0,0 +1,46 @@
1
+ import { OfficeConverterConfig, OfficeFileType } from './types';
2
+ /**
3
+ * Retrieves a cached converted PDF from memory or sessionStorage.
4
+ */
5
+ export declare function getCachedOfficePdf(fileOrUrl: string | File | Blob | ArrayBuffer, fileType: OfficeFileType, cacheMode?: OfficeConverterConfig['cache']): Promise<ArrayBuffer | null>;
6
+ /**
7
+ * Stores a converted PDF in memory and optionally sessionStorage.
8
+ */
9
+ export declare function setCachedOfficePdf(fileOrUrl: string | File | Blob | ArrayBuffer, fileType: OfficeFileType, pdfBuffer: ArrayBuffer, cacheMode?: OfficeConverterConfig['cache']): Promise<void>;
10
+ /**
11
+ * Clears the converted document cache.
12
+ */
13
+ export declare function clearOfficeCache(): void;
14
+ export interface ConvertOfficeDocumentResult {
15
+ /** Raw PDF ArrayBuffer ready for PDF.js or downstream processing */
16
+ pdfBuffer: ArrayBuffer;
17
+ /** Browser Blob Object URL (e.g. blob:http...) ready for rendering or iframe preview */
18
+ objectUrl: string;
19
+ /** Whether the document was served from cache */
20
+ fromCache: boolean;
21
+ }
22
+ /**
23
+ * Converts an Office document (Word, PowerPoint, Excel) into a standardized PDF ArrayBuffer
24
+ * and Blob URL using either a custom converter or the configured backend microservice.
25
+ */
26
+ export declare function convertOfficeDocument(fileOrUrl: string | File | Blob | ArrayBuffer, config: OfficeConverterConfig, fileName?: string): Promise<ConvertOfficeDocumentResult>;
27
+ /**
28
+ * Convenience helper to convert a remote Office document URL.
29
+ */
30
+ export declare function convertOfficeUrl(url: string, config: OfficeConverterConfig, fileName?: string): Promise<ConvertOfficeDocumentResult>;
31
+ /**
32
+ * Convenience helper to convert a local Office File or Blob.
33
+ */
34
+ export declare function convertOfficeFile(file: File | Blob, config: OfficeConverterConfig, fileName?: string): Promise<ConvertOfficeDocumentResult>;
35
+ /**
36
+ * Unified Office converter service object.
37
+ */
38
+ export declare const officeConverter: {
39
+ convert: typeof convertOfficeDocument;
40
+ convertDocument: typeof convertOfficeDocument;
41
+ convertUrl: typeof convertOfficeUrl;
42
+ convertFile: typeof convertOfficeFile;
43
+ getCached: typeof getCachedOfficePdf;
44
+ setCached: typeof setCachedOfficePdf;
45
+ clearCache: typeof clearOfficeCache;
46
+ };
@@ -0,0 +1,30 @@
1
+ import { OfficeFileType, OfficeDocumentCategory, OfficeBadgeMeta, OfficeDocumentInfo } from './types';
2
+ /**
3
+ * Detects whether a string URL, File, or Blob represents a supported Microsoft Office document.
4
+ */
5
+ export declare function getOfficeFileType(target: unknown): OfficeFileType | null;
6
+ /**
7
+ * Returns true if the given input is a supported Microsoft Office document.
8
+ */
9
+ export declare function isOfficeDocument(target: unknown): boolean;
10
+ /**
11
+ * Returns the broad document category ('word' | 'powerpoint' | 'excel') for an Office file type.
12
+ */
13
+ export declare function getOfficeDocumentCategory(fileType: OfficeFileType): OfficeDocumentCategory;
14
+ /**
15
+ * Returns standard MIME type for an Office file type.
16
+ */
17
+ export declare function getOfficeMimeType(fileType: OfficeFileType): string;
18
+ /**
19
+ * Metadata used to display themed UI badges, spinners, and icons for Office document types.
20
+ */
21
+ export declare function getOfficeBadgeMeta(fileType: OfficeFileType): OfficeBadgeMeta;
22
+ /**
23
+ * Inspects a target and returns rich Office metadata if it is an Office document.
24
+ */
25
+ export declare function getOfficeDocumentInfo(target: unknown): OfficeDocumentInfo | null;
26
+ export declare const isOfficeDocumentUrl: typeof isOfficeDocument;
27
+ export declare const isOfficeFile: typeof isOfficeDocument;
28
+ export declare const detectOfficeType: typeof getOfficeFileType;
29
+ export declare function isOfficeExtension(ext: string): boolean;
30
+ export declare const SUPPORTED_OFFICE_EXTENSIONS: readonly ["docx", "doc", "pptx", "ppt", "xlsx", "xls"];
@@ -0,0 +1,67 @@
1
+ export type OfficeFileType = 'docx' | 'doc' | 'pptx' | 'ppt' | 'xlsx' | 'xls';
2
+ export type OfficeDocumentCategory = 'word' | 'powerpoint' | 'excel';
3
+ export interface OfficeBadgeMeta {
4
+ category: OfficeDocumentCategory;
5
+ name: string;
6
+ extension: string;
7
+ brandColor: string;
8
+ darkBrandColor: string;
9
+ iconName: string;
10
+ }
11
+ export type OfficeConversionState = 'idle' | 'converting' | 'converted' | 'error';
12
+ export interface OfficeConverterConfig {
13
+ /**
14
+ * Backend conversion endpoint URL (e.g. Gotenberg, custom API proxy, or serverless function).
15
+ * Example: 'http://localhost:3000/api/convert-office' or 'http://localhost:3001/forms/libreoffice/convert'
16
+ */
17
+ endpoint?: string;
18
+ /**
19
+ * Custom HTTP headers to include with the conversion request.
20
+ */
21
+ headers?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
22
+ /**
23
+ * Authorization token (Bearer token, API key, or JWT) sent with conversion requests.
24
+ * Can be a static string or a function/promise returning the current token.
25
+ * Automatically injected as 'Authorization: Bearer <token>' header.
26
+ */
27
+ authToken?: string | (() => string | Promise<string>);
28
+ /**
29
+ * Caching strategy:
30
+ * - 'memory': Cache converted PDF ArrayBuffers in browser memory for the current session (default).
31
+ * - 'session': Cache in sessionStorage.
32
+ * - 'none': Do not cache.
33
+ */
34
+ cache?: 'memory' | 'session' | 'none' | boolean;
35
+ /**
36
+ * Custom conversion hook allowing host application to supply its own conversion logic.
37
+ * If provided, this hook is called instead of the built-in Gotenberg/HTTP dispatcher.
38
+ */
39
+ convert?: (fileOrUrl: string | File | Blob | ArrayBuffer, fileType: OfficeFileType, options?: {
40
+ fileName?: string;
41
+ excelOptions?: OfficeConverterConfig['excelOptions'];
42
+ }) => Promise<ArrayBuffer | Uint8Array | Blob | string>;
43
+ /**
44
+ * Options for Excel worksheet conversion.
45
+ */
46
+ excelOptions?: {
47
+ fitToPageWidth?: boolean;
48
+ includeGridlines?: boolean;
49
+ paperSize?: 'A4' | 'Letter' | 'Legal';
50
+ orientation?: 'landscape' | 'portrait';
51
+ };
52
+ }
53
+ export interface OfficeDocumentInfo {
54
+ fileType: OfficeFileType;
55
+ category: OfficeDocumentCategory;
56
+ fileName?: string;
57
+ originalUrl?: string;
58
+ mimeType: string;
59
+ }
60
+ /**
61
+ * Alias for OfficeConverterConfig for ergonomic naming.
62
+ */
63
+ export type OfficeConversionConfig = OfficeConverterConfig;
64
+ /**
65
+ * Alias for OfficeDocumentInfo / options.
66
+ */
67
+ export type OfficeDocumentOptions = OfficeDocumentInfo;
@@ -0,0 +1,44 @@
1
+ import { OfficeConverterConfig, OfficeFileType, OfficeDocumentInfo } from './types';
2
+ export interface UseOfficeDocumentOptions {
3
+ /** Converter configuration (endpoint, authToken, cache mode, etc.) */
4
+ converterConfig?: OfficeConverterConfig;
5
+ /** Optional file name override */
6
+ fileName?: string;
7
+ /** Whether to automatically convert when the document changes (defaults to true) */
8
+ autoConvert?: boolean;
9
+ }
10
+ export interface UseOfficeDocumentResult {
11
+ /** Whether the input source was identified as a Microsoft Office document */
12
+ isOffice: boolean;
13
+ /** Detected office file type ('docx', 'pptx', 'xlsx', etc.) or null if PDF */
14
+ fileType: OfficeFileType | null;
15
+ /** Detailed metadata about the office document */
16
+ documentInfo: OfficeDocumentInfo | null;
17
+ /** Whether conversion is actively in progress */
18
+ isConverting: boolean;
19
+ /** The final PDF URL ready for the viewer (<TeamSyncViewer fileUrl={pdfUrl} />) */
20
+ pdfUrl: string | null;
21
+ /** Raw PDF ArrayBuffer */
22
+ pdfBuffer: ArrayBuffer | null;
23
+ /** Whether the document was served from memory/session cache */
24
+ fromCache: boolean;
25
+ /** Any error encountered during conversion */
26
+ error: Error | null;
27
+ /** Manually trigger conversion or retry */
28
+ convert: () => Promise<string | null>;
29
+ }
30
+ /**
31
+ * React hook that pre-converts Office documents into viewable PDF URLs before viewer mounting.
32
+ * If the input is already a PDF, it passes through immediately with `isConverting: false`.
33
+ */
34
+ export declare function useOfficeDocument(fileOrUrl: string | File | Blob | ArrayBuffer | null | undefined, options?: UseOfficeDocumentOptions): UseOfficeDocumentResult;
35
+ /**
36
+ * Standalone asynchronous preloader for Office documents.
37
+ * Can be called anywhere (e.g. in loaders, event handlers, or background tasks).
38
+ */
39
+ export declare function preloadOfficeDocument(fileOrUrl: string | File | Blob | ArrayBuffer, config: OfficeConverterConfig, fileName?: string): Promise<{
40
+ pdfUrl: string;
41
+ pdfBuffer: ArrayBuffer;
42
+ fromCache: boolean;
43
+ fileType: OfficeFileType | 'pdf';
44
+ }>;
@@ -0,0 +1 @@
1
+ export declare const VERSION: string;