mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-10 01:09:43 +02:00
feat(preview): render XLSX spreadsheets in the file-preview overlay
xlsx files were download-only. Add a read-only, virtualized preview (sheet tabs, number formats, merges, theme colours) parsed entirely in a browser Web Worker with exceljs and fflate, loaded only when a spreadsheet is opened. The workbook is checked against ZIP-bomb, entry and cell limits before exceljs loads; cell text is written with textContent, formulas are never evaluated and nothing referenced by the workbook is fetched. On the server xlsx only joins the existing allowlist and classification, with a 10 MB cap on ?preview=true. xls and ods stay download-only.
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Copy the XLSX preview's browser bundles (exceljs, fflate) into a public vendor
|
||||
* dir. Run by postinstall for dev (src/web/public/vendor, gitignored) and by
|
||||
* build.mjs for prod (dist/web/public/vendor). Both packages are pinned exactly
|
||||
* in package.json, and check-public-assets.mjs hashes the output into
|
||||
* SPREADSHEET_ASSET_VERSION (the worker's cache-bust token), so a version bump
|
||||
* that changes the bytes fails that check until the token is refreshed.
|
||||
* Source-map comments are stripped: the maps are not shipped.
|
||||
*/
|
||||
|
||||
import { createRequire } from 'node:module';
|
||||
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
||||
import { dirname, join, resolve } from 'node:path';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const outputDir = resolve(process.argv[2] || join(import.meta.dirname, '..', 'src', 'web', 'public', 'vendor'));
|
||||
const excelSource = require.resolve('exceljs/dist/exceljs.min.js');
|
||||
const fflateSource = join(dirname(require.resolve('fflate')), '..', 'umd', 'index.js');
|
||||
|
||||
function copyBrowserBundle(source, outputName) {
|
||||
const content = readFileSync(source, 'utf8').replace(/\n?\/\/# sourceMappingURL=.*(?:\n|$)/g, '\n');
|
||||
if (/sourceMappingURL/.test(content)) {
|
||||
throw new Error(`Failed to strip sourceMappingURL from ${outputName}`);
|
||||
}
|
||||
writeFileSync(join(outputDir, outputName), content, 'utf8');
|
||||
}
|
||||
|
||||
mkdirSync(outputDir, { recursive: true });
|
||||
copyBrowserBundle(excelSource, 'exceljs.min.js');
|
||||
copyBrowserBundle(fflateSource, 'fflate.min.js');
|
||||
Reference in New Issue
Block a user