@condorinst/mobile-bridge 0.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 +350 -0
- package/LICENSE +14 -0
- package/README.md +396 -0
- package/dist/cli.cjs +194 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.js +193 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +1045 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +624 -0
- package/dist/index.d.ts +624 -0
- package/dist/index.js +1005 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/cli.ts
|
|
4
|
+
import { mkdirSync, writeFileSync } from "fs";
|
|
5
|
+
import { dirname as dirname2, resolve as resolve2 } from "path";
|
|
6
|
+
|
|
7
|
+
// src/cli-core.ts
|
|
8
|
+
import { createHash } from "crypto";
|
|
9
|
+
import { readFileSync } from "fs";
|
|
10
|
+
import { dirname, extname, resolve } from "path";
|
|
11
|
+
import { strToU8, zipSync } from "fflate";
|
|
12
|
+
import { parse } from "node-html-parser";
|
|
13
|
+
var DEFAULT_MAX_BYTES = 2 * 1024 * 1024;
|
|
14
|
+
var FIXED_MTIME = /* @__PURE__ */ new Date("2000-01-01T00:00:00Z");
|
|
15
|
+
var MIME_TYPES = {
|
|
16
|
+
".png": "image/png",
|
|
17
|
+
".jpg": "image/jpeg",
|
|
18
|
+
".jpeg": "image/jpeg",
|
|
19
|
+
".gif": "image/gif",
|
|
20
|
+
".webp": "image/webp",
|
|
21
|
+
".avif": "image/avif",
|
|
22
|
+
".svg": "image/svg+xml",
|
|
23
|
+
".ico": "image/x-icon",
|
|
24
|
+
".bmp": "image/bmp",
|
|
25
|
+
".woff": "font/woff",
|
|
26
|
+
".woff2": "font/woff2",
|
|
27
|
+
".ttf": "font/ttf",
|
|
28
|
+
".otf": "font/otf",
|
|
29
|
+
".eot": "application/vnd.ms-fontobject",
|
|
30
|
+
".mp3": "audio/mpeg",
|
|
31
|
+
".mp4": "video/mp4",
|
|
32
|
+
".webm": "video/webm",
|
|
33
|
+
".json": "application/json"
|
|
34
|
+
};
|
|
35
|
+
function isExternalOrInline(url) {
|
|
36
|
+
return /^(https?:)?\/\//i.test(url) || /^data:/i.test(url) || /^(mailto:|tel:|#)/i.test(url);
|
|
37
|
+
}
|
|
38
|
+
function stripQueryHash(url) {
|
|
39
|
+
return url.split(/[?#]/)[0] ?? url;
|
|
40
|
+
}
|
|
41
|
+
function resolveLocal(htmlRoot, resourceDir, url) {
|
|
42
|
+
const clean = stripQueryHash(url);
|
|
43
|
+
return clean.startsWith("/") ? resolve(htmlRoot, `.${clean}`) : resolve(resourceDir, clean);
|
|
44
|
+
}
|
|
45
|
+
function toDataUri(filePath) {
|
|
46
|
+
const bytes = readFileSync(filePath);
|
|
47
|
+
const mime = MIME_TYPES[extname(filePath).toLowerCase()] ?? "application/octet-stream";
|
|
48
|
+
return `data:${mime};base64,${bytes.toString("base64")}`;
|
|
49
|
+
}
|
|
50
|
+
function inlineCssUrls(css, htmlRoot, cssDir) {
|
|
51
|
+
return css.replace(/url\(\s*(['"]?)([^'")]+)\1\s*\)/gi, (match, _quote, rawUrl) => {
|
|
52
|
+
if (isExternalOrInline(rawUrl)) return match;
|
|
53
|
+
const filePath = resolveLocal(htmlRoot, cssDir, rawUrl);
|
|
54
|
+
return `url(${toDataUri(filePath)})`;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
function inlineScripts(root, htmlRoot) {
|
|
58
|
+
for (const el of root.querySelectorAll("script[src]")) {
|
|
59
|
+
const src = el.getAttribute("src");
|
|
60
|
+
if (!src || isExternalOrInline(src)) continue;
|
|
61
|
+
const js = readFileSync(resolveLocal(htmlRoot, htmlRoot, src), "utf-8").replace(
|
|
62
|
+
/<\/script>/gi,
|
|
63
|
+
"<\\/script>"
|
|
64
|
+
);
|
|
65
|
+
el.removeAttribute("src");
|
|
66
|
+
el.set_content(js);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function inlineStylesheets(root, htmlRoot) {
|
|
70
|
+
for (const el of root.querySelectorAll('link[rel="stylesheet"]')) {
|
|
71
|
+
const href = el.getAttribute("href");
|
|
72
|
+
if (!href || isExternalOrInline(href)) continue;
|
|
73
|
+
const cssPath = resolveLocal(htmlRoot, htmlRoot, href);
|
|
74
|
+
const css = inlineCssUrls(readFileSync(cssPath, "utf-8"), htmlRoot, dirname(cssPath));
|
|
75
|
+
el.replaceWith(...parse(`<style>${css}</style>`).childNodes);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function inlineExistingStyleBlocks(root, htmlRoot) {
|
|
79
|
+
for (const el of root.querySelectorAll("style")) {
|
|
80
|
+
const css = el.innerHTML;
|
|
81
|
+
if (!css.includes("url(")) continue;
|
|
82
|
+
el.set_content(inlineCssUrls(css, htmlRoot, htmlRoot));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function inlineMediaAttributes(root, htmlRoot) {
|
|
86
|
+
const targets = [
|
|
87
|
+
["img[src]", "src"],
|
|
88
|
+
["source[src]", "src"],
|
|
89
|
+
["audio[src]", "src"],
|
|
90
|
+
["video[src]", "src"],
|
|
91
|
+
['link[rel="icon"]', "href"],
|
|
92
|
+
['link[rel="shortcut icon"]', "href"],
|
|
93
|
+
['link[rel="apple-touch-icon"]', "href"],
|
|
94
|
+
['link[rel="preload"]', "href"]
|
|
95
|
+
];
|
|
96
|
+
for (const [selector, attr] of targets) {
|
|
97
|
+
for (const el of root.querySelectorAll(selector)) {
|
|
98
|
+
const ref = el.getAttribute(attr);
|
|
99
|
+
if (!ref || isExternalOrInline(ref)) continue;
|
|
100
|
+
el.setAttribute(attr, toDataUri(resolveLocal(htmlRoot, htmlRoot, ref)));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function inlineHtml(htmlPath) {
|
|
105
|
+
const htmlRoot = dirname(resolve(htmlPath));
|
|
106
|
+
const root = parse(readFileSync(htmlPath, "utf-8"), {
|
|
107
|
+
comment: true,
|
|
108
|
+
voidTag: { closingSlash: true }
|
|
109
|
+
});
|
|
110
|
+
inlineScripts(root, htmlRoot);
|
|
111
|
+
inlineStylesheets(root, htmlRoot);
|
|
112
|
+
inlineExistingStyleBlocks(root, htmlRoot);
|
|
113
|
+
inlineMediaAttributes(root, htmlRoot);
|
|
114
|
+
return root.toString();
|
|
115
|
+
}
|
|
116
|
+
function buildBundle(htmlPath, maxBytes = DEFAULT_MAX_BYTES) {
|
|
117
|
+
const html = inlineHtml(htmlPath);
|
|
118
|
+
const zipBytes = zipSync({ "index.html": [strToU8(html), { mtime: FIXED_MTIME }] }, { level: 6 });
|
|
119
|
+
const size = zipBytes.length;
|
|
120
|
+
const hash = `sha256-${createHash("sha256").update(zipBytes).digest("hex")}`;
|
|
121
|
+
return { html, zipBytes, size, hash, overLimit: size > maxBytes };
|
|
122
|
+
}
|
|
123
|
+
var DEFAULT_OUT = "dist/whitelabel-bundle.zip";
|
|
124
|
+
function parseArgs(argv) {
|
|
125
|
+
const args = {
|
|
126
|
+
htmlPath: "",
|
|
127
|
+
outPath: DEFAULT_OUT,
|
|
128
|
+
maxBytes: DEFAULT_MAX_BYTES,
|
|
129
|
+
help: false
|
|
130
|
+
};
|
|
131
|
+
for (let i = 0; i < argv.length; i++) {
|
|
132
|
+
const token = argv[i];
|
|
133
|
+
switch (token) {
|
|
134
|
+
case "--help":
|
|
135
|
+
case "-h":
|
|
136
|
+
args.help = true;
|
|
137
|
+
break;
|
|
138
|
+
case "--html":
|
|
139
|
+
case "-i":
|
|
140
|
+
args.htmlPath = argv[++i] ?? "";
|
|
141
|
+
break;
|
|
142
|
+
case "--out":
|
|
143
|
+
case "-o":
|
|
144
|
+
args.outPath = argv[++i] ?? DEFAULT_OUT;
|
|
145
|
+
break;
|
|
146
|
+
case "--max-bytes":
|
|
147
|
+
args.maxBytes = Number.parseInt(argv[++i] ?? "", 10) || DEFAULT_MAX_BYTES;
|
|
148
|
+
break;
|
|
149
|
+
case "build":
|
|
150
|
+
break;
|
|
151
|
+
default:
|
|
152
|
+
if (token && !token.startsWith("-") && !args.htmlPath) args.htmlPath = token;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return args;
|
|
156
|
+
}
|
|
157
|
+
var USAGE = `condor-mobile-bridge build \u2014 gera o .zip white-label self-contained.
|
|
158
|
+
|
|
159
|
+
Uso:
|
|
160
|
+
npx condor-mobile-bridge build -i <html> [-o <zip>]
|
|
161
|
+
|
|
162
|
+
Op\xE7\xF5es:
|
|
163
|
+
-i, --html <path> HTML de entrada (ex.: dist/index.html). Obrigat\xF3rio.
|
|
164
|
+
-o, --out <path> .zip de sa\xEDda (default: ${DEFAULT_OUT}).
|
|
165
|
+
--max-bytes <n> Limite de aviso em bytes (default: ${DEFAULT_MAX_BYTES} = 2 MB).
|
|
166
|
+
-h, --help Mostra esta ajuda.`;
|
|
167
|
+
|
|
168
|
+
// src/cli.ts
|
|
169
|
+
function main() {
|
|
170
|
+
const args = parseArgs(process.argv.slice(2));
|
|
171
|
+
if (args.help || !args.htmlPath) {
|
|
172
|
+
console.log(USAGE);
|
|
173
|
+
process.exit(args.help ? 0 : 1);
|
|
174
|
+
}
|
|
175
|
+
const result = buildBundle(args.htmlPath, args.maxBytes);
|
|
176
|
+
const outPath = resolve2(args.outPath);
|
|
177
|
+
mkdirSync(dirname2(outPath), { recursive: true });
|
|
178
|
+
writeFileSync(outPath, result.zipBytes);
|
|
179
|
+
const kb = (Buffer.byteLength(result.html) / 1024).toFixed(1);
|
|
180
|
+
console.log(`Built ${args.outPath}`);
|
|
181
|
+
console.log(` entry: index.html (${kb} KB self-contained)`);
|
|
182
|
+
console.log(` bundleSize (zip): ${result.size} bytes`);
|
|
183
|
+
console.log(` bundleHash (zip): ${result.hash}`);
|
|
184
|
+
if (result.overLimit) {
|
|
185
|
+
const limitMb = (args.maxBytes / (1024 * 1024)).toFixed(1);
|
|
186
|
+
console.warn(
|
|
187
|
+
`
|
|
188
|
+
\u26A0\uFE0F AVISO: o .zip (${result.size} bytes) excede o limite de ${limitMb} MB \u2014 o app vai REJEITAR este bundle (cai no mock). Reduza assets/m\xEDdias inline.`
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
main();
|
|
193
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/cli-core.ts"],"sourcesContent":["/**\n * cli.ts — Entry `bin` do `condor-mobile-bridge build`.\n *\n * Fino: parse de argv → `buildBundle` → escreve o `.zip` (mkdir recursivo) →\n * imprime tamanho + SHA-256 (formato que espelha `web-mock-src/build-demo.mjs`)\n * e avisa se passar do limite. Toda a lógica testável vive em `cli-core.ts`.\n */\nimport { mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { buildBundle, parseArgs, USAGE } from './cli-core';\n\nfunction main(): void {\n const args = parseArgs(process.argv.slice(2));\n\n if (args.help || !args.htmlPath) {\n console.log(USAGE);\n process.exit(args.help ? 0 : 1);\n }\n\n const result = buildBundle(args.htmlPath, args.maxBytes);\n\n const outPath = resolve(args.outPath);\n mkdirSync(dirname(outPath), { recursive: true });\n writeFileSync(outPath, result.zipBytes);\n\n const kb = (Buffer.byteLength(result.html) / 1024).toFixed(1);\n console.log(`Built ${args.outPath}`);\n console.log(` entry: index.html (${kb} KB self-contained)`);\n console.log(` bundleSize (zip): ${result.size} bytes`);\n console.log(` bundleHash (zip): ${result.hash}`);\n\n if (result.overLimit) {\n const limitMb = (args.maxBytes / (1024 * 1024)).toFixed(1);\n console.warn(\n `\\n⚠️ AVISO: o .zip (${result.size} bytes) excede o limite de ${limitMb} MB — ` +\n 'o app vai REJEITAR este bundle (cai no mock). Reduza assets/mídias inline.',\n );\n }\n}\n\nmain();\n","/**\n * cli-core.ts — Núcleo (puro/testável) do CLI `condor-mobile-bridge build`.\n *\n * Materializa a Frente 1 da Opção A do bundle white-label: pega um\n * `dist/index.html` (build React/Vite do cliente), inlina JS em `<script>`,\n * CSS em `<style>` (resolvendo `url()` em `data:` URI), converte mídias\n * locais em `data:` URI e empacota num `.zip` com um único `index.html` na\n * raiz. Não toca o filesystem de saída — quem escreve o `.zip` é `cli.ts`.\n *\n * Modelo de render do app: `iframe.srcdoc` (origem `null`, sem base URL) só\n * resolve conteúdo inline + `data:` URI — por isso o bundle precisa ser\n * self-contained. Ver `condor_wiki/decisions/2026-06-22_whitelabel-bundle-format.md`.\n *\n * LIMITAÇÃO conhecida: o inliner pós-build assume `dist` single-chunk\n * (um JS + um CSS + assets). Builds com code-split / ES modules que fazem\n * `import` entre chunks quebram em `srcdoc` — o cliente deve buildar\n * single-file (Vite: `vite-plugin-singlefile`; CRA: sem split). Ver README.\n */\nimport { createHash } from 'node:crypto';\nimport { readFileSync } from 'node:fs';\nimport { dirname, extname, resolve } from 'node:path';\nimport { strToU8, zipSync } from 'fflate';\nimport { type HTMLElement, parse } from 'node-html-parser';\n\n/** Default do tamanho máximo do `.zip` (espelha `WhitelabelBundleLimits.maxZipBytes` no app). */\nexport const DEFAULT_MAX_BYTES = 2 * 1024 * 1024;\n\n/** Mtime fixo (>=1980, limite do formato ZIP) → SHA-256 reprodutível entre builds. */\nconst FIXED_MTIME = new Date('2000-01-01T00:00:00Z');\n\n/** Mapa de extensão → MIME para montar `data:` URIs de mídias embutidas. */\nexport const MIME_TYPES: Record<string, string> = {\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.webp': 'image/webp',\n '.avif': 'image/avif',\n '.svg': 'image/svg+xml',\n '.ico': 'image/x-icon',\n '.bmp': 'image/bmp',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n '.otf': 'font/otf',\n '.eot': 'application/vnd.ms-fontobject',\n '.mp3': 'audio/mpeg',\n '.mp4': 'video/mp4',\n '.webm': 'video/webm',\n '.json': 'application/json',\n};\n\n/** Refs que NÃO devem ser inlinadas: absolutas externas, protocol-relative, data: já-inline. */\nfunction isExternalOrInline(url: string): boolean {\n return /^(https?:)?\\/\\//i.test(url) || /^data:/i.test(url) || /^(mailto:|tel:|#)/i.test(url);\n}\n\n/** Remove query/hash de uma ref local (`main.js?v=abc#x` → `main.js`). */\nfunction stripQueryHash(url: string): string {\n return url.split(/[?#]/)[0] ?? url;\n}\n\n/**\n * Resolve uma ref local para caminho absoluto no filesystem.\n * `htmlRoot` é a raiz do site (dir do `index.html`); `resourceDir` é o dir do\n * recurso que contém a ref (p/ `url()` no CSS, é o dir do `.css`). Refs que\n * começam com `/` são relativas à raiz do site.\n */\nfunction resolveLocal(htmlRoot: string, resourceDir: string, url: string): string {\n const clean = stripQueryHash(url);\n return clean.startsWith('/') ? resolve(htmlRoot, `.${clean}`) : resolve(resourceDir, clean);\n}\n\n/** Lê um arquivo local e devolve uma `data:` URI base64. */\nexport function toDataUri(filePath: string): string {\n const bytes = readFileSync(filePath);\n const mime = MIME_TYPES[extname(filePath).toLowerCase()] ?? 'application/octet-stream';\n return `data:${mime};base64,${bytes.toString('base64')}`;\n}\n\n/**\n * Resolve `url(...)` dentro de um bloco CSS, trocando refs locais por `data:`\n * URIs. `cssDir` é o dir do arquivo CSS (ou do HTML, p/ `<style>` inline).\n */\nexport function inlineCssUrls(css: string, htmlRoot: string, cssDir: string): string {\n return css.replace(/url\\(\\s*(['\"]?)([^'\")]+)\\1\\s*\\)/gi, (match, _quote, rawUrl: string) => {\n if (isExternalOrInline(rawUrl)) return match;\n const filePath = resolveLocal(htmlRoot, cssDir, rawUrl);\n return `url(${toDataUri(filePath)})`;\n });\n}\n\n/** Inlina `<script src=\"local\">` → `<script>…</script>` (escapando `</script>`). */\nfunction inlineScripts(root: HTMLElement, htmlRoot: string): void {\n for (const el of root.querySelectorAll('script[src]')) {\n const src = el.getAttribute('src');\n if (!src || isExternalOrInline(src)) continue;\n const js = readFileSync(resolveLocal(htmlRoot, htmlRoot, src), 'utf-8').replace(\n /<\\/script>/gi,\n '<\\\\/script>',\n );\n el.removeAttribute('src');\n el.set_content(js);\n }\n}\n\n/** Inlina `<link rel=\"stylesheet\" href=\"local\">` → `<style>…</style>` (com `url()` resolvido). */\nfunction inlineStylesheets(root: HTMLElement, htmlRoot: string): void {\n for (const el of root.querySelectorAll('link[rel=\"stylesheet\"]')) {\n const href = el.getAttribute('href');\n if (!href || isExternalOrInline(href)) continue;\n const cssPath = resolveLocal(htmlRoot, htmlRoot, href);\n const css = inlineCssUrls(readFileSync(cssPath, 'utf-8'), htmlRoot, dirname(cssPath));\n el.replaceWith(...parse(`<style>${css}</style>`).childNodes);\n }\n}\n\n/** Resolve `url()` em blocos `<style>` já existentes no HTML. */\nfunction inlineExistingStyleBlocks(root: HTMLElement, htmlRoot: string): void {\n for (const el of root.querySelectorAll('style')) {\n const css = el.innerHTML;\n if (!css.includes('url(')) continue;\n el.set_content(inlineCssUrls(css, htmlRoot, htmlRoot));\n }\n}\n\n/** Converte mídias locais referenciadas por atributo (`src`/`href`) em `data:` URIs. */\nfunction inlineMediaAttributes(root: HTMLElement, htmlRoot: string): void {\n const targets: Array<[selector: string, attr: string]> = [\n ['img[src]', 'src'],\n ['source[src]', 'src'],\n ['audio[src]', 'src'],\n ['video[src]', 'src'],\n ['link[rel=\"icon\"]', 'href'],\n ['link[rel=\"shortcut icon\"]', 'href'],\n ['link[rel=\"apple-touch-icon\"]', 'href'],\n ['link[rel=\"preload\"]', 'href'],\n ];\n for (const [selector, attr] of targets) {\n for (const el of root.querySelectorAll(selector)) {\n const ref = el.getAttribute(attr);\n if (!ref || isExternalOrInline(ref)) continue;\n el.setAttribute(attr, toDataUri(resolveLocal(htmlRoot, htmlRoot, ref)));\n }\n }\n}\n\n/**\n * Lê o HTML de entrada e devolve o HTML consolidado self-contained\n * (JS/CSS inline, mídias em `data:` URI). Não escreve nada em disco.\n */\nexport function inlineHtml(htmlPath: string): string {\n const htmlRoot = dirname(resolve(htmlPath));\n const root = parse(readFileSync(htmlPath, 'utf-8'), {\n comment: true,\n voidTag: { closingSlash: true },\n });\n inlineScripts(root, htmlRoot);\n inlineStylesheets(root, htmlRoot);\n inlineExistingStyleBlocks(root, htmlRoot);\n inlineMediaAttributes(root, htmlRoot);\n return root.toString();\n}\n\nexport interface BundleResult {\n /** HTML consolidado self-contained. */\n html: string;\n /** Bytes do `.zip` (entry único `index.html` na raiz). */\n zipBytes: Uint8Array;\n /** Tamanho do `.zip` em bytes. */\n size: number;\n /** SHA-256 dos bytes do `.zip`, no formato `sha256-<hex>`. */\n hash: string;\n /** `true` se `size` excede `maxBytes`. */\n overLimit: boolean;\n}\n\n/**\n * Constrói o bundle a partir do `index.html` de entrada: inlina, zipa\n * (entry `index.html` na raiz, mtime fixo p/ hash determinístico) e calcula\n * tamanho + SHA-256. Puro — não escreve o `.zip` (responsabilidade do caller).\n */\nexport function buildBundle(htmlPath: string, maxBytes: number = DEFAULT_MAX_BYTES): BundleResult {\n const html = inlineHtml(htmlPath);\n const zipBytes = zipSync({ 'index.html': [strToU8(html), { mtime: FIXED_MTIME }] }, { level: 6 });\n const size = zipBytes.length;\n const hash = `sha256-${createHash('sha256').update(zipBytes).digest('hex')}`;\n return { html, zipBytes, size, hash, overLimit: size > maxBytes };\n}\n\nexport interface CliArgs {\n htmlPath: string;\n outPath: string;\n maxBytes: number;\n help: boolean;\n}\n\nconst DEFAULT_OUT = 'dist/whitelabel-bundle.zip';\n\n/** Parse mínimo de argv (sem deps): `--html/-i`, `--out/-o`, `--max-bytes`, `--help/-h`. */\nexport function parseArgs(argv: string[]): CliArgs {\n const args: CliArgs = {\n htmlPath: '',\n outPath: DEFAULT_OUT,\n maxBytes: DEFAULT_MAX_BYTES,\n help: false,\n };\n for (let i = 0; i < argv.length; i++) {\n const token = argv[i];\n switch (token) {\n case '--help':\n case '-h':\n args.help = true;\n break;\n case '--html':\n case '-i':\n args.htmlPath = argv[++i] ?? '';\n break;\n case '--out':\n case '-o':\n args.outPath = argv[++i] ?? DEFAULT_OUT;\n break;\n case '--max-bytes':\n args.maxBytes = Number.parseInt(argv[++i] ?? '', 10) || DEFAULT_MAX_BYTES;\n break;\n case 'build':\n // Subcomando (`condor-mobile-bridge build …`) — ignorado aqui.\n break;\n default:\n // Primeiro posicional vira o html de entrada (ergonomia: `build dist/index.html`).\n if (token && !token.startsWith('-') && !args.htmlPath) args.htmlPath = token;\n }\n }\n return args;\n}\n\nexport const USAGE = `condor-mobile-bridge build — gera o .zip white-label self-contained.\n\nUso:\n npx condor-mobile-bridge build -i <html> [-o <zip>]\n\nOpções:\n -i, --html <path> HTML de entrada (ex.: dist/index.html). Obrigatório.\n -o, --out <path> .zip de saída (default: ${DEFAULT_OUT}).\n --max-bytes <n> Limite de aviso em bytes (default: ${DEFAULT_MAX_BYTES} = 2 MB).\n -h, --help Mostra esta ajuda.`;\n"],"mappings":"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","names":["dirname","resolve","resolve","dirname"]}
|