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 CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  //#region package.json
3
- var version = "0.0.13";
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/scan`, {
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?id=${result.id}`)}\n`);
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":"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"}
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":";;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,YAAY;GAC/C,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,oBAAoB,OAAO,GAAG,EAC3C,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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "afterpack",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
4
4
  "description": "A high-performance post-build JavaScript obfuscator and minifier",
5
5
  "type": "module",
6
6
  "main": "./dist/cli.js",
package/readme.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # [AfterPack](https://www.afterpack.dev)
2
2
 
3
- A high-performance post-build JavaScript obfuscator and minifier — the final step before your code ships.
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
- ## Features
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