@file-viewer/core 2.4.0 → 3.0.1
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/README.en.md +18 -1
- package/README.md +18 -1
- package/dist/config/options.js +9 -3
- package/dist/contracts/types.d.ts +249 -9
- package/dist/export.d.ts +10 -0
- package/dist/export.js +9 -0
- package/dist/exportDocument.d.ts +36 -0
- package/dist/exportDocument.js +894 -0
- package/dist/features/document/zoom.d.ts +1 -0
- package/dist/features/document/zoom.js +3 -0
- package/dist/features/printMask.js +138 -13
- package/dist/headless.d.ts +2 -2
- package/dist/headless.js +1 -1
- package/dist/i18n/messages.de.js +3 -0
- package/dist/i18n/messages.ja.js +3 -0
- package/dist/i18n/messages.js +6 -0
- package/dist/index.d.ts +5 -4
- package/dist/index.js +3 -2
- package/dist/output/export.d.ts +3 -24
- package/dist/output/export.js +27 -372
- package/dist/output/printLayout.js +10 -0
- package/dist/platform/assets.d.ts +69 -2
- package/dist/platform/assets.js +532 -29
- package/dist/registry/capabilities.d.ts +2 -2
- package/dist/registry/formats.d.ts +4 -4
- package/dist/registry/formats.generated.d.ts +273 -20
- package/dist/registry/formats.generated.js +463 -2
- package/dist/registry/registry.js +153 -11
- package/dist/renderers/index.d.ts +270 -17
- package/dist/security/svgResources.d.ts +13 -0
- package/dist/security/svgResources.js +177 -0
- package/dist/viewer/createViewer.js +42 -0
- package/dist/viewer/operations.d.ts +1 -0
- package/dist/viewer/operations.js +68 -5
- package/dist/viewer/state.js +1 -0
- package/package.json +9 -1
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
const SVG_URL_ATTRIBUTES = new Set(['href', 'xlink:href', 'src', 'poster']);
|
|
2
|
+
const SAFE_EMBEDDED_IMAGE_DATA_URL = /^data:image\/(?:avif|bmp|gif|jpeg|png|webp|x-icon);base64,[A-Za-z0-9+/=\s]+$/i;
|
|
3
|
+
const stripResourceUrlControlCharacters = (value) => {
|
|
4
|
+
let normalized = '';
|
|
5
|
+
for (const character of value) {
|
|
6
|
+
const codePoint = character.charCodeAt(0);
|
|
7
|
+
if (codePoint <= 0x20 || (codePoint >= 0x7f && codePoint <= 0x9f))
|
|
8
|
+
continue;
|
|
9
|
+
normalized += character;
|
|
10
|
+
}
|
|
11
|
+
return normalized.trim();
|
|
12
|
+
};
|
|
13
|
+
const isSafeSvgAnchorUrl = (value) => {
|
|
14
|
+
const normalized = stripResourceUrlControlCharacters(value);
|
|
15
|
+
if (!normalized)
|
|
16
|
+
return false;
|
|
17
|
+
if (/^#[A-Za-z0-9_.:-]+$/.test(normalized))
|
|
18
|
+
return true;
|
|
19
|
+
if (/^(?:https?|mailto|tel):/i.test(normalized))
|
|
20
|
+
return true;
|
|
21
|
+
return !normalized.includes(':') &&
|
|
22
|
+
!normalized.startsWith('//') &&
|
|
23
|
+
!normalized.startsWith('\\');
|
|
24
|
+
};
|
|
25
|
+
const isSafeEmbeddedSvgUrl = (value, allowFragment) => {
|
|
26
|
+
const normalized = stripResourceUrlControlCharacters(value);
|
|
27
|
+
if (allowFragment && /^#[A-Za-z0-9_.:-]+$/.test(normalized))
|
|
28
|
+
return true;
|
|
29
|
+
if (/^blob:/i.test(normalized))
|
|
30
|
+
return true;
|
|
31
|
+
return SAFE_EMBEDDED_IMAGE_DATA_URL.test(normalized);
|
|
32
|
+
};
|
|
33
|
+
const normalizeCssUrl = (value) => {
|
|
34
|
+
let normalized = value.trim();
|
|
35
|
+
const quote = normalized[0];
|
|
36
|
+
if ((quote === '"' || quote === "'") && normalized[normalized.length - 1] === quote) {
|
|
37
|
+
normalized = normalized.slice(1, -1).trim();
|
|
38
|
+
}
|
|
39
|
+
return stripResourceUrlControlCharacters(normalized);
|
|
40
|
+
};
|
|
41
|
+
const isSafeSvgCssUrl = (value) => {
|
|
42
|
+
const normalized = normalizeCssUrl(value);
|
|
43
|
+
return /^#[A-Za-z0-9_.:-]+$/.test(normalized) ||
|
|
44
|
+
/^blob:/i.test(normalized) ||
|
|
45
|
+
SAFE_EMBEDDED_IMAGE_DATA_URL.test(normalized);
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Keep ordinary SVG styles while preventing imports and resource requests.
|
|
49
|
+
* Obfuscated URL tokens fail closed instead of depending on parser quirks.
|
|
50
|
+
*/
|
|
51
|
+
export const sanitizeFileViewerSvgCss = (value) => {
|
|
52
|
+
const normalizedCharacters = [];
|
|
53
|
+
for (const character of value) {
|
|
54
|
+
const codePoint = character.charCodeAt(0);
|
|
55
|
+
const disallowedControl = codePoint <= 0x08 || codePoint === 0x0b || codePoint === 0x0c ||
|
|
56
|
+
(codePoint >= 0x0e && codePoint <= 0x1f) || (codePoint >= 0x7f && codePoint <= 0x9f);
|
|
57
|
+
if (!disallowedControl)
|
|
58
|
+
normalizedCharacters.push(character);
|
|
59
|
+
}
|
|
60
|
+
const normalized = normalizedCharacters.join('');
|
|
61
|
+
if (normalized.includes('\\') || normalized.includes('/*') || /@import\b/i.test(normalized)) {
|
|
62
|
+
return '';
|
|
63
|
+
}
|
|
64
|
+
const chunks = [];
|
|
65
|
+
let segmentStart = 0;
|
|
66
|
+
let cursor = 0;
|
|
67
|
+
while (cursor < normalized.length) {
|
|
68
|
+
const hasUrlPrefix = (normalized.charCodeAt(cursor) | 0x20) === 0x75 &&
|
|
69
|
+
(normalized.charCodeAt(cursor + 1) | 0x20) === 0x72 &&
|
|
70
|
+
(normalized.charCodeAt(cursor + 2) | 0x20) === 0x6c;
|
|
71
|
+
if (!hasUrlPrefix) {
|
|
72
|
+
cursor += 1;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
let open = cursor + 3;
|
|
76
|
+
while (open < normalized.length && normalized[open].trim() === '')
|
|
77
|
+
open += 1;
|
|
78
|
+
if (normalized[open] !== '(') {
|
|
79
|
+
cursor += 1;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
let close = open + 1;
|
|
83
|
+
while (close < normalized.length && normalized[close] !== ')')
|
|
84
|
+
close += 1;
|
|
85
|
+
if (close >= normalized.length)
|
|
86
|
+
return '';
|
|
87
|
+
const target = normalized.slice(open + 1, close);
|
|
88
|
+
chunks.push(normalized.slice(segmentStart, cursor));
|
|
89
|
+
chunks.push(isSafeSvgCssUrl(target) ? `url(${target})` : 'none');
|
|
90
|
+
cursor = close + 1;
|
|
91
|
+
segmentStart = cursor;
|
|
92
|
+
}
|
|
93
|
+
chunks.push(normalized.slice(segmentStart));
|
|
94
|
+
return chunks.join('');
|
|
95
|
+
};
|
|
96
|
+
/** Remove executable attributes and every SVG resource URL that can load data remotely. */
|
|
97
|
+
export const sanitizeFileViewerSvgResources = (root) => {
|
|
98
|
+
root.querySelectorAll('*').forEach(element => {
|
|
99
|
+
for (const attribute of Array.from(element.attributes)) {
|
|
100
|
+
const name = attribute.name.toLowerCase();
|
|
101
|
+
if (name.startsWith('on') || name === 'srcdoc') {
|
|
102
|
+
element.removeAttribute(attribute.name);
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (name === 'style') {
|
|
106
|
+
const sanitizedStyle = sanitizeFileViewerSvgCss(attribute.value);
|
|
107
|
+
if (sanitizedStyle) {
|
|
108
|
+
element.setAttribute(attribute.name, sanitizedStyle);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
element.removeAttribute(attribute.name);
|
|
112
|
+
}
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (SVG_URL_ATTRIBUTES.has(name)) {
|
|
116
|
+
const localName = element.localName.toLowerCase();
|
|
117
|
+
const isAnchor = localName === 'a' && name === 'href';
|
|
118
|
+
const allowFragment = localName === 'use' || localName === 'mpath';
|
|
119
|
+
const safe = isAnchor
|
|
120
|
+
? isSafeSvgAnchorUrl(attribute.value)
|
|
121
|
+
: isSafeEmbeddedSvgUrl(attribute.value, allowFragment);
|
|
122
|
+
if (safe) {
|
|
123
|
+
attribute.value = stripResourceUrlControlCharacters(attribute.value);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
element.removeAttribute(attribute.name);
|
|
127
|
+
}
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if (/url\s*\(/i.test(attribute.value)) {
|
|
131
|
+
const sanitizedValue = sanitizeFileViewerSvgCss(attribute.value);
|
|
132
|
+
if (sanitizedValue) {
|
|
133
|
+
element.setAttribute(attribute.name, sanitizedValue);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
element.removeAttribute(attribute.name);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
root.querySelectorAll('style').forEach(style => {
|
|
142
|
+
const sanitizedStyle = sanitizeFileViewerSvgCss(style.textContent || '');
|
|
143
|
+
if (sanitizedStyle) {
|
|
144
|
+
style.textContent = sanitizedStyle;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
style.remove();
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
};
|
|
151
|
+
const canonicalizeMermaidSourceForResourceScan = (source) => {
|
|
152
|
+
let output = '';
|
|
153
|
+
for (const character of source) {
|
|
154
|
+
const codePoint = character.charCodeAt(0);
|
|
155
|
+
if (codePoint === 0 || (codePoint >= 0x7f && codePoint <= 0x9f))
|
|
156
|
+
continue;
|
|
157
|
+
output += codePoint < 0x20 && character !== '\n' && character !== '\r' && character !== '\t'
|
|
158
|
+
? ' '
|
|
159
|
+
: character;
|
|
160
|
+
}
|
|
161
|
+
return output;
|
|
162
|
+
};
|
|
163
|
+
/**
|
|
164
|
+
* Mermaid 11 resolves image-node URLs with `new Image()` while rendering,
|
|
165
|
+
* before its SVG can be sanitized. Reject image metadata and explicit remote
|
|
166
|
+
* URLs before calling Mermaid so an untrusted diagram cannot initiate I/O.
|
|
167
|
+
*/
|
|
168
|
+
export const assertFileViewerMermaidSourceHasNoExternalResources = (source) => {
|
|
169
|
+
const normalized = canonicalizeMermaidSourceForResourceScan(String(source || ''));
|
|
170
|
+
const compact = normalized.replace(/[\t\r\n ]+/g, '');
|
|
171
|
+
const hasImageMetadata = /(?:^|[,{])\s*(?:img|["']img["'])\s*:/im.test(normalized);
|
|
172
|
+
const hasRemoteUrl = /(?:https?|ftp):\/\//i.test(compact) ||
|
|
173
|
+
/(?:^|[\s"'(=:,])(?:\/\/|\\\\)[A-Za-z0-9]/m.test(normalized);
|
|
174
|
+
if (hasImageMetadata || hasRemoteUrl) {
|
|
175
|
+
throw new Error('Mermaid diagrams may not load external image resources.');
|
|
176
|
+
}
|
|
177
|
+
};
|
|
@@ -319,6 +319,47 @@ export const createViewer = (container, createOptions = {}) => {
|
|
|
319
319
|
registerHandler,
|
|
320
320
|
});
|
|
321
321
|
};
|
|
322
|
+
const renderNestedBuffer = async (buffer, type, target, context) => {
|
|
323
|
+
var _a;
|
|
324
|
+
const inheritedOptions = (context === null || context === void 0 ? void 0 : context.options) || options;
|
|
325
|
+
const nestedViewer = createViewer(target, {
|
|
326
|
+
registry,
|
|
327
|
+
options: {
|
|
328
|
+
...inheritedOptions,
|
|
329
|
+
// The parent already resolved its renderer assembly into `registry`.
|
|
330
|
+
// Reuse that exact registry without reinstalling presets or mutating a
|
|
331
|
+
// shared registry while an attachment is open.
|
|
332
|
+
autoRenderers: false,
|
|
333
|
+
rendererMode: 'extend',
|
|
334
|
+
renderers: undefined,
|
|
335
|
+
preset: undefined,
|
|
336
|
+
presets: undefined,
|
|
337
|
+
},
|
|
338
|
+
signal: context === null || context === void 0 ? void 0 : context.signal,
|
|
339
|
+
renderPurpose: (context === null || context === void 0 ? void 0 : context.renderPurpose) || createOptions.renderPurpose || 'preview',
|
|
340
|
+
});
|
|
341
|
+
try {
|
|
342
|
+
await nestedViewer.load({
|
|
343
|
+
buffer,
|
|
344
|
+
filename: (context === null || context === void 0 ? void 0 : context.filename) || `attachment.${type || 'bin'}`,
|
|
345
|
+
type,
|
|
346
|
+
}, {
|
|
347
|
+
signal: context === null || context === void 0 ? void 0 : context.signal,
|
|
348
|
+
});
|
|
349
|
+
if ((_a = context === null || context === void 0 ? void 0 : context.signal) === null || _a === void 0 ? void 0 : _a.aborted) {
|
|
350
|
+
await nestedViewer.destroy('replace');
|
|
351
|
+
return undefined;
|
|
352
|
+
}
|
|
353
|
+
return {
|
|
354
|
+
$el: target,
|
|
355
|
+
destroy: () => nestedViewer.destroy('component-unmount'),
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
catch (error) {
|
|
359
|
+
await nestedViewer.destroy('replace');
|
|
360
|
+
throw error;
|
|
361
|
+
}
|
|
362
|
+
};
|
|
322
363
|
const buildCurrentLifecycleContext = () => {
|
|
323
364
|
const source = currentSource || normalizeSource({});
|
|
324
365
|
return buildFileViewerLifecycleContextFromNormalizedSource({
|
|
@@ -514,6 +555,7 @@ export const createViewer = (container, createOptions = {}) => {
|
|
|
514
555
|
},
|
|
515
556
|
renderContext: {
|
|
516
557
|
renderPurpose: createOptions.renderPurpose || 'preview',
|
|
558
|
+
renderNestedBuffer,
|
|
517
559
|
},
|
|
518
560
|
});
|
|
519
561
|
}
|
|
@@ -87,6 +87,7 @@ export declare const resolveFileViewerOriginalFilename: (source: FileViewerOrigi
|
|
|
87
87
|
export declare const resolveFileViewerOperationFilename: ({ filename, source, fallback, }: ResolveFileViewerOperationFilenameInput) => string;
|
|
88
88
|
export declare const resolveFileViewerOperationActionErrorMessage: ({ context, formatErrorMessage, prefixes, i18n, }: ResolveFileViewerOperationActionErrorMessageInput) => string;
|
|
89
89
|
export declare const hasFileViewerOriginalSource: (source: FileViewerOriginalSourceState) => boolean;
|
|
90
|
+
export declare const replaceFileViewerPrintDocument: (targetDocument: Document, sanitizedRoot: HTMLHtmlElement) => void;
|
|
90
91
|
export declare const executeFileViewerDownloadOperation: ({ source, filename, beforeOperation, i18n, throwOnMissingSource, }: ExecuteFileViewerDownloadOperationInput) => Promise<boolean>;
|
|
91
92
|
export declare const executeFileViewerExportHtmlOperation: ({ download, filename, beforeOperation, i18n, ...input }: ExecuteFileViewerExportHtmlOperationInput) => Promise<string>;
|
|
92
93
|
export declare const executeFileViewerPrintOperation: ({ autoPrint, beforeOperation, i18n, openWindow, printAvailable, printWindow, ...input }: ExecuteFileViewerPrintOperationInput) => Promise<boolean>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { triggerFileViewerBlobDownload, triggerFileViewerUrlDownload, waitForFileViewerPrintWindowReady, } from '../output/export.js';
|
|
2
2
|
import { DEFAULT_FILE_VIEWER_SOURCE_FILENAME } from '../source/index.js';
|
|
3
3
|
import { translateFileViewerMessage, } from '../i18n/messages.js';
|
|
4
4
|
export const DEFAULT_FILE_VIEWER_PREVIEW_TITLE = 'file-viewer-preview';
|
|
@@ -65,6 +65,7 @@ const buildRenderedHtmlDocumentFromOperation = async (mode, { source, title, fil
|
|
|
65
65
|
if (!source) {
|
|
66
66
|
throw new Error(translateFileViewerMessage(i18n, 'error.noExportContent'));
|
|
67
67
|
}
|
|
68
|
+
const { buildFileViewerRenderedHtmlDocument } = await import('../export.js');
|
|
68
69
|
return buildFileViewerRenderedHtmlDocument({
|
|
69
70
|
source,
|
|
70
71
|
mode,
|
|
@@ -77,6 +78,69 @@ const buildRenderedHtmlDocumentFromOperation = async (mode, { source, title, fil
|
|
|
77
78
|
mask: mode === 'print' ? mask : null,
|
|
78
79
|
});
|
|
79
80
|
};
|
|
81
|
+
const buildRenderedDomDocumentFromOperation = async ({ source, title, filename, adapter = null, watermarkInlineStyle, mask = null, i18n, }) => {
|
|
82
|
+
if (!source) {
|
|
83
|
+
throw new Error(translateFileViewerMessage(i18n, 'error.noExportContent'));
|
|
84
|
+
}
|
|
85
|
+
const { buildFileViewerRenderedDomDocument } = await import('../export.js');
|
|
86
|
+
return buildFileViewerRenderedDomDocument({
|
|
87
|
+
source,
|
|
88
|
+
mode: 'print',
|
|
89
|
+
title: resolveFileViewerOperationFilename({
|
|
90
|
+
filename: title || filename,
|
|
91
|
+
fallback: DEFAULT_FILE_VIEWER_PREVIEW_TITLE,
|
|
92
|
+
}),
|
|
93
|
+
adapter,
|
|
94
|
+
watermarkInlineStyle,
|
|
95
|
+
mask,
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
export const replaceFileViewerPrintDocument = (targetDocument, sanitizedRoot) => {
|
|
99
|
+
const importedRoot = targetDocument.importNode(sanitizedRoot, true);
|
|
100
|
+
const currentRoot = targetDocument.documentElement;
|
|
101
|
+
if (currentRoot) {
|
|
102
|
+
currentRoot.replaceWith(importedRoot);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
targetDocument.append(importedRoot);
|
|
106
|
+
}
|
|
107
|
+
if (!targetDocument.doctype) {
|
|
108
|
+
targetDocument.insertBefore(targetDocument.implementation.createDocumentType('html', '', ''), importedRoot);
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
const FILE_VIEWER_PRINT_STANDARDS_DOCUMENT = '<!doctype html><html lang="en"><head><meta charset="utf-8"></head><body></body></html>';
|
|
112
|
+
const ensureFileViewerPrintStandardsMode = async (targetWindow) => {
|
|
113
|
+
if (targetWindow.document.compatMode === 'CSS1Compat') {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const targetGlobal = targetWindow;
|
|
117
|
+
const objectUrl = targetGlobal.URL.createObjectURL(new targetGlobal.Blob([FILE_VIEWER_PRINT_STANDARDS_DOCUMENT], {
|
|
118
|
+
type: 'text/html;charset=utf-8',
|
|
119
|
+
}));
|
|
120
|
+
try {
|
|
121
|
+
await new Promise((resolve, reject) => {
|
|
122
|
+
let settled = false;
|
|
123
|
+
const finish = () => {
|
|
124
|
+
if (settled)
|
|
125
|
+
return;
|
|
126
|
+
settled = true;
|
|
127
|
+
globalThis.clearTimeout(timeoutId);
|
|
128
|
+
if (targetWindow.document.compatMode === 'CSS1Compat') {
|
|
129
|
+
resolve();
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
reject(new Error('Unable to initialize the print window in standards mode.'));
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
const timeoutId = globalThis.setTimeout(finish, 1500);
|
|
136
|
+
targetWindow.addEventListener('load', finish, { once: true });
|
|
137
|
+
targetWindow.location.replace(objectUrl);
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
finally {
|
|
141
|
+
targetGlobal.URL.revokeObjectURL(objectUrl);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
80
144
|
export const executeFileViewerDownloadOperation = async ({ source, filename, beforeOperation, i18n, throwOnMissingSource = true, }) => {
|
|
81
145
|
var _a;
|
|
82
146
|
if (!hasFileViewerOriginalSource(source)) {
|
|
@@ -145,16 +209,15 @@ export const executeFileViewerPrintOperation = async ({ autoPrint = true, before
|
|
|
145
209
|
if (!await runBeforeOperation(beforeOperation, 'print')) {
|
|
146
210
|
return false;
|
|
147
211
|
}
|
|
148
|
-
const
|
|
212
|
+
const printableRoot = await buildRenderedDomDocumentFromOperation({ ...input, i18n });
|
|
149
213
|
const targetWindow = printWindow ||
|
|
150
214
|
(openWindow === null || openWindow === void 0 ? void 0 : openWindow()) ||
|
|
151
215
|
(typeof window !== 'undefined' ? window.open('', '_blank') : null);
|
|
152
216
|
if (!targetWindow) {
|
|
153
217
|
throw new Error(translateFileViewerMessage(i18n, 'error.printWindowBlocked'));
|
|
154
218
|
}
|
|
155
|
-
targetWindow
|
|
156
|
-
targetWindow.document
|
|
157
|
-
targetWindow.document.close();
|
|
219
|
+
await ensureFileViewerPrintStandardsMode(targetWindow);
|
|
220
|
+
replaceFileViewerPrintDocument(targetWindow.document, printableRoot);
|
|
158
221
|
targetWindow.focus();
|
|
159
222
|
await waitForFileViewerPrintWindowReady(targetWindow);
|
|
160
223
|
if (autoPrint !== false) {
|
package/dist/viewer/state.js
CHANGED
|
@@ -47,6 +47,7 @@ const rendererPackageById = {
|
|
|
47
47
|
ofd: '@file-viewer/renderer-ofd',
|
|
48
48
|
typst: '@file-viewer/renderer-typst',
|
|
49
49
|
archive: '@file-viewer/renderer-archive',
|
|
50
|
+
chm: '@file-viewer/renderer-chm',
|
|
50
51
|
email: '@file-viewer/renderer-email',
|
|
51
52
|
eda: '@file-viewer/renderer-eda',
|
|
52
53
|
cad: '@file-viewer/renderer-cad',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@file-viewer/core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Framework-neutral modular TypeScript core for File Viewer renderer orchestration, lifecycle APIs, search, zoom, print, and export",
|
|
@@ -62,6 +62,11 @@
|
|
|
62
62
|
"import": "./dist/browser.js",
|
|
63
63
|
"default": "./dist/browser.js"
|
|
64
64
|
},
|
|
65
|
+
"./export": {
|
|
66
|
+
"types": "./dist/export.d.ts",
|
|
67
|
+
"import": "./dist/export.js",
|
|
68
|
+
"default": "./dist/export.js"
|
|
69
|
+
},
|
|
65
70
|
"./print-mask": {
|
|
66
71
|
"types": "./dist/print-mask.d.ts",
|
|
67
72
|
"import": "./dist/print-mask.js",
|
|
@@ -84,6 +89,9 @@
|
|
|
84
89
|
"README.en.md",
|
|
85
90
|
"LICENSE"
|
|
86
91
|
],
|
|
92
|
+
"dependencies": {
|
|
93
|
+
"dompurify": "3.4.14"
|
|
94
|
+
},
|
|
87
95
|
"devDependencies": {
|
|
88
96
|
"typescript": "^6.0.3"
|
|
89
97
|
},
|