@extenshi/cli 0.0.4 → 0.0.5
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 +5 -2
- package/dist/cli.js.map +1 -1
- package/dist/scan.d.ts +23 -0
- package/dist/scan.d.ts.map +1 -1
- package/dist/scan.js +197 -33
- package/dist/scan.js.map +1 -1
- package/dist/sse.d.ts +30 -0
- package/dist/sse.d.ts.map +1 -0
- package/dist/sse.js +53 -0
- package/dist/sse.js.map +1 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -26,7 +26,7 @@ const MISSING_KEY_HELP = 'Error: API key not found.\n' +
|
|
|
26
26
|
' • run: extenshi login\n' +
|
|
27
27
|
' • set the EXTENSHI_API_KEY environment variable\n' +
|
|
28
28
|
' • add EXTENSHI_API_KEY=... to a .env file in this directory\n' +
|
|
29
|
-
'Get an API key at https://dojo.extenshi.io/billing
|
|
29
|
+
'Get an API key at https://dojo.extenshi.io/billing';
|
|
30
30
|
const _require = createRequire(import.meta.url);
|
|
31
31
|
const pkg = _require('../package.json');
|
|
32
32
|
program
|
|
@@ -37,8 +37,9 @@ program
|
|
|
37
37
|
.command('scan <artifact>')
|
|
38
38
|
.description('Scan a browser extension artifact (.crx, .xpi, or .zip)')
|
|
39
39
|
.option('--json', 'Output raw JSON (default: pretty-printed findings)')
|
|
40
|
-
.option('--extension-id <id>',
|
|
40
|
+
.option('--extension-id <id>', "Numeric catalog ID of a verified extension (required to spend free credits; see the Ownership tab in dojo). Paid credits don't need it.")
|
|
41
41
|
.option('--skip-preflight', 'Skip CI timeout pre-flight probe (use at your own risk)')
|
|
42
|
+
.option('--no-stream', 'Disable live progress streaming; wait for a single final JSON response')
|
|
42
43
|
.option('--api-url <url>', 'Override the scan API base URL (default: https://scan.extenshi.io)')
|
|
43
44
|
.action(async (artifact, opts) => {
|
|
44
45
|
try {
|
|
@@ -56,6 +57,8 @@ program
|
|
|
56
57
|
extensionId: opts.extensionId,
|
|
57
58
|
outputJson: opts.json ?? false,
|
|
58
59
|
skipPreflight: opts.skipPreflight ?? false,
|
|
60
|
+
// commander maps --no-stream to opts.stream === false; default on.
|
|
61
|
+
stream: opts.stream ?? true,
|
|
59
62
|
});
|
|
60
63
|
}
|
|
61
64
|
catch (err) {
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,KAAK,QAAQ,MAAM,wBAAwB,CAAA;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC,MAAM,gBAAgB,GACrB,6BAA6B;IAC7B,oCAAoC;IACpC,2BAA2B;IAC3B,qDAAqD;IACrD,iEAAiE;IACjE,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/scan.d.ts
CHANGED
|
@@ -22,6 +22,27 @@
|
|
|
22
22
|
* "при network error не делайте автоматический retry —
|
|
23
23
|
* списанный credit вернётся автоматически в течение 1 минуты (auto-refund cron)"
|
|
24
24
|
*/
|
|
25
|
+
/**
|
|
26
|
+
* Build the user-facing message for a 403 from the scan API.
|
|
27
|
+
*
|
|
28
|
+
* The free credit tier is gated: free credits ONLY cover extensions whose
|
|
29
|
+
* ownership you have verified, and ONLY when you name one with
|
|
30
|
+
* `--extension-id <id>` (the numeric catalog ID of a verified extension). A
|
|
31
|
+
* bare `extenshi scan <artifact>` running on free credits therefore 403s —
|
|
32
|
+
* which is confusing when dojo just says "5 free scans left".
|
|
33
|
+
*
|
|
34
|
+
* The BFF signals this case via a stable `errorCode`
|
|
35
|
+
* (`FREE_REQUIRES_CLAIM` / `FREE_REQUIRES_VERIFIED_OWNERSHIP`). The CLI ships
|
|
36
|
+
* via npm independently of the BFF deploy, so during version skew the
|
|
37
|
+
* deployed BFF may not set `errorCode` yet — we fall back to matching the
|
|
38
|
+
* human `error` text. Either way we append actionable next steps.
|
|
39
|
+
*
|
|
40
|
+
* Exported for unit testing.
|
|
41
|
+
*/
|
|
42
|
+
export declare function buildAccessDeniedMessage(body: {
|
|
43
|
+
error?: unknown;
|
|
44
|
+
errorCode?: unknown;
|
|
45
|
+
}): string;
|
|
25
46
|
export interface ScanOptions {
|
|
26
47
|
artifactPath: string;
|
|
27
48
|
apiKey: string;
|
|
@@ -29,6 +50,8 @@ export interface ScanOptions {
|
|
|
29
50
|
extensionId?: string;
|
|
30
51
|
outputJson: boolean;
|
|
31
52
|
skipPreflight: boolean;
|
|
53
|
+
/** Request live progress over SSE (default). `false` forces the legacy single-JSON mode. */
|
|
54
|
+
stream: boolean;
|
|
32
55
|
}
|
|
33
56
|
export declare function runScan(opts: ScanOptions): Promise<void>;
|
|
34
57
|
//# sourceMappingURL=scan.d.ts.map
|
package/dist/scan.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../src/scan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;
|
|
1
|
+
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../src/scan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAeH;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,CA0B/F;AAqCD,MAAM,WAAW,WAAW;IAC3B,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,OAAO,CAAA;IACnB,aAAa,EAAE,OAAO,CAAA;IACtB,4FAA4F;IAC5F,MAAM,EAAE,OAAO,CAAA;CACf;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAkG9D"}
|
package/dist/scan.js
CHANGED
|
@@ -27,8 +27,49 @@ import path from 'node:path';
|
|
|
27
27
|
import ora from 'ora';
|
|
28
28
|
import { FormData, fetch } from 'undici';
|
|
29
29
|
import { renderReport } from './render.js';
|
|
30
|
+
import { parseSseFrames } from './sse.js';
|
|
30
31
|
const SCAN_TIMEOUT_MS = 240_000; // 240 seconds
|
|
31
32
|
const PREFLIGHT_TIMEOUT_MS = 70_000; // 70 seconds
|
|
33
|
+
const CLI_BILLING_URL = 'https://dojo.extenshi.io/billing';
|
|
34
|
+
const DOJO_URL = 'https://dojo.extenshi.io';
|
|
35
|
+
/**
|
|
36
|
+
* Build the user-facing message for a 403 from the scan API.
|
|
37
|
+
*
|
|
38
|
+
* The free credit tier is gated: free credits ONLY cover extensions whose
|
|
39
|
+
* ownership you have verified, and ONLY when you name one with
|
|
40
|
+
* `--extension-id <id>` (the numeric catalog ID of a verified extension). A
|
|
41
|
+
* bare `extenshi scan <artifact>` running on free credits therefore 403s —
|
|
42
|
+
* which is confusing when dojo just says "5 free scans left".
|
|
43
|
+
*
|
|
44
|
+
* The BFF signals this case via a stable `errorCode`
|
|
45
|
+
* (`FREE_REQUIRES_CLAIM` / `FREE_REQUIRES_VERIFIED_OWNERSHIP`). The CLI ships
|
|
46
|
+
* via npm independently of the BFF deploy, so during version skew the
|
|
47
|
+
* deployed BFF may not set `errorCode` yet — we fall back to matching the
|
|
48
|
+
* human `error` text. Either way we append actionable next steps.
|
|
49
|
+
*
|
|
50
|
+
* Exported for unit testing.
|
|
51
|
+
*/
|
|
52
|
+
export function buildAccessDeniedMessage(body) {
|
|
53
|
+
const errorMsg = typeof body.error === 'string' ? body.error : 'access denied';
|
|
54
|
+
const code = typeof body.errorCode === 'string' ? body.errorCode : '';
|
|
55
|
+
const isFreeGating = code === 'FREE_REQUIRES_CLAIM' ||
|
|
56
|
+
code === 'FREE_REQUIRES_VERIFIED_OWNERSHIP' ||
|
|
57
|
+
/free credit/i.test(errorMsg);
|
|
58
|
+
if (!isFreeGating) {
|
|
59
|
+
return `Access denied: ${errorMsg}`;
|
|
60
|
+
}
|
|
61
|
+
return (`Access denied: ${errorMsg}\n\n` +
|
|
62
|
+
`Free credits only cover extensions you have verified ownership of, and you\n` +
|
|
63
|
+
`must name one with --extension-id <id>:\n\n` +
|
|
64
|
+
` extenshi scan <artifact> --extension-id <id>\n\n` +
|
|
65
|
+
`where <id> is the numeric catalog ID of a verified extension (open the\n` +
|
|
66
|
+
`Ownership tab at ${DOJO_URL} to see your verified extensions and their IDs).\n\n` +
|
|
67
|
+
`Other options:\n` +
|
|
68
|
+
` • Claim ownership of an extension you publish:\n` +
|
|
69
|
+
` ${DOJO_URL} → Ownership tab → Claim Extension Ownership\n` +
|
|
70
|
+
` • Buy credits to scan arbitrary / unclaimed artifacts:\n` +
|
|
71
|
+
` ${CLI_BILLING_URL}`);
|
|
72
|
+
}
|
|
32
73
|
/**
|
|
33
74
|
* A spinner whose label shows live elapsed seconds, rendered to stderr so it
|
|
34
75
|
* never corrupts --json output on stdout. ora auto-disables animation when
|
|
@@ -60,7 +101,7 @@ function startElapsedSpinner(label) {
|
|
|
60
101
|
};
|
|
61
102
|
}
|
|
62
103
|
export async function runScan(opts) {
|
|
63
|
-
const { artifactPath, apiKey, apiUrl, extensionId, outputJson, skipPreflight } = opts;
|
|
104
|
+
const { artifactPath, apiKey, apiUrl, extensionId, outputJson, skipPreflight, stream } = opts;
|
|
64
105
|
// Validate artifact file exists
|
|
65
106
|
if (!fs.existsSync(artifactPath)) {
|
|
66
107
|
throw new Error(`Artifact file not found: ${artifactPath}`);
|
|
@@ -73,8 +114,11 @@ export async function runScan(opts) {
|
|
|
73
114
|
if (artifactStats.size > MAX_SIZE) {
|
|
74
115
|
throw new Error(`Artifact file exceeds 50 MB limit (${(artifactStats.size / 1024 / 1024).toFixed(1)} MB)`);
|
|
75
116
|
}
|
|
76
|
-
// Step 1: CI timeout pre-flight
|
|
77
|
-
|
|
117
|
+
// Step 1: CI timeout pre-flight.
|
|
118
|
+
// Skipped in streaming mode: the SSE keep-alive pings keep the connection
|
|
119
|
+
// alive past any outbound idle timeout, which is the very failure the
|
|
120
|
+
// pre-flight probe exists to detect — so it's redundant there.
|
|
121
|
+
if (!skipPreflight && !stream) {
|
|
78
122
|
await runPreflight(apiUrl);
|
|
79
123
|
}
|
|
80
124
|
// Step 2: Upload and scan
|
|
@@ -86,20 +130,24 @@ export async function runScan(opts) {
|
|
|
86
130
|
if (extensionId) {
|
|
87
131
|
form.append('extensionId', extensionId);
|
|
88
132
|
}
|
|
89
|
-
//
|
|
90
|
-
//
|
|
91
|
-
//
|
|
92
|
-
const progress = startElapsedSpinner(`Scanning ${artifactName}`);
|
|
133
|
+
// Legacy (non-stream) mode is one long-blocking request with no server-side
|
|
134
|
+
// progress, so show an elapsed-seconds spinner. Streaming mode draws live
|
|
135
|
+
// per-scanner progress in renderSseStream instead, so no elapsed spinner.
|
|
136
|
+
const progress = stream ? null : startElapsedSpinner(`Scanning ${artifactName}`);
|
|
93
137
|
let response;
|
|
94
138
|
try {
|
|
95
139
|
response = await fetch(`${apiUrl}/api/v1/scan`, {
|
|
96
140
|
method: 'POST',
|
|
97
141
|
body: form,
|
|
142
|
+
// Negotiate streaming progress. Auth/billing errors still come back
|
|
143
|
+
// as JSON regardless, so the response handling branches on the
|
|
144
|
+
// actual Content-Type below, not on this header.
|
|
145
|
+
headers: stream ? { accept: 'text/event-stream' } : undefined,
|
|
98
146
|
signal: AbortSignal.timeout(SCAN_TIMEOUT_MS),
|
|
99
147
|
});
|
|
100
148
|
}
|
|
101
149
|
catch (err) {
|
|
102
|
-
progress
|
|
150
|
+
progress?.stop();
|
|
103
151
|
if (err instanceof Error && err.name === 'TimeoutError') {
|
|
104
152
|
throw new Error(`Scan request timed out after ${SCAN_TIMEOUT_MS / 1000}s.\n` +
|
|
105
153
|
'This may indicate a network issue or a slow scan.\n' +
|
|
@@ -108,17 +156,52 @@ export async function runScan(opts) {
|
|
|
108
156
|
}
|
|
109
157
|
throw err;
|
|
110
158
|
}
|
|
111
|
-
//
|
|
112
|
-
//
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
159
|
+
// Auth/billing/gateway errors are always JSON (they happen before any
|
|
160
|
+
// stream starts), regardless of the Accept header → handle and throw.
|
|
161
|
+
if (!response.ok) {
|
|
162
|
+
progress?.stop();
|
|
163
|
+
const body = await parseJsonBody(response, apiUrl);
|
|
164
|
+
throwForStatus(response.status, body);
|
|
165
|
+
}
|
|
166
|
+
// Step 3: Output.
|
|
167
|
+
// Streaming success is text/event-stream; legacy success (or a server that
|
|
168
|
+
// ignored the Accept header) is a single JSON body. Branch on the actual
|
|
169
|
+
// Content-Type rather than assuming the negotiated mode.
|
|
170
|
+
const contentType = response.headers.get('content-type') ?? '';
|
|
171
|
+
if (contentType.includes('text/event-stream')) {
|
|
172
|
+
// progress is null in streaming mode — renderSseStream owns its spinner.
|
|
173
|
+
await renderSseStream(response, outputJson);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
116
176
|
let body;
|
|
117
177
|
try {
|
|
118
|
-
body =
|
|
178
|
+
body = await parseJsonBody(response, apiUrl);
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
progress?.stop();
|
|
182
|
+
throw err;
|
|
183
|
+
}
|
|
184
|
+
if (progress)
|
|
185
|
+
progress.succeed(`Scan complete in ${progress.seconds()}s`);
|
|
186
|
+
if (outputJson) {
|
|
187
|
+
process.stdout.write(`${JSON.stringify(body, null, 2)}\n`);
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
renderReport(body);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Read the response body as JSON, with a clear error if the endpoint returns
|
|
195
|
+
* an HTML/plain-text page instead (404 from a misrouted gateway, 502 from
|
|
196
|
+
* Cloudflare, etc.) — blindly calling response.json() on that throws a cryptic
|
|
197
|
+
* "Unexpected token '<'" SyntaxError that hides the real failure.
|
|
198
|
+
*/
|
|
199
|
+
async function parseJsonBody(response, apiUrl) {
|
|
200
|
+
const raw = await response.text();
|
|
201
|
+
try {
|
|
202
|
+
return JSON.parse(raw);
|
|
119
203
|
}
|
|
120
204
|
catch {
|
|
121
|
-
progress.stop();
|
|
122
205
|
const snippet = raw.replace(/\s+/g, ' ').trim().slice(0, 200);
|
|
123
206
|
const statusText = response.statusText ? ` ${response.statusText}` : '';
|
|
124
207
|
throw new Error(`Server returned a non-JSON response (HTTP ${response.status}${statusText}).\n` +
|
|
@@ -127,32 +210,113 @@ export async function runScan(opts) {
|
|
|
127
210
|
(snippet ? ` Response: ${snippet}\n` : '') +
|
|
128
211
|
`Override the endpoint with --api-url if you use a custom deployment.`);
|
|
129
212
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
213
|
+
}
|
|
214
|
+
/** Map a non-2xx status + parsed body to an actionable thrown error. */
|
|
215
|
+
function throwForStatus(status, body) {
|
|
216
|
+
const errorMsg = typeof body.error === 'string' ? body.error : `HTTP ${status}`;
|
|
217
|
+
if (status === 401) {
|
|
218
|
+
throw new Error(`Authentication failed: ${errorMsg}\nCheck your EXTENSHI_API_KEY.`);
|
|
219
|
+
}
|
|
220
|
+
if (status === 402) {
|
|
221
|
+
throw new Error(`Insufficient credits.\nPurchase more at ${CLI_BILLING_URL}`);
|
|
222
|
+
}
|
|
223
|
+
if (status === 403) {
|
|
224
|
+
throw new Error(buildAccessDeniedMessage(body));
|
|
225
|
+
}
|
|
226
|
+
if (status === 429) {
|
|
227
|
+
const retryAfter = body.retryAfterSec ?? 60;
|
|
228
|
+
throw new Error(`Rate limit exceeded. Please wait ${retryAfter}s before trying again.`);
|
|
229
|
+
}
|
|
230
|
+
throw new Error(`Scan failed: ${errorMsg}`);
|
|
231
|
+
}
|
|
232
|
+
function safeJsonParse(data) {
|
|
233
|
+
try {
|
|
234
|
+
return JSON.parse(data);
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
/** Render a unicode progress bar like `[█████░░░░░]`. */
|
|
241
|
+
function progressBar(completed, total, width = 18) {
|
|
242
|
+
const filled = total > 0 ? Math.min(width, Math.round((completed / total) * width)) : 0;
|
|
243
|
+
return `[${'█'.repeat(filled)}${'░'.repeat(Math.max(0, width - filled))}]`;
|
|
244
|
+
}
|
|
245
|
+
/** Turn a progress event into a spinner line. */
|
|
246
|
+
function formatProgress(p) {
|
|
247
|
+
const stage = p.stage ?? '';
|
|
248
|
+
const completed = typeof p.completed === 'number' ? p.completed : 0;
|
|
249
|
+
const total = typeof p.total === 'number' ? p.total : null;
|
|
250
|
+
if (stage === 'accepted')
|
|
251
|
+
return 'Queued…';
|
|
252
|
+
if (stage === 'extracting')
|
|
253
|
+
return 'Extracting artifact…';
|
|
254
|
+
if (stage === 'scanning' && total) {
|
|
255
|
+
const scanner = p.scanner ? ` ${p.scanner}` : '';
|
|
256
|
+
return `Scanning ${progressBar(completed, total)} ${completed}/${total}${scanner}`;
|
|
257
|
+
}
|
|
258
|
+
// Unknown/future stage — show the raw label rather than erroring.
|
|
259
|
+
return `${stage || 'Working'}…`;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Consume the SSE progress stream, drawing a live spinner/bar on stderr, and
|
|
263
|
+
* render the final report (pretty or JSON) once the terminal `result` event
|
|
264
|
+
* arrives. Throws on a terminal `error` event or a truncated stream.
|
|
265
|
+
*/
|
|
266
|
+
async function renderSseStream(response, outputJson) {
|
|
267
|
+
if (!response.body) {
|
|
268
|
+
throw new Error('Scan stream had no response body');
|
|
269
|
+
}
|
|
270
|
+
const spinner = ora({ stream: process.stderr, text: 'Connecting…' }).start();
|
|
271
|
+
const decoder = new TextDecoder();
|
|
272
|
+
let buffer = '';
|
|
273
|
+
let report = null;
|
|
274
|
+
let errorMessage = null;
|
|
275
|
+
const handle = (ev) => {
|
|
276
|
+
if (ev.event === 'progress') {
|
|
277
|
+
const p = safeJsonParse(ev.data);
|
|
278
|
+
if (p)
|
|
279
|
+
spinner.text = formatProgress(p);
|
|
136
280
|
}
|
|
137
|
-
if (
|
|
138
|
-
|
|
281
|
+
else if (ev.event === 'result') {
|
|
282
|
+
report = safeJsonParse(ev.data);
|
|
139
283
|
}
|
|
140
|
-
if (
|
|
141
|
-
|
|
284
|
+
else if (ev.event === 'error') {
|
|
285
|
+
const e = safeJsonParse(ev.data);
|
|
286
|
+
errorMessage = e && typeof e.error === 'string' ? e.error : 'scan failed';
|
|
142
287
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
288
|
+
};
|
|
289
|
+
try {
|
|
290
|
+
for await (const chunk of response.body) {
|
|
291
|
+
buffer += decoder.decode(chunk, { stream: true });
|
|
292
|
+
const { events, rest } = parseSseFrames(buffer);
|
|
293
|
+
buffer = rest;
|
|
294
|
+
for (const ev of events)
|
|
295
|
+
handle(ev);
|
|
146
296
|
}
|
|
147
|
-
|
|
297
|
+
// Flush any trailing frame not terminated by a blank line.
|
|
298
|
+
const { events } = parseSseFrames(`${buffer}\n\n`);
|
|
299
|
+
for (const ev of events)
|
|
300
|
+
handle(ev);
|
|
148
301
|
}
|
|
149
|
-
|
|
150
|
-
|
|
302
|
+
catch (err) {
|
|
303
|
+
spinner.fail('Scan stream interrupted');
|
|
304
|
+
throw err;
|
|
305
|
+
}
|
|
306
|
+
if (errorMessage) {
|
|
307
|
+
spinner.fail(errorMessage);
|
|
308
|
+
throw new Error(`Scan failed: ${errorMessage}`);
|
|
309
|
+
}
|
|
310
|
+
if (!report) {
|
|
311
|
+
spinner.fail('Scan ended without a result');
|
|
312
|
+
throw new Error('Scan stream ended before returning a result');
|
|
313
|
+
}
|
|
314
|
+
spinner.succeed('Scan complete');
|
|
151
315
|
if (outputJson) {
|
|
152
|
-
process.stdout.write(`${JSON.stringify(
|
|
316
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
153
317
|
}
|
|
154
318
|
else {
|
|
155
|
-
renderReport(
|
|
319
|
+
renderReport(report);
|
|
156
320
|
}
|
|
157
321
|
}
|
|
158
322
|
/**
|
package/dist/scan.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../src/scan.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../src/scan.ts"],"names":[],"mappings":"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"}
|
package/dist/sse.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal Server-Sent Events frame parser for the scan progress stream.
|
|
3
|
+
*
|
|
4
|
+
* The worker emits `text/event-stream` with named events (`progress`,
|
|
5
|
+
* `result`, `error`) plus keep-alive comment frames (`:ping`). See
|
|
6
|
+
* services/extenshi-scan-worker/PROGRESS_PROTOCOL.md.
|
|
7
|
+
*
|
|
8
|
+
* This module is intentionally pure (no I/O) so it can be unit-tested:
|
|
9
|
+
* feed it the accumulated buffer, get back the complete events plus the
|
|
10
|
+
* unconsumed tail to carry into the next chunk.
|
|
11
|
+
*/
|
|
12
|
+
export interface SseEvent {
|
|
13
|
+
/** The `event:` field value (defaults to "message" per the SSE spec). */
|
|
14
|
+
event: string;
|
|
15
|
+
/** The joined `data:` field value(s). */
|
|
16
|
+
data: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Split an accumulated SSE buffer into complete events.
|
|
20
|
+
*
|
|
21
|
+
* Frames are delimited by a blank line (`\n\n`). A partial frame at the end is
|
|
22
|
+
* returned as `rest` so the caller can prepend it to the next chunk. Comment
|
|
23
|
+
* frames (lines starting with `:`, e.g. keep-alive pings) and frames with no
|
|
24
|
+
* `data` are skipped.
|
|
25
|
+
*/
|
|
26
|
+
export declare function parseSseFrames(buffer: string): {
|
|
27
|
+
events: SseEvent[];
|
|
28
|
+
rest: string;
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=sse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../src/sse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,QAAQ;IACxB,yEAAyE;IACzE,KAAK,EAAE,MAAM,CAAA;IACb,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAA;CACZ;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAmCnF"}
|
package/dist/sse.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal Server-Sent Events frame parser for the scan progress stream.
|
|
3
|
+
*
|
|
4
|
+
* The worker emits `text/event-stream` with named events (`progress`,
|
|
5
|
+
* `result`, `error`) plus keep-alive comment frames (`:ping`). See
|
|
6
|
+
* services/extenshi-scan-worker/PROGRESS_PROTOCOL.md.
|
|
7
|
+
*
|
|
8
|
+
* This module is intentionally pure (no I/O) so it can be unit-tested:
|
|
9
|
+
* feed it the accumulated buffer, get back the complete events plus the
|
|
10
|
+
* unconsumed tail to carry into the next chunk.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Split an accumulated SSE buffer into complete events.
|
|
14
|
+
*
|
|
15
|
+
* Frames are delimited by a blank line (`\n\n`). A partial frame at the end is
|
|
16
|
+
* returned as `rest` so the caller can prepend it to the next chunk. Comment
|
|
17
|
+
* frames (lines starting with `:`, e.g. keep-alive pings) and frames with no
|
|
18
|
+
* `data` are skipped.
|
|
19
|
+
*/
|
|
20
|
+
export function parseSseFrames(buffer) {
|
|
21
|
+
// Normalize CRLF so frame splitting on `\n\n` is reliable regardless of
|
|
22
|
+
// the server's line endings. A `\r\n` straddling a chunk boundary stays in
|
|
23
|
+
// `rest` and is normalized on the next pass.
|
|
24
|
+
let buf = buffer.replace(/\r\n/g, '\n');
|
|
25
|
+
const events = [];
|
|
26
|
+
while (true) {
|
|
27
|
+
const boundary = buf.indexOf('\n\n');
|
|
28
|
+
if (boundary === -1)
|
|
29
|
+
break;
|
|
30
|
+
const frame = buf.slice(0, boundary);
|
|
31
|
+
buf = buf.slice(boundary + 2);
|
|
32
|
+
let eventName = 'message';
|
|
33
|
+
const dataLines = [];
|
|
34
|
+
for (const line of frame.split('\n')) {
|
|
35
|
+
if (line === '' || line.startsWith(':'))
|
|
36
|
+
continue; // blank or comment (keep-alive)
|
|
37
|
+
const colon = line.indexOf(':');
|
|
38
|
+
const field = colon === -1 ? line : line.slice(0, colon);
|
|
39
|
+
let value = colon === -1 ? '' : line.slice(colon + 1);
|
|
40
|
+
if (value.startsWith(' '))
|
|
41
|
+
value = value.slice(1); // strip one leading space
|
|
42
|
+
if (field === 'event')
|
|
43
|
+
eventName = value;
|
|
44
|
+
else if (field === 'data')
|
|
45
|
+
dataLines.push(value);
|
|
46
|
+
}
|
|
47
|
+
if (dataLines.length > 0) {
|
|
48
|
+
events.push({ event: eventName, data: dataLines.join('\n') });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return { events, rest: buf };
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=sse.js.map
|
package/dist/sse.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse.js","sourceRoot":"","sources":["../src/sse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AASH;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc;IAC5C,wEAAwE;IACxE,2EAA2E;IAC3E,6CAA6C;IAC7C,IAAI,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;IACvC,MAAM,MAAM,GAAe,EAAE,CAAA;IAE7B,OAAO,IAAI,EAAE,CAAC;QACb,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;QACpC,IAAI,QAAQ,KAAK,CAAC,CAAC;YAAE,MAAK;QAE1B,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAA;QACpC,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAA;QAE7B,IAAI,SAAS,GAAG,SAAS,CAAA;QACzB,MAAM,SAAS,GAAa,EAAE,CAAA;QAE9B,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACtC,IAAI,IAAI,KAAK,EAAE,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,SAAQ,CAAC,gCAAgC;YAElF,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;YAC/B,MAAM,KAAK,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;YACxD,IAAI,KAAK,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAA;YACrD,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA,CAAC,0BAA0B;YAE5E,IAAI,KAAK,KAAK,OAAO;gBAAE,SAAS,GAAG,KAAK,CAAA;iBACnC,IAAI,KAAK,KAAK,MAAM;gBAAE,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACjD,CAAC;QAED,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAC9D,CAAC;IACF,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,CAAA;AAC7B,CAAC"}
|