// Packt die Erweiterung als ZIP (für „Entpackte Erweiterung laden“ nicht nötig, aber für den Chrome Web Store oder zum Weitergeben). // Start: node pack.mjs [Zielordner] (Standard: ../release). Enthalten sind nur die Laufzeitdateien, keine Tests. import { readFileSync, readdirSync, statSync, mkdirSync, writeFileSync } from 'node:fs'; import { join, relative, sep } from 'node:path'; import { deflateRawSync, crc32 } from 'node:zlib'; import { fileURLToPath } from 'node:url'; const root = fileURLToPath(new URL('.', import.meta.url)); const out = process.argv[2] || join(root, '..', 'release'); const include = ['manifest.json', 'background.js', 'app.html', 'app.css', 'app.js', 'lib', 'views', 'icons']; const files = []; (function walk(p) { const st = statSync(p); if (st.isDirectory()) for (const f of readdirSync(p).sort()) walk(join(p, f)); else files.push(p); })(root); const wanted = files.filter((f) => include.some((i) => relative(root, f).split(sep)[0] === i)).sort(); const version = JSON.parse(readFileSync(join(root, 'manifest.json'), 'utf8')).version; const parts = []; const central = []; let offset = 0; const dos = new Date(2026, 0, 1, 0, 0, 0); // fester Zeitstempel: gleiches Ergebnis bei jedem Packen const dosTime = (dos.getHours() << 11) | (dos.getMinutes() << 5) | (dos.getSeconds() >> 1); const dosDate = ((dos.getFullYear() - 1980) << 9) | ((dos.getMonth() + 1) << 5) | dos.getDate(); for (const file of wanted) { const name = Buffer.from(relative(root, file).split(sep).join('/'), 'utf8'); // immer mit / (Chrome verlangt das) const data = readFileSync(file); const comp = deflateRawSync(data, { level: 9 }); const crc = crc32(data) >>> 0; const local = Buffer.alloc(30); local.writeUInt32LE(0x04034b50, 0); local.writeUInt16LE(20, 4); local.writeUInt16LE(0x0800, 6); local.writeUInt16LE(8, 8); local.writeUInt16LE(dosTime, 10); local.writeUInt16LE(dosDate, 12); local.writeUInt32LE(crc, 14); local.writeUInt32LE(comp.length, 18); local.writeUInt32LE(data.length, 22); local.writeUInt16LE(name.length, 26); parts.push(local, name, comp); const c = Buffer.alloc(46); c.writeUInt32LE(0x02014b50, 0); c.writeUInt16LE(20, 4); c.writeUInt16LE(20, 6); c.writeUInt16LE(0x0800, 8); c.writeUInt16LE(8, 10); c.writeUInt16LE(dosTime, 12); c.writeUInt16LE(dosDate, 14); c.writeUInt32LE(crc, 16); c.writeUInt32LE(comp.length, 20); c.writeUInt32LE(data.length, 24); c.writeUInt16LE(name.length, 28); c.writeUInt32LE(offset, 42); central.push(c, name); offset += 30 + name.length + comp.length; } const cd = Buffer.concat(central); const end = Buffer.alloc(22); end.writeUInt32LE(0x06054b50, 0); end.writeUInt16LE(wanted.length, 8); end.writeUInt16LE(wanted.length, 10); end.writeUInt32LE(cd.length, 12); end.writeUInt32LE(offset, 16); mkdirSync(out, { recursive: true }); const target = join(out, `deskhub-chrome-erweiterung-${version}.zip`); writeFileSync(target, Buffer.concat([...parts, cd, end])); console.log(`${wanted.length} Dateien -> ${target}`);