mirror of
https://github.com/amitwh/markdown-converter.git
synced 2026-10-01 17:29:29 +05:30
feat(legal): bundle small dependencies, add notices, credits, and GPL source offers
Bundle (v4.7.0): - MarkItDown frozen to a single ~75MB per-platform binary (PyInstaller via npm run bundle:markitdown; ML extras excluded) — built and verified locally: HTML/XLSX/PDF conversions pass through the bundled binary, and the app resolves bin/linux/markitdown first at runtime - Packaging copies bundled markitdown alongside Pandoc for win/mac/linux; FFmpeg/sharp/KaTeX/fonts were already bundled Legal artifacts: - THIRD-PARTY-NOTICES.md: complete license inventory of everything distributed (binaries, npm runtime deps, fonts, embedded Python packages) - SOURCES.md: GPL §3(b) written source offers for Pandoc 3.9.0.2, ffmpeg-static's GPL build, and the PyInstaller bootloader; LGPL relinking note for libvips - third-party-licenses/: canonical GPL-2.0, LGPL-2.1, MPL-2.0, Apache-2.0, OFL-1.1, PSF-Python texts - Help > Third-Party Notices & Licenses: in-app viewer for both documents - README: 'Bundled Dependencies, Legal Notices & Credits' section Hardening: - download-tools.js now SHA-256 pins every artifact, verifies after download AND against the cache on every run, and hard-fails on mismatch (closes security finding D6) Large tools intentionally not bundled (documented): LibreOffice, MiKTeX/TeX Live, ImageMagick, PlantUML+JRE, Calibre. 637/637 tests green; lint clean; clean boot; bundled binary verified.
This commit is contained in:
+43
-10
@@ -23,15 +23,47 @@ const CONVERT_TIMEOUT_MS = 120000;
|
||||
const MAX_OUTPUT_BUFFER = 20 * 1024 * 1024;
|
||||
|
||||
/**
|
||||
* Candidate command templates probed in order. `argsPrefix` is prepended to
|
||||
* the user path when invoking (e.g. ['-m', 'markitdown'] for module-style
|
||||
* invocation through a python launcher).
|
||||
* Path to the bundled markitdown binary (built by scripts/bundle-markitdown.js
|
||||
* via PyInstaller), when the app ships one. Mirrors getPandocPath's layout:
|
||||
* dev: bin/<platform>/markitdown · packaged: <resourcesPath>/bin/markitdown.
|
||||
* Returns null when no bundle exists (PATH/python fallbacks apply).
|
||||
*/
|
||||
const COMMAND_CANDIDATES = [
|
||||
{ command: 'markitdown', argsPrefix: [] },
|
||||
{ command: process.platform === 'win32' ? 'python' : 'python3', argsPrefix: ['-m', 'markitdown'] },
|
||||
{ command: 'python3', argsPrefix: ['-m', 'markitdown'] },
|
||||
];
|
||||
function getBundledMarkItDownPath() {
|
||||
const pathUtil = require('path');
|
||||
const fs = require('fs');
|
||||
const exe = process.platform === 'win32' ? 'markitdown.exe' : 'markitdown';
|
||||
if (typeof process === 'object' && process.resourcesPath && !process.resourcesPath.includes('node_modules')) {
|
||||
// Packaged (Electron) — resourcesPath only exists in a real app runtime
|
||||
try {
|
||||
const electron = require('electron');
|
||||
if (electron.app?.isPackaged) {
|
||||
const packaged = pathUtil.join(process.resourcesPath, 'bin', exe);
|
||||
if (fs.existsSync(packaged)) return packaged;
|
||||
}
|
||||
} catch {
|
||||
/* not running under Electron (tests) — fall through to dev layout */
|
||||
}
|
||||
}
|
||||
const dev = pathUtil.join(__dirname, '..', '..', 'bin', process.platform, exe);
|
||||
return fs.existsSync(dev) ? dev : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Candidate command templates probed in order (bundled binary first). The
|
||||
* bundled candidate is verified with the same --version probe as the rest.
|
||||
*/
|
||||
function commandCandidates() {
|
||||
const bundled = getBundledMarkItDownPath();
|
||||
const candidates = [];
|
||||
if (bundled) candidates.push({ command: bundled, argsPrefix: [], bundled: true });
|
||||
candidates.push({ command: 'markitdown', argsPrefix: [] });
|
||||
candidates.push({
|
||||
command: process.platform === 'win32' ? 'python' : 'python3',
|
||||
argsPrefix: ['-m', 'markitdown'],
|
||||
});
|
||||
candidates.push({ command: 'python3', argsPrefix: ['-m', 'markitdown'] });
|
||||
return candidates;
|
||||
}
|
||||
|
||||
/** Run one probe: `--version` exits 0 when the tool is importable. */
|
||||
function probeCandidate(runner, candidate) {
|
||||
@@ -61,7 +93,7 @@ function probeCandidate(runner, candidate) {
|
||||
* @returns {Promise<{command: string, argsPrefix: string[], version: string|null}|null>}
|
||||
*/
|
||||
async function resolveMarkItDown(runner) {
|
||||
for (const candidate of COMMAND_CANDIDATES) {
|
||||
for (const candidate of commandCandidates()) {
|
||||
const resolved = await probeCandidate(runner, candidate);
|
||||
if (resolved) return resolved;
|
||||
}
|
||||
@@ -153,5 +185,6 @@ async function convertToMarkdown(inputPath, options = {}) {
|
||||
module.exports = {
|
||||
resolveMarkItDown,
|
||||
convertToMarkdown,
|
||||
COMMAND_CANDIDATES,
|
||||
commandCandidates,
|
||||
getBundledMarkItDownPath,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user