afterpack 0.0.13 → 0.0.15
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/dist/cli.js +3 -3
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/readme.md +28 -2
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
//#region package.json
|
|
3
|
-
var version = "0.0.
|
|
3
|
+
var version = "0.0.15";
|
|
4
4
|
|
|
5
5
|
//#endregion
|
|
6
6
|
//#region src/utils/format.ts
|
|
@@ -164,7 +164,7 @@ async function audit(url) {
|
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
166
|
try {
|
|
167
|
-
const stream = streamSSE(`${API_BASE}/v1/
|
|
167
|
+
const stream = streamSSE(`${API_BASE}/v1/audit`, {
|
|
168
168
|
method: "POST",
|
|
169
169
|
headers: { "Content-Type": "application/json" },
|
|
170
170
|
body: JSON.stringify({ url: normalizedUrl })
|
|
@@ -218,7 +218,7 @@ async function audit(url) {
|
|
|
218
218
|
for (const f of critical) console.log(` ${f.title}${f.detail ? ` (${dim(f.detail)})` : ""}`);
|
|
219
219
|
}
|
|
220
220
|
}
|
|
221
|
-
if (result.id) console.log(`\n Full report: ${cyan(`${WEB_BASE}/security-scanner
|
|
221
|
+
if (result.id) console.log(`\n Full report: ${cyan(`${WEB_BASE}/security-scanner/${result.id}`)}\n`);
|
|
222
222
|
else console.log("");
|
|
223
223
|
process.exit(0);
|
|
224
224
|
case "error":
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","names":["open: string","close: string","text: string","severity: string","version: string","version","url: string","options?: RequestInit","currentData: string[]","input: string","label: string","done: boolean","result: ScanResult","lines: string[]","parts: string[]","counts: Record<string, number>","str: string","url: string | undefined","phaseName?: string","payload: any","finding: Finding","err: any"],"sources":["../package.json","../src/utils/format.ts","../src/utils/sse.ts","../src/commands/audit.ts","../src/cli.ts"],"sourcesContent":["{\n \"name\": \"afterpack\",\n \"version\": \"0.0.13\",\n \"description\": \"A high-performance post-build JavaScript obfuscator and minifier\",\n \"type\": \"module\",\n \"main\": \"./dist/cli.js\",\n \"bin\": {\n \"afterpack\": \"./dist/cli.js\"\n },\n \"files\": [\n \"dist\"\n ],\n \"scripts\": {\n \"build\": \"tsdown src/cli.ts --format esm --dts\",\n \"dev\": \"tsdown src/cli.ts --format esm --watch\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"prepublishOnly\": \"pnpm build\",\n \"prepack\": \"tsx scripts/prepack.ts\",\n \"postpack\": \"tsx scripts/postpack.ts\",\n \"release\": \"npm version patch && git push && git push --tags\",\n \"release:minor\": \"npm version minor && git push && git push --tags\",\n \"release:major\": \"npm version major && git push && git push --tags\",\n \"lint\": \"biome check .\",\n \"lint:fix\": \"biome check --write .\"\n },\n \"keywords\": [\n \"obfuscator\",\n \"minifier\",\n \"javascript\",\n \"protection\",\n \"security\",\n \"afterpack\"\n ],\n \"author\": \"AfterPack <hello@afterpack.dev>\",\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/afterpack-dev/afterpack.git\"\n },\n \"homepage\": \"https://afterpack.dev\",\n \"bugs\": {\n \"url\": \"https://github.com/afterpack-dev/afterpack/issues\"\n },\n \"engines\": {\n \"node\": \">=18\"\n },\n \"devDependencies\": {\n \"@biomejs/biome\": \"^2.4.4\",\n \"@types/node\": \"^25.0.9\",\n \"tsdown\": \"^0.11.0\",\n \"tsx\": \"^4.21.0\",\n \"typescript\": \"^5.0.0\",\n \"vitest\": \"^2.0.0\"\n }\n}\n","const isColorSupported =\n process.env.FORCE_COLOR !== \"0\" &&\n !process.env.NO_COLOR &&\n (process.env.FORCE_COLOR !== undefined || process.stdout.isTTY);\n\nfunction ansi(open: string, close: string) {\n return (text: string) =>\n isColorSupported ? `\\x1b[${open}m${text}\\x1b[${close}m` : text;\n}\n\nexport const bold = ansi(\"1\", \"22\");\nexport const dim = ansi(\"2\", \"22\");\nexport const red = ansi(\"31\", \"39\");\nexport const green = ansi(\"32\", \"39\");\nexport const yellow = ansi(\"33\", \"39\");\nexport const cyan = ansi(\"36\", \"39\");\n\nexport function severityColor(severity: string): (text: string) => string {\n switch (severity.toLowerCase()) {\n case \"critical\":\n return red;\n case \"high\":\n return red;\n case \"medium\":\n return yellow;\n case \"low\":\n return cyan;\n default:\n return dim;\n }\n}\n\nexport function header(version: string): string {\n return `\\n ${bold(`AfterPack v${version}`)} — Security Analyzer\\n`;\n}\n","export interface SSEEvent {\n event: string;\n data: string;\n}\n\nexport async function* streamSSE(\n url: string,\n options?: RequestInit,\n): AsyncGenerator<SSEEvent> {\n const response = await fetch(url, options);\n\n if (!response.ok) {\n throw new Error(\n `SSE request failed: ${response.status} ${response.statusText}`,\n );\n }\n\n const body = response.body;\n if (!body) {\n throw new Error(\"SSE response has no body\");\n }\n\n const decoder = new TextDecoder();\n let buffer = \"\";\n let currentEvent = \"message\";\n let currentData: string[] = [];\n\n for await (const chunk of body) {\n buffer += decoder.decode(chunk, { stream: true });\n\n const lines = buffer.split(\"\\n\");\n // Keep the last incomplete line in the buffer\n buffer = lines.pop() ?? \"\";\n\n for (const line of lines) {\n if (line.startsWith(\"event:\")) {\n currentEvent = line.slice(6).trim();\n } else if (line.startsWith(\"data:\")) {\n currentData.push(line.slice(5).trim());\n } else if (line === \"\") {\n // Empty line = end of event\n if (currentData.length > 0) {\n yield { event: currentEvent, data: currentData.join(\"\\n\") };\n currentEvent = \"message\";\n currentData = [];\n }\n }\n }\n }\n\n // Flush any remaining event\n if (currentData.length > 0) {\n yield { event: currentEvent, data: currentData.join(\"\\n\") };\n }\n}\n","import { version } from \"../../package.json\";\nimport {\n bold,\n cyan,\n dim,\n green,\n header,\n red,\n severityColor,\n yellow,\n} from \"../utils/format.js\";\nimport { streamSSE } from \"../utils/sse.js\";\n\nconst API_BASE = \"https://api.afterpack.dev\";\nconst WEB_BASE = \"https://afterpack.dev\";\n\ninterface Finding {\n severity: string;\n title: string;\n detail?: string;\n}\n\ninterface ScanResult {\n id?: string;\n score?: number;\n resources?: { total?: number; unprotected?: number; sourceExposed?: number };\n findings?: Finding[];\n techStack?: string[];\n readability?: number;\n}\n\nfunction printUsage(): void {\n console.log(`\n ${bold(\"Usage:\")} afterpack audit ${cyan(\"<url>\")}\n\n Example: afterpack audit https://example.com\n`);\n process.exit(1);\n}\n\nfunction normalizeUrl(input: string): string {\n let url = input.trim();\n if (!/^https?:\\/\\//i.test(url)) {\n url = `https://${url}`;\n }\n // Validate\n try {\n new URL(url);\n } catch {\n console.error(`\\n ${red(\"Error:\")} Invalid URL: ${input}\\n`);\n process.exit(1);\n }\n return url;\n}\n\nfunction clearLine(): void {\n if (process.stdout.isTTY) {\n process.stdout.write(\"\\x1b[1A\\x1b[2K\");\n }\n}\n\nfunction printPhase(label: string, done: boolean): void {\n const icon = done ? green(\"✓\") : yellow(\"●\");\n console.log(` ${icon} ${label}`);\n}\n\nfunction printSummaryBox(result: ScanResult): void {\n const lines: string[] = [];\n\n // Score\n if (result.score !== undefined) {\n const scoreColor =\n result.score >= 70 ? green : result.score >= 40 ? yellow : red;\n lines.push(` Score: ${scoreColor(bold(`${result.score}/100`))}`);\n lines.push(\"\");\n }\n\n // Resources\n if (result.resources) {\n const r = result.resources;\n const parts: string[] = [];\n if (r.unprotected) parts.push(`${r.unprotected} unprotected`);\n if (r.sourceExposed) parts.push(`${r.sourceExposed} source exposed`);\n const detail = parts.length > 0 ? ` (${parts.join(\", \")})` : \"\";\n lines.push(` Resources ${r.total ?? 0} found${detail}`);\n }\n\n // Findings\n if (result.findings && result.findings.length > 0) {\n const counts: Record<string, number> = {};\n for (const f of result.findings) {\n const s = f.severity.toLowerCase();\n counts[s] = (counts[s] || 0) + 1;\n }\n const parts = Object.entries(counts).map(([sev, n]) => `${n} ${sev}`);\n lines.push(\n ` Findings ${result.findings.length} issues (${parts.join(\", \")})`,\n );\n }\n\n // Tech Stack\n if (result.techStack && result.techStack.length > 0) {\n lines.push(` Tech Stack ${result.techStack.join(\", \")}`);\n }\n\n // Readability\n if (result.readability !== undefined) {\n lines.push(` Readability ${result.readability}/100`);\n }\n\n // Box\n const maxLen = Math.max(...lines.map((l) => stripAnsi(l).length), 50);\n const border = \"─\".repeat(maxLen + 4);\n\n console.log(`\\n ┌─${border}─┐`);\n for (const line of lines) {\n const pad = maxLen + 4 - stripAnsi(line).length;\n console.log(` │ ${line}${\" \".repeat(pad)} │`);\n }\n console.log(` └─${border}─┘`);\n}\n\nfunction stripAnsi(str: string): string {\n return str.replace(/\\x1b\\[[0-9;]*m/g, \"\");\n}\n\nexport async function audit(url: string | undefined): Promise<void> {\n if (!url) {\n printUsage();\n return;\n }\n\n const normalizedUrl = normalizeUrl(url);\n\n console.log(header(version));\n console.log(` Scanning ${cyan(normalizedUrl)} ...\\n`);\n\n const phases = [\n \"Fetching page\",\n \"Rendering JavaScript\",\n \"Analyzing resources\",\n ];\n let currentPhaseIndex = -1;\n let extraLinesSincePhase = 0;\n const result: ScanResult = {};\n\n function advancePhase(phaseName?: string): void {\n // Mark current phase as done\n if (currentPhaseIndex >= 0) {\n if (extraLinesSincePhase === 0) {\n // No findings printed — replace ● with ✓ in place\n if (process.stdout.isTTY) clearLine();\n printPhase(phases[currentPhaseIndex], true);\n }\n // If findings were printed, the ● line stays — no ✓ needed\n }\n\n if (phaseName) {\n // Find phase index or add it\n let idx = phases.indexOf(phaseName);\n if (idx === -1) {\n phases.push(phaseName);\n idx = phases.length - 1;\n }\n currentPhaseIndex = idx;\n extraLinesSincePhase = 0;\n printPhase(phaseName, false);\n }\n }\n\n try {\n const stream = streamSSE(`${API_BASE}/v1/scan`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ url: normalizedUrl }),\n });\n\n for await (const event of stream) {\n let payload: any;\n try {\n payload = JSON.parse(event.data);\n } catch {\n payload = event.data;\n }\n\n switch (event.event) {\n case \"progress\":\n advancePhase(payload.phase ?? payload.message);\n break;\n\n case \"finding\": {\n const finding: Finding = {\n severity: payload.severity ?? \"info\",\n title: payload.title ?? payload.message ?? \"\",\n detail: payload.detail,\n };\n if (!result.findings) result.findings = [];\n result.findings.push(finding);\n\n // Print critical/high findings immediately\n const sev = finding.severity.toLowerCase();\n if (sev === \"critical\" || sev === \"high\") {\n const color = severityColor(sev);\n console.log(\n ` ${color(\"⚠\")} ${color(finding.severity)}: ${finding.title}`,\n );\n extraLinesSincePhase++;\n }\n break;\n }\n\n case \"score_update\":\n result.score = payload.score ?? payload.value;\n break;\n\n case \"complete\":\n // Finalize current phase\n if (currentPhaseIndex >= 0 && extraLinesSincePhase === 0) {\n if (process.stdout.isTTY) clearLine();\n printPhase(phases[currentPhaseIndex], true);\n }\n\n // Merge final data\n if (payload.score !== undefined) result.score = payload.score;\n if (payload.id) result.id = payload.id;\n if (payload.resources) result.resources = payload.resources;\n if (payload.findings) result.findings = payload.findings;\n if (payload.techStack) result.techStack = payload.techStack;\n if (payload.readability !== undefined)\n result.readability = payload.readability;\n\n printSummaryBox(result);\n\n // Critical findings summary\n if (result.findings) {\n const critical = result.findings.filter(\n (f) => f.severity.toLowerCase() === \"critical\",\n );\n if (critical.length > 0) {\n console.log(\n `\\n ${red(\"⚠\")} ${bold(\n `${critical.length} critical finding${\n critical.length > 1 ? \"s\" : \"\"\n }:`,\n )}`,\n );\n for (const f of critical) {\n console.log(\n ` ${f.title}${f.detail ? ` (${dim(f.detail)})` : \"\"}`,\n );\n }\n }\n }\n\n // Report link\n if (result.id) {\n console.log(\n `\\n Full report: ${cyan(\n `${WEB_BASE}/security-scanner?id=${result.id}`,\n )}\\n`,\n );\n } else {\n console.log(\"\");\n }\n\n process.exit(0);\n\n case \"error\":\n console.error(\n `\\n ${red(\"Error:\")} ${\n payload.message ?? payload.error ?? \"Scan failed\"\n }\\n`,\n );\n process.exit(1);\n }\n }\n\n // If stream ends without a complete event, still show what we have\n if (result.score !== undefined) {\n printSummaryBox(result);\n }\n console.error(\n `\\n ${yellow(\"Warning:\")} Stream ended without completion event.\\n`,\n );\n process.exit(1);\n } catch (err: any) {\n console.error(\n `\\n ${red(\"Error:\")} ${err.message ?? \"Failed to connect to API\"}\\n`,\n );\n process.exit(1);\n }\n}\n","#!/usr/bin/env node\n\nimport { version } from \"../package.json\";\nimport { audit } from \"./commands/audit.js\";\n\nconst args = process.argv.slice(2);\n\n// Version flag\nif (args.includes(\"--version\") || args.includes(\"-v\")) {\n console.log(`AfterPack v${version}`);\n process.exit(0);\n}\n\n// Command routing\nconst command = args[0];\n\nswitch (command) {\n case \"audit\":\n await audit(args[1]);\n break;\n\n default:\n console.log(`\n AfterPack v${version}\n\n ┌─────────────────────────────────────────────────────┐\n │ Launching soon — join the waitlist for day-one │\n │ access: https://www.afterpack.dev │\n └─────────────────────────────────────────────────────┘\n\n Usage: afterpack <command> [options]\n\n Commands:\n audit <url> Audit your frontend for leaked secrets & sensitive data\n\n Options:\n -v, --version Show version\n`);\n break;\n}\n"],"mappings":";;cAEa;;;;ACFb,MAAM,mBACJ,QAAQ,IAAI,gBAAgB,QAC3B,QAAQ,IAAI,aACZ,QAAQ,IAAI,0BAA6B,QAAQ,OAAO;AAE3D,SAAS,KAAKA,MAAcC,OAAe;AACzC,QAAO,CAACC,SACN,oBAAoB,OAAO,KAAK,GAAG,KAAK,OAAO,MAAM,KAAK;AAC7D;AAED,MAAa,OAAO,KAAK,KAAK,KAAK;AACnC,MAAa,MAAM,KAAK,KAAK,KAAK;AAClC,MAAa,MAAM,KAAK,MAAM,KAAK;AACnC,MAAa,QAAQ,KAAK,MAAM,KAAK;AACrC,MAAa,SAAS,KAAK,MAAM,KAAK;AACtC,MAAa,OAAO,KAAK,MAAM,KAAK;AAEpC,SAAgB,cAAcC,UAA4C;AACxE,SAAQ,SAAS,aAAa,EAA9B;EACE,KAAK,WACH,QAAO;EACT,KAAK,OACH,QAAO;EACT,KAAK,SACH,QAAO;EACT,KAAK,MACH,QAAO;EACT,QACE,QAAO;CACV;AACF;AAED,SAAgB,OAAOC,WAAyB;AAC9C,SAAQ,MAAM,MAAM,aAAaC,UAAQ,EAAE,CAAC;AAC7C;;;;AC7BD,gBAAuB,UACrBC,KACAC,SAC0B;CAC1B,MAAM,WAAW,MAAM,MAAM,KAAK,QAAQ;AAE1C,MAAK,SAAS,GACZ,OAAM,IAAI,OACP,sBAAsB,SAAS,OAAO,GAAG,SAAS,WAAW;CAIlE,MAAM,OAAO,SAAS;AACtB,MAAK,KACH,OAAM,IAAI,MAAM;CAGlB,MAAM,UAAU,IAAI;CACpB,IAAI,SAAS;CACb,IAAI,eAAe;CACnB,IAAIC,cAAwB,CAAE;AAE9B,YAAW,MAAM,SAAS,MAAM;AAC9B,YAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAM,EAAC;EAEjD,MAAM,QAAQ,OAAO,MAAM,KAAK;AAEhC,WAAS,MAAM,KAAK,IAAI;AAExB,OAAK,MAAM,QAAQ,MACjB,KAAI,KAAK,WAAW,SAAS,CAC3B,gBAAe,KAAK,MAAM,EAAE,CAAC,MAAM;WAC1B,KAAK,WAAW,QAAQ,CACjC,aAAY,KAAK,KAAK,MAAM,EAAE,CAAC,MAAM,CAAC;WAC7B,SAAS,IAElB;OAAI,YAAY,SAAS,GAAG;AAC1B,UAAM;KAAE,OAAO;KAAc,MAAM,YAAY,KAAK,KAAK;IAAE;AAC3D,mBAAe;AACf,kBAAc,CAAE;GACjB;;CAGN;AAGD,KAAI,YAAY,SAAS,EACvB,OAAM;EAAE,OAAO;EAAc,MAAM,YAAY,KAAK,KAAK;CAAE;AAE9D;;;;ACzCD,MAAM,WAAW;AACjB,MAAM,WAAW;AAiBjB,SAAS,aAAmB;AAC1B,SAAQ,KAAK;IACX,KAAK,SAAS,CAAC,mBAAmB,KAAK,QAAQ,CAAC;;;EAGlD;AACA,SAAQ,KAAK,EAAE;AAChB;AAED,SAAS,aAAaC,OAAuB;CAC3C,IAAI,MAAM,MAAM,MAAM;AACtB,MAAK,gBAAgB,KAAK,IAAI,CAC5B,QAAO,UAAU,IAAI;AAGvB,KAAI;AACF,MAAI,IAAI;CACT,QAAO;AACN,UAAQ,OAAO,MAAM,IAAI,SAAS,CAAC,gBAAgB,MAAM,IAAI;AAC7D,UAAQ,KAAK,EAAE;CAChB;AACD,QAAO;AACR;AAED,SAAS,YAAkB;AACzB,KAAI,QAAQ,OAAO,MACjB,SAAQ,OAAO,MAAM,iBAAiB;AAEzC;AAED,SAAS,WAAWC,OAAeC,MAAqB;CACtD,MAAM,OAAO,OAAO,MAAM,IAAI,GAAG,OAAO,IAAI;AAC5C,SAAQ,KAAK,IAAI,KAAK,GAAG,MAAM,EAAE;AAClC;AAED,SAAS,gBAAgBC,QAA0B;CACjD,MAAMC,QAAkB,CAAE;AAG1B,KAAI,OAAO,kBAAqB;EAC9B,MAAM,aACJ,OAAO,SAAS,KAAK,QAAQ,OAAO,SAAS,KAAK,SAAS;AAC7D,QAAM,MAAM,WAAW,WAAW,MAAM,EAAE,OAAO,MAAM,MAAM,CAAC,CAAC,EAAE;AACjE,QAAM,KAAK,GAAG;CACf;AAGD,KAAI,OAAO,WAAW;EACpB,MAAM,IAAI,OAAO;EACjB,MAAMC,QAAkB,CAAE;AAC1B,MAAI,EAAE,YAAa,OAAM,MAAM,EAAE,EAAE,YAAY,cAAc;AAC7D,MAAI,EAAE,cAAe,OAAM,MAAM,EAAE,EAAE,cAAc,iBAAiB;EACpE,MAAM,SAAS,MAAM,SAAS,KAAK,IAAI,MAAM,KAAK,KAAK,CAAC,KAAK;AAC7D,QAAM,MAAM,mBAAmB,EAAE,SAAS,EAAE,QAAQ,OAAO,EAAE;CAC9D;AAGD,KAAI,OAAO,YAAY,OAAO,SAAS,SAAS,GAAG;EACjD,MAAMC,SAAiC,CAAE;AACzC,OAAK,MAAM,KAAK,OAAO,UAAU;GAC/B,MAAM,IAAI,EAAE,SAAS,aAAa;AAClC,UAAO,MAAM,OAAO,MAAM,KAAK;EAChC;EACD,MAAM,QAAQ,OAAO,QAAQ,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,IAAI,EAAE;AACrE,QAAM,MACH,mBAAmB,OAAO,SAAS,OAAO,WAAW,MAAM,KAAK,KAAK,CAAC,GACxE;CACF;AAGD,KAAI,OAAO,aAAa,OAAO,UAAU,SAAS,EAChD,OAAM,MAAM,mBAAmB,OAAO,UAAU,KAAK,KAAK,CAAC,EAAE;AAI/D,KAAI,OAAO,uBACT,OAAM,MAAM,mBAAmB,OAAO,YAAY,MAAM;CAI1D,MAAM,SAAS,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,UAAU,EAAE,CAAC,OAAO,EAAE,GAAG;CACrE,MAAM,SAAS,IAAI,OAAO,SAAS,EAAE;AAErC,SAAQ,KAAK,QAAQ,OAAO,IAAI;AAChC,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,MAAM,SAAS,IAAI,UAAU,KAAK,CAAC;AACzC,UAAQ,KAAK,MAAM,KAAK,EAAE,IAAI,OAAO,IAAI,CAAC,IAAI;CAC/C;AACD,SAAQ,KAAK,MAAM,OAAO,IAAI;AAC/B;AAED,SAAS,UAAUC,KAAqB;AACtC,QAAO,IAAI,QAAQ,mBAAmB,GAAG;AAC1C;AAED,eAAsB,MAAMC,KAAwC;AAClE,MAAK,KAAK;AACR,cAAY;AACZ;CACD;CAED,MAAM,gBAAgB,aAAa,IAAI;AAEvC,SAAQ,IAAI,OAAO,QAAQ,CAAC;AAC5B,SAAQ,KAAK,aAAa,KAAK,cAAc,CAAC,QAAQ;CAEtD,MAAM,SAAS;EACb;EACA;EACA;CACD;CACD,IAAI,oBAAoB;CACxB,IAAI,uBAAuB;CAC3B,MAAML,SAAqB,CAAE;CAE7B,SAAS,aAAaM,WAA0B;AAE9C,MAAI,qBAAqB,GACvB;OAAI,yBAAyB,GAAG;AAE9B,QAAI,QAAQ,OAAO,MAAO,YAAW;AACrC,eAAW,OAAO,oBAAoB,KAAK;GAC5C;;AAIH,MAAI,WAAW;GAEb,IAAI,MAAM,OAAO,QAAQ,UAAU;AACnC,OAAI,QAAQ,IAAI;AACd,WAAO,KAAK,UAAU;AACtB,UAAM,OAAO,SAAS;GACvB;AACD,uBAAoB;AACpB,0BAAuB;AACvB,cAAW,WAAW,MAAM;EAC7B;CACF;AAED,KAAI;EACF,MAAM,SAAS,WAAW,EAAE,SAAS,WAAW;GAC9C,QAAQ;GACR,SAAS,EAAE,gBAAgB,mBAAoB;GAC/C,MAAM,KAAK,UAAU,EAAE,KAAK,cAAe,EAAC;EAC7C,EAAC;AAEF,aAAW,MAAM,SAAS,QAAQ;GAChC,IAAIC;AACJ,OAAI;AACF,cAAU,KAAK,MAAM,MAAM,KAAK;GACjC,QAAO;AACN,cAAU,MAAM;GACjB;AAED,WAAQ,MAAM,OAAd;IACE,KAAK;AACH,kBAAa,QAAQ,SAAS,QAAQ,QAAQ;AAC9C;IAEF,KAAK,WAAW;KACd,MAAMC,UAAmB;MACvB,UAAU,QAAQ,YAAY;MAC9B,OAAO,QAAQ,SAAS,QAAQ,WAAW;MAC3C,QAAQ,QAAQ;KACjB;AACD,UAAK,OAAO,SAAU,QAAO,WAAW,CAAE;AAC1C,YAAO,SAAS,KAAK,QAAQ;KAG7B,MAAM,MAAM,QAAQ,SAAS,aAAa;AAC1C,SAAI,QAAQ,cAAc,QAAQ,QAAQ;MACxC,MAAM,QAAQ,cAAc,IAAI;AAChC,cAAQ,KACL,IAAI,MAAM,IAAI,CAAC,IAAI,MAAM,QAAQ,SAAS,CAAC,IAAI,QAAQ,MAAM,EAC/D;AACD;KACD;AACD;IACD;IAED,KAAK;AACH,YAAO,QAAQ,QAAQ,SAAS,QAAQ;AACxC;IAEF,KAAK;AAEH,SAAI,qBAAqB,KAAK,yBAAyB,GAAG;AACxD,UAAI,QAAQ,OAAO,MAAO,YAAW;AACrC,iBAAW,OAAO,oBAAoB,KAAK;KAC5C;AAGD,SAAI,QAAQ,iBAAqB,QAAO,QAAQ,QAAQ;AACxD,SAAI,QAAQ,GAAI,QAAO,KAAK,QAAQ;AACpC,SAAI,QAAQ,UAAW,QAAO,YAAY,QAAQ;AAClD,SAAI,QAAQ,SAAU,QAAO,WAAW,QAAQ;AAChD,SAAI,QAAQ,UAAW,QAAO,YAAY,QAAQ;AAClD,SAAI,QAAQ,uBACV,QAAO,cAAc,QAAQ;AAE/B,qBAAgB,OAAO;AAGvB,SAAI,OAAO,UAAU;MACnB,MAAM,WAAW,OAAO,SAAS,OAC/B,CAAC,MAAM,EAAE,SAAS,aAAa,KAAK,WACrC;AACD,UAAI,SAAS,SAAS,GAAG;AACvB,eAAQ,KACL,MAAM,IAAI,IAAI,CAAC,IAAI,MACjB,EAAE,SAAS,OAAO,mBACjB,SAAS,SAAS,IAAI,MAAM,GAC7B,GACF,CAAC,EACH;AACD,YAAK,MAAM,KAAK,SACd,SAAQ,KACL,OAAO,EAAE,MAAM,EAAE,EAAE,UAAU,IAAI,IAAI,EAAE,OAAO,CAAC,KAAK,GAAG,EACzD;MAEJ;KACF;AAGD,SAAI,OAAO,GACT,SAAQ,KACL,mBAAmB,MACjB,EAAE,SAAS,uBAAuB,OAAO,GAAG,EAC9C,CAAC,IACH;SAED,SAAQ,IAAI,GAAG;AAGjB,aAAQ,KAAK,EAAE;IAEjB,KAAK;AACH,aAAQ,OACL,MAAM,IAAI,SAAS,CAAC,GACnB,QAAQ,WAAW,QAAQ,SAAS,cACrC,IACF;AACD,aAAQ,KAAK,EAAE;GAClB;EACF;AAGD,MAAI,OAAO,iBACT,iBAAgB,OAAO;AAEzB,UAAQ,OACL,MAAM,OAAO,WAAW,CAAC,2CAC3B;AACD,UAAQ,KAAK,EAAE;CAChB,SAAQC,KAAU;AACjB,UAAQ,OACL,MAAM,IAAI,SAAS,CAAC,GAAG,IAAI,WAAW,2BAA2B,IACnE;AACD,UAAQ,KAAK,EAAE;CAChB;AACF;;;;AC9RD,MAAM,OAAO,QAAQ,KAAK,MAAM,EAAE;AAGlC,IAAI,KAAK,SAAS,YAAY,IAAI,KAAK,SAAS,KAAK,EAAE;AACrD,SAAQ,KAAK,aAAa,QAAQ,EAAE;AACpC,SAAQ,KAAK,EAAE;AAChB;AAGD,MAAM,UAAU,KAAK;AAErB,QAAQ,SAAR;CACE,KAAK;AACH,QAAM,MAAM,KAAK,GAAG;AACpB;CAEF;AACE,UAAQ,KAAK;eACF,QAAQ;;;;;;;;;;;;;;EAcrB;AACE;AACH"}
|
|
1
|
+
{"version":3,"file":"cli.js","names":["open: string","close: string","text: string","severity: string","version: string","version","url: string","options?: RequestInit","currentData: string[]","input: string","label: string","done: boolean","result: ScanResult","lines: string[]","parts: string[]","counts: Record<string, number>","str: string","url: string | undefined","phaseName?: string","payload: any","finding: Finding","err: any"],"sources":["../package.json","../src/utils/format.ts","../src/utils/sse.ts","../src/commands/audit.ts","../src/cli.ts"],"sourcesContent":["{\n \"name\": \"afterpack\",\n \"version\": \"0.0.15\",\n \"description\": \"A high-performance post-build JavaScript obfuscator and minifier\",\n \"type\": \"module\",\n \"main\": \"./dist/cli.js\",\n \"bin\": {\n \"afterpack\": \"./dist/cli.js\"\n },\n \"files\": [\n \"dist\"\n ],\n \"scripts\": {\n \"build\": \"tsdown src/cli.ts --format esm --dts\",\n \"dev\": \"tsdown src/cli.ts --format esm --watch\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"prepublishOnly\": \"pnpm build\",\n \"prepack\": \"tsx scripts/prepack.ts\",\n \"postpack\": \"tsx scripts/postpack.ts\",\n \"release\": \"npm version patch && git push && git push --tags\",\n \"release:minor\": \"npm version minor && git push && git push --tags\",\n \"release:major\": \"npm version major && git push && git push --tags\",\n \"lint\": \"biome check .\",\n \"lint:fix\": \"biome check --write .\"\n },\n \"keywords\": [\n \"obfuscator\",\n \"minifier\",\n \"javascript\",\n \"protection\",\n \"security\",\n \"afterpack\"\n ],\n \"author\": \"AfterPack <hello@afterpack.dev>\",\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/afterpack-dev/afterpack.git\"\n },\n \"homepage\": \"https://afterpack.dev\",\n \"bugs\": {\n \"url\": \"https://github.com/afterpack-dev/afterpack/issues\"\n },\n \"engines\": {\n \"node\": \">=18\"\n },\n \"devDependencies\": {\n \"@biomejs/biome\": \"^2.4.4\",\n \"@types/node\": \"^25.0.9\",\n \"tsdown\": \"^0.11.0\",\n \"tsx\": \"^4.21.0\",\n \"typescript\": \"^5.0.0\",\n \"vitest\": \"^2.0.0\"\n }\n}\n","const isColorSupported =\n process.env.FORCE_COLOR !== \"0\" &&\n !process.env.NO_COLOR &&\n (process.env.FORCE_COLOR !== undefined || process.stdout.isTTY);\n\nfunction ansi(open: string, close: string) {\n return (text: string) =>\n isColorSupported ? `\\x1b[${open}m${text}\\x1b[${close}m` : text;\n}\n\nexport const bold = ansi(\"1\", \"22\");\nexport const dim = ansi(\"2\", \"22\");\nexport const red = ansi(\"31\", \"39\");\nexport const green = ansi(\"32\", \"39\");\nexport const yellow = ansi(\"33\", \"39\");\nexport const cyan = ansi(\"36\", \"39\");\n\nexport function severityColor(severity: string): (text: string) => string {\n switch (severity.toLowerCase()) {\n case \"critical\":\n return red;\n case \"high\":\n return red;\n case \"medium\":\n return yellow;\n case \"low\":\n return cyan;\n default:\n return dim;\n }\n}\n\nexport function header(version: string): string {\n return `\\n ${bold(`AfterPack v${version}`)} — Security Analyzer\\n`;\n}\n","export interface SSEEvent {\n event: string;\n data: string;\n}\n\nexport async function* streamSSE(\n url: string,\n options?: RequestInit,\n): AsyncGenerator<SSEEvent> {\n const response = await fetch(url, options);\n\n if (!response.ok) {\n throw new Error(\n `SSE request failed: ${response.status} ${response.statusText}`,\n );\n }\n\n const body = response.body;\n if (!body) {\n throw new Error(\"SSE response has no body\");\n }\n\n const decoder = new TextDecoder();\n let buffer = \"\";\n let currentEvent = \"message\";\n let currentData: string[] = [];\n\n for await (const chunk of body) {\n buffer += decoder.decode(chunk, { stream: true });\n\n const lines = buffer.split(\"\\n\");\n // Keep the last incomplete line in the buffer\n buffer = lines.pop() ?? \"\";\n\n for (const line of lines) {\n if (line.startsWith(\"event:\")) {\n currentEvent = line.slice(6).trim();\n } else if (line.startsWith(\"data:\")) {\n currentData.push(line.slice(5).trim());\n } else if (line === \"\") {\n // Empty line = end of event\n if (currentData.length > 0) {\n yield { event: currentEvent, data: currentData.join(\"\\n\") };\n currentEvent = \"message\";\n currentData = [];\n }\n }\n }\n }\n\n // Flush any remaining event\n if (currentData.length > 0) {\n yield { event: currentEvent, data: currentData.join(\"\\n\") };\n }\n}\n","import { version } from \"../../package.json\";\nimport {\n bold,\n cyan,\n dim,\n green,\n header,\n red,\n severityColor,\n yellow,\n} from \"../utils/format.js\";\nimport { streamSSE } from \"../utils/sse.js\";\n\nconst API_BASE = \"https://api.afterpack.dev\";\nconst WEB_BASE = \"https://afterpack.dev\";\n\ninterface Finding {\n severity: string;\n title: string;\n detail?: string;\n}\n\ninterface ScanResult {\n id?: string;\n score?: number;\n resources?: { total?: number; unprotected?: number; sourceExposed?: number };\n findings?: Finding[];\n techStack?: string[];\n readability?: number;\n}\n\nfunction printUsage(): void {\n console.log(`\n ${bold(\"Usage:\")} afterpack audit ${cyan(\"<url>\")}\n\n Example: afterpack audit https://example.com\n`);\n process.exit(1);\n}\n\nfunction normalizeUrl(input: string): string {\n let url = input.trim();\n if (!/^https?:\\/\\//i.test(url)) {\n url = `https://${url}`;\n }\n // Validate\n try {\n new URL(url);\n } catch {\n console.error(`\\n ${red(\"Error:\")} Invalid URL: ${input}\\n`);\n process.exit(1);\n }\n return url;\n}\n\nfunction clearLine(): void {\n if (process.stdout.isTTY) {\n process.stdout.write(\"\\x1b[1A\\x1b[2K\");\n }\n}\n\nfunction printPhase(label: string, done: boolean): void {\n const icon = done ? green(\"✓\") : yellow(\"●\");\n console.log(` ${icon} ${label}`);\n}\n\nfunction printSummaryBox(result: ScanResult): void {\n const lines: string[] = [];\n\n // Score\n if (result.score !== undefined) {\n const scoreColor =\n result.score >= 70 ? green : result.score >= 40 ? yellow : red;\n lines.push(` Score: ${scoreColor(bold(`${result.score}/100`))}`);\n lines.push(\"\");\n }\n\n // Resources\n if (result.resources) {\n const r = result.resources;\n const parts: string[] = [];\n if (r.unprotected) parts.push(`${r.unprotected} unprotected`);\n if (r.sourceExposed) parts.push(`${r.sourceExposed} source exposed`);\n const detail = parts.length > 0 ? ` (${parts.join(\", \")})` : \"\";\n lines.push(` Resources ${r.total ?? 0} found${detail}`);\n }\n\n // Findings\n if (result.findings && result.findings.length > 0) {\n const counts: Record<string, number> = {};\n for (const f of result.findings) {\n const s = f.severity.toLowerCase();\n counts[s] = (counts[s] || 0) + 1;\n }\n const parts = Object.entries(counts).map(([sev, n]) => `${n} ${sev}`);\n lines.push(\n ` Findings ${result.findings.length} issues (${parts.join(\", \")})`,\n );\n }\n\n // Tech Stack\n if (result.techStack && result.techStack.length > 0) {\n lines.push(` Tech Stack ${result.techStack.join(\", \")}`);\n }\n\n // Readability\n if (result.readability !== undefined) {\n lines.push(` Readability ${result.readability}/100`);\n }\n\n // Box\n const maxLen = Math.max(...lines.map((l) => stripAnsi(l).length), 50);\n const border = \"─\".repeat(maxLen + 4);\n\n console.log(`\\n ┌─${border}─┐`);\n for (const line of lines) {\n const pad = maxLen + 4 - stripAnsi(line).length;\n console.log(` │ ${line}${\" \".repeat(pad)} │`);\n }\n console.log(` └─${border}─┘`);\n}\n\nfunction stripAnsi(str: string): string {\n return str.replace(/\\x1b\\[[0-9;]*m/g, \"\");\n}\n\nexport async function audit(url: string | undefined): Promise<void> {\n if (!url) {\n printUsage();\n return;\n }\n\n const normalizedUrl = normalizeUrl(url);\n\n console.log(header(version));\n console.log(` Scanning ${cyan(normalizedUrl)} ...\\n`);\n\n const phases = [\n \"Fetching page\",\n \"Rendering JavaScript\",\n \"Analyzing resources\",\n ];\n let currentPhaseIndex = -1;\n let extraLinesSincePhase = 0;\n const result: ScanResult = {};\n\n function advancePhase(phaseName?: string): void {\n // Mark current phase as done\n if (currentPhaseIndex >= 0) {\n if (extraLinesSincePhase === 0) {\n // No findings printed — replace ● with ✓ in place\n if (process.stdout.isTTY) clearLine();\n printPhase(phases[currentPhaseIndex], true);\n }\n // If findings were printed, the ● line stays — no ✓ needed\n }\n\n if (phaseName) {\n // Find phase index or add it\n let idx = phases.indexOf(phaseName);\n if (idx === -1) {\n phases.push(phaseName);\n idx = phases.length - 1;\n }\n currentPhaseIndex = idx;\n extraLinesSincePhase = 0;\n printPhase(phaseName, false);\n }\n }\n\n try {\n const stream = streamSSE(`${API_BASE}/v1/audit`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ url: normalizedUrl }),\n });\n\n for await (const event of stream) {\n let payload: any;\n try {\n payload = JSON.parse(event.data);\n } catch {\n payload = event.data;\n }\n\n switch (event.event) {\n case \"progress\":\n advancePhase(payload.phase ?? payload.message);\n break;\n\n case \"finding\": {\n const finding: Finding = {\n severity: payload.severity ?? \"info\",\n title: payload.title ?? payload.message ?? \"\",\n detail: payload.detail,\n };\n if (!result.findings) result.findings = [];\n result.findings.push(finding);\n\n // Print critical/high findings immediately\n const sev = finding.severity.toLowerCase();\n if (sev === \"critical\" || sev === \"high\") {\n const color = severityColor(sev);\n console.log(\n ` ${color(\"⚠\")} ${color(finding.severity)}: ${finding.title}`,\n );\n extraLinesSincePhase++;\n }\n break;\n }\n\n case \"score_update\":\n result.score = payload.score ?? payload.value;\n break;\n\n case \"complete\":\n // Finalize current phase\n if (currentPhaseIndex >= 0 && extraLinesSincePhase === 0) {\n if (process.stdout.isTTY) clearLine();\n printPhase(phases[currentPhaseIndex], true);\n }\n\n // Merge final data\n if (payload.score !== undefined) result.score = payload.score;\n if (payload.id) result.id = payload.id;\n if (payload.resources) result.resources = payload.resources;\n if (payload.findings) result.findings = payload.findings;\n if (payload.techStack) result.techStack = payload.techStack;\n if (payload.readability !== undefined)\n result.readability = payload.readability;\n\n printSummaryBox(result);\n\n // Critical findings summary\n if (result.findings) {\n const critical = result.findings.filter(\n (f) => f.severity.toLowerCase() === \"critical\",\n );\n if (critical.length > 0) {\n console.log(\n `\\n ${red(\"⚠\")} ${bold(\n `${critical.length} critical finding${\n critical.length > 1 ? \"s\" : \"\"\n }:`,\n )}`,\n );\n for (const f of critical) {\n console.log(\n ` ${f.title}${f.detail ? ` (${dim(f.detail)})` : \"\"}`,\n );\n }\n }\n }\n\n // Report link\n if (result.id) {\n console.log(\n `\\n Full report: ${cyan(\n `${WEB_BASE}/security-scanner/${result.id}`,\n )}\\n`,\n );\n } else {\n console.log(\"\");\n }\n\n process.exit(0);\n\n case \"error\":\n console.error(\n `\\n ${red(\"Error:\")} ${\n payload.message ?? payload.error ?? \"Scan failed\"\n }\\n`,\n );\n process.exit(1);\n }\n }\n\n // If stream ends without a complete event, still show what we have\n if (result.score !== undefined) {\n printSummaryBox(result);\n }\n console.error(\n `\\n ${yellow(\"Warning:\")} Stream ended without completion event.\\n`,\n );\n process.exit(1);\n } catch (err: any) {\n console.error(\n `\\n ${red(\"Error:\")} ${err.message ?? \"Failed to connect to API\"}\\n`,\n );\n process.exit(1);\n }\n}\n","#!/usr/bin/env node\n\nimport { version } from \"../package.json\";\nimport { audit } from \"./commands/audit.js\";\n\nconst args = process.argv.slice(2);\n\n// Version flag\nif (args.includes(\"--version\") || args.includes(\"-v\")) {\n console.log(`AfterPack v${version}`);\n process.exit(0);\n}\n\n// Command routing\nconst command = args[0];\n\nswitch (command) {\n case \"audit\":\n await audit(args[1]);\n break;\n\n default:\n console.log(`\n AfterPack v${version}\n\n ┌─────────────────────────────────────────────────────┐\n │ Launching soon — join the waitlist for day-one │\n │ access: https://www.afterpack.dev │\n └─────────────────────────────────────────────────────┘\n\n Usage: afterpack <command> [options]\n\n Commands:\n audit <url> Audit your frontend for leaked secrets & sensitive data\n\n Options:\n -v, --version Show version\n`);\n break;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# [AfterPack](https://www.afterpack.dev)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
High-performance JavaScript obfuscator and audit tool — find leaked secrets, seal your production code.
|
|
4
4
|
|
|
5
5
|
[www.afterpack.dev](https://www.afterpack.dev)
|
|
6
6
|
|
|
@@ -10,7 +10,33 @@ A high-performance post-build JavaScript obfuscator and minifier — the final s
|
|
|
10
10
|
npx afterpack
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## Commands
|
|
14
|
+
|
|
15
|
+
| Command | Description |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| `npx afterpack audit <url>` | Scan a live URL for leaked secrets and sensitive data |
|
|
18
|
+
| `npx afterpack` | Obfuscate JavaScript build artifacts _(coming soon)_ |
|
|
19
|
+
|
|
20
|
+
## Security Audit
|
|
21
|
+
|
|
22
|
+
Scan any live frontend for leaked secrets, exposed source code, and sensitive data — powered by the [AfterPack API](https://www.afterpack.dev).
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx afterpack audit <url>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Example:**
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx afterpack audit example.com
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- **Security score** — 0-100 rating based on exposed secrets, source maps, and unprotected resources
|
|
35
|
+
- **Resource analysis** — counts total, unprotected, and source-exposed JavaScript files
|
|
36
|
+
- **Tech stack detection** — identifies frameworks and libraries in use
|
|
37
|
+
- **Web report** — outputs a link to the full interactive report on afterpack.dev
|
|
38
|
+
|
|
39
|
+
## Obfuscation
|
|
14
40
|
|
|
15
41
|
- **Free & Production-Ready** — Full obfuscation at no cost. Pro unlocks multi-file and edge features
|
|
16
42
|
- **20-70x Faster** — Rust-powered engine leaves JavaScript-based tools in the dust
|