@saptools/cf-inspector 0.4.12 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +217 -32
- package/dist/cli.js +1509 -538
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +145 -9
- package/dist/index.js +1130 -250
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -152,7 +152,7 @@ var init_wsTransport = __esm({
|
|
|
152
152
|
});
|
|
153
153
|
|
|
154
154
|
// src/cli.ts
|
|
155
|
-
import
|
|
155
|
+
import process11 from "process";
|
|
156
156
|
|
|
157
157
|
// src/cli/program.ts
|
|
158
158
|
import { readFileSync } from "fs";
|
|
@@ -166,37 +166,65 @@ import process3 from "process";
|
|
|
166
166
|
// src/inspector/discovery.ts
|
|
167
167
|
init_types();
|
|
168
168
|
import { request } from "http";
|
|
169
|
+
import { performance } from "perf_hooks";
|
|
170
|
+
var InvalidDiscoveryPayloadError = class extends CfInspectorError {
|
|
171
|
+
};
|
|
169
172
|
async function fetchJson(url, timeoutMs) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
173
|
+
const deadline = performance.now() + timeoutMs;
|
|
174
|
+
let lastError;
|
|
175
|
+
while (performance.now() < deadline) {
|
|
176
|
+
try {
|
|
177
|
+
const remainingMs = deadline - performance.now();
|
|
178
|
+
if (remainingMs <= 0) {
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
return await new Promise((resolve, reject) => {
|
|
182
|
+
const req = request(url, { method: "GET" }, (res) => {
|
|
183
|
+
const chunks = [];
|
|
184
|
+
res.on("data", (chunk) => {
|
|
185
|
+
chunks.push(chunk);
|
|
186
|
+
});
|
|
187
|
+
res.on("end", () => {
|
|
188
|
+
try {
|
|
189
|
+
resolve(parseJsonResponse(chunks));
|
|
190
|
+
} catch (err) {
|
|
191
|
+
reject(parseDiscoveryError(url, err));
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
res.on("error", (err) => {
|
|
195
|
+
reject(newDiscoveryError(`Inspector discovery response error: ${err.message}`));
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
const attemptTimeoutMs = Math.min(2e3, remainingMs);
|
|
199
|
+
req.setTimeout(attemptTimeoutMs, () => {
|
|
200
|
+
req.destroy(
|
|
201
|
+
new CfInspectorError(
|
|
202
|
+
"INSPECTOR_DISCOVERY_FAILED",
|
|
203
|
+
`Inspector discovery at ${url} timed out after ${timeoutMs.toString()}ms`
|
|
204
|
+
)
|
|
205
|
+
);
|
|
206
|
+
});
|
|
207
|
+
req.on("error", (err) => {
|
|
208
|
+
reject(err instanceof CfInspectorError ? err : formatDiscoveryRequestError(url, err));
|
|
209
|
+
});
|
|
210
|
+
req.end();
|
|
185
211
|
});
|
|
186
|
-
})
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
212
|
+
} catch (err) {
|
|
213
|
+
if (err instanceof InvalidDiscoveryPayloadError) {
|
|
214
|
+
throw err;
|
|
215
|
+
}
|
|
216
|
+
lastError = err;
|
|
217
|
+
const now = performance.now();
|
|
218
|
+
if (now < deadline) {
|
|
219
|
+
const sleepMs = Math.min(1e3, deadline - now);
|
|
220
|
+
await new Promise((r) => setTimeout(r, sleepMs));
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
if (lastError instanceof Error) {
|
|
225
|
+
throw lastError;
|
|
226
|
+
}
|
|
227
|
+
throw new CfInspectorError("INSPECTOR_DISCOVERY_FAILED", `Inspector discovery at ${url} timed out after ${timeoutMs.toString()}ms`);
|
|
200
228
|
}
|
|
201
229
|
function isNodeSystemError(err) {
|
|
202
230
|
return err instanceof Error;
|
|
@@ -232,7 +260,10 @@ function parseJsonResponse(chunks) {
|
|
|
232
260
|
}
|
|
233
261
|
function parseDiscoveryError(url, err) {
|
|
234
262
|
const message = err instanceof Error ? err.message : String(err);
|
|
235
|
-
return
|
|
263
|
+
return new InvalidDiscoveryPayloadError(
|
|
264
|
+
"INSPECTOR_DISCOVERY_FAILED",
|
|
265
|
+
`Failed to parse inspector discovery response from ${url}: ${message}`
|
|
266
|
+
);
|
|
236
267
|
}
|
|
237
268
|
function newDiscoveryError(message) {
|
|
238
269
|
return new CfInspectorError("INSPECTOR_DISCOVERY_FAILED", message);
|
|
@@ -332,7 +363,7 @@ function writeHumanSnapshot(snapshot) {
|
|
|
332
363
|
lines.push(" captures:");
|
|
333
364
|
for (const capture of snapshot.captures) {
|
|
334
365
|
const detail = capture.error ?? capture.value ?? "undefined";
|
|
335
|
-
lines.push(` ${capture.expression} = ${detail}`);
|
|
366
|
+
lines.push(` ${capture.expression} = ${renderTruncated(detail, capture)}`);
|
|
336
367
|
}
|
|
337
368
|
}
|
|
338
369
|
if (snapshot.stack !== void 0 && snapshot.stack.length > 0) {
|
|
@@ -350,13 +381,17 @@ function appendFrameLines(lines, frame) {
|
|
|
350
381
|
lines.push(
|
|
351
382
|
` frame: ${fnName} ${sourceUrl}:${frame.line.toString()}:${frame.column.toString()}`
|
|
352
383
|
);
|
|
384
|
+
if (frame.truncated === true) {
|
|
385
|
+
lines.push(` scopes: ${truncationLabel(frame)}`);
|
|
386
|
+
}
|
|
353
387
|
if (frame.scopes === void 0) {
|
|
354
388
|
return;
|
|
355
389
|
}
|
|
356
390
|
for (const scope of frame.scopes) {
|
|
357
|
-
|
|
391
|
+
const scopeSuffix = scope.truncated === true ? `; ${truncationLabel(scope)}` : "";
|
|
392
|
+
lines.push(` scope ${scope.type} (${scope.variables.length.toString()} vars${scopeSuffix}):`);
|
|
358
393
|
for (const variable of scope.variables) {
|
|
359
|
-
lines.push(` ${variable.name} = ${variable.value}`);
|
|
394
|
+
lines.push(` ${variable.name} = ${renderTruncated(variable.value, variable)}`);
|
|
360
395
|
}
|
|
361
396
|
}
|
|
362
397
|
}
|
|
@@ -367,7 +402,7 @@ function appendStackFrameLine(lines, frame) {
|
|
|
367
402
|
if (frame.captures !== void 0) {
|
|
368
403
|
for (const capture of frame.captures) {
|
|
369
404
|
const detail = capture.error ?? capture.value ?? "undefined";
|
|
370
|
-
lines.push(` ${capture.expression} = ${detail}`);
|
|
405
|
+
lines.push(` ${capture.expression} = ${renderTruncated(detail, capture)}`);
|
|
371
406
|
}
|
|
372
407
|
}
|
|
373
408
|
}
|
|
@@ -376,8 +411,7 @@ function appendExceptionLines(lines, exception) {
|
|
|
376
411
|
lines.push(` exception: !err ${exception.error}`);
|
|
377
412
|
return;
|
|
378
413
|
}
|
|
379
|
-
|
|
380
|
-
lines.push(` exception: ${detail}`);
|
|
414
|
+
lines.push(` exception: ${renderExceptionDetail(exception)}`);
|
|
381
415
|
}
|
|
382
416
|
function writeLogEvent(event, json) {
|
|
383
417
|
if (json) {
|
|
@@ -386,11 +420,11 @@ function writeLogEvent(event, json) {
|
|
|
386
420
|
return;
|
|
387
421
|
}
|
|
388
422
|
if (event.error !== void 0) {
|
|
389
|
-
process.stdout.write(`[${event.ts}] ${event.at} !err ${event.error}
|
|
423
|
+
process.stdout.write(`[${event.ts}] ${event.at} !err ${renderTruncated(event.error, event)}
|
|
390
424
|
`);
|
|
391
425
|
return;
|
|
392
426
|
}
|
|
393
|
-
process.stdout.write(`[${event.ts}] ${event.at} ${event.value ?? ""}
|
|
427
|
+
process.stdout.write(`[${event.ts}] ${event.at} ${renderTruncated(event.value ?? "", event)}
|
|
394
428
|
`);
|
|
395
429
|
}
|
|
396
430
|
function writeWatchEvent(event, json) {
|
|
@@ -402,90 +436,124 @@ function writeWatchEvent(event, json) {
|
|
|
402
436
|
process.stdout.write(`[${event.ts}] hit#${event.hit.toString()} ${event.at}
|
|
403
437
|
`);
|
|
404
438
|
if (event.exception !== void 0) {
|
|
405
|
-
|
|
406
|
-
process.stdout.write(` exception: ${detail}
|
|
439
|
+
process.stdout.write(` exception: ${renderExceptionDetail(event.exception)}
|
|
407
440
|
`);
|
|
408
441
|
}
|
|
409
442
|
for (const capture of event.captures) {
|
|
410
443
|
const detail = capture.error ?? capture.value ?? "undefined";
|
|
411
|
-
process.stdout.write(` ${capture.expression} = ${detail}
|
|
444
|
+
process.stdout.write(` ${capture.expression} = ${renderTruncated(detail, capture)}
|
|
412
445
|
`);
|
|
413
446
|
}
|
|
414
447
|
}
|
|
448
|
+
function renderExceptionDetail(exception) {
|
|
449
|
+
if (exception.description !== void 0) {
|
|
450
|
+
const originalLength = exception.descriptionOriginalLength;
|
|
451
|
+
return renderTruncated(
|
|
452
|
+
exception.description,
|
|
453
|
+
originalLength === void 0 ? {} : { truncated: true, originalLength }
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
if (exception.value !== void 0) {
|
|
457
|
+
const originalLength = exception.valueOriginalLength ?? exception.originalLength;
|
|
458
|
+
const summary = {
|
|
459
|
+
...originalLength === void 0 ? {} : { truncated: true, originalLength },
|
|
460
|
+
...exception.omittedCount === void 0 ? {} : { truncated: true, omittedCount: exception.omittedCount }
|
|
461
|
+
};
|
|
462
|
+
return renderTruncated(exception.value, summary);
|
|
463
|
+
}
|
|
464
|
+
return exception.error ?? "(unknown)";
|
|
465
|
+
}
|
|
466
|
+
function renderTruncated(value, summary) {
|
|
467
|
+
if (summary.truncated !== true) {
|
|
468
|
+
return value;
|
|
469
|
+
}
|
|
470
|
+
const visualValue = summary.originalLength === void 0 ? value : `${value}\u2026`;
|
|
471
|
+
return `${visualValue} [${truncationLabel(summary)}]`;
|
|
472
|
+
}
|
|
473
|
+
function truncationLabel(summary) {
|
|
474
|
+
const details = [];
|
|
475
|
+
if (summary.originalLength !== void 0) {
|
|
476
|
+
details.push(`original ${summary.originalLength.toString()} chars`);
|
|
477
|
+
}
|
|
478
|
+
if (summary.omittedCount !== void 0) {
|
|
479
|
+
details.push(`${summary.omittedCount.toString()} omitted`);
|
|
480
|
+
}
|
|
481
|
+
return details.length === 0 ? "truncated" : `truncated: ${details.join(", ")}`;
|
|
482
|
+
}
|
|
415
483
|
|
|
416
484
|
// src/cli/target.ts
|
|
417
|
-
import
|
|
418
|
-
import {
|
|
419
|
-
readCurrentCfTarget,
|
|
420
|
-
requireCurrentCfRegion
|
|
421
|
-
} from "@saptools/cf-debugger";
|
|
485
|
+
import "@saptools/cf-debugger";
|
|
422
486
|
|
|
423
487
|
// src/cf/tunnel.ts
|
|
424
488
|
import { startDebugger } from "@saptools/cf-debugger";
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
region: target.region,
|
|
489
|
+
function targetOptions(target) {
|
|
490
|
+
return {
|
|
428
491
|
...target.apiEndpoint === void 0 ? {} : { apiEndpoint: target.apiEndpoint },
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
492
|
+
...target.process === void 0 ? {} : { process: target.process },
|
|
493
|
+
...target.instance === void 0 ? {} : { instance: target.instance },
|
|
494
|
+
...target.nodePid === void 0 ? {} : { nodePid: target.nodePid }
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
function lifecycleOptions(target) {
|
|
498
|
+
return {
|
|
499
|
+
...target.allowSshEnableRestart === void 0 ? {} : { allowSshEnableRestart: target.allowSshEnableRestart },
|
|
432
500
|
...target.tunnelReadyTimeoutMs === void 0 ? {} : { tunnelReadyTimeoutMs: target.tunnelReadyTimeoutMs },
|
|
433
501
|
...target.preferredPort === void 0 ? {} : { preferredPort: target.preferredPort },
|
|
434
502
|
...target.verbose === void 0 ? {} : { verbose: target.verbose },
|
|
435
503
|
...target.signal === void 0 ? {} : { signal: target.signal },
|
|
436
504
|
...target.onStatus === void 0 ? {} : { onStatus: target.onStatus }
|
|
437
505
|
};
|
|
438
|
-
try {
|
|
439
|
-
const handle = await startDebugger(opts);
|
|
440
|
-
return {
|
|
441
|
-
localPort: handle.session.localPort,
|
|
442
|
-
handle,
|
|
443
|
-
dispose: async () => {
|
|
444
|
-
await handle.dispose();
|
|
445
|
-
}
|
|
446
|
-
};
|
|
447
|
-
} catch (err) {
|
|
448
|
-
return reuseExistingTunnelOrThrow(err, target.onStatus);
|
|
449
|
-
}
|
|
450
506
|
}
|
|
451
|
-
function
|
|
452
|
-
if (!isSessionAlreadyRunningError(err)) {
|
|
453
|
-
throw err;
|
|
454
|
-
}
|
|
455
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
456
|
-
const port = extractExistingTunnelPort(message);
|
|
457
|
-
if (port === void 0) {
|
|
458
|
-
throw err;
|
|
459
|
-
}
|
|
460
|
-
const warning = `Reusing existing tunnel on port ${port.toString()}`;
|
|
461
|
-
onStatus?.("ready", warning);
|
|
507
|
+
function toStartDebuggerOptions(target) {
|
|
462
508
|
return {
|
|
463
|
-
|
|
464
|
-
|
|
509
|
+
region: target.region,
|
|
510
|
+
org: target.org,
|
|
511
|
+
space: target.space,
|
|
512
|
+
app: target.app,
|
|
513
|
+
...targetOptions(target),
|
|
514
|
+
...lifecycleOptions(target)
|
|
465
515
|
};
|
|
466
516
|
}
|
|
467
|
-
function
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
517
|
+
async function openOwnedCfTunnel(target) {
|
|
518
|
+
const opts = toStartDebuggerOptions(target);
|
|
519
|
+
const handle = await startDebugger(opts);
|
|
520
|
+
return {
|
|
521
|
+
localPort: handle.session.localPort,
|
|
522
|
+
handle,
|
|
523
|
+
dispose: async () => {
|
|
524
|
+
await handle.dispose();
|
|
525
|
+
}
|
|
526
|
+
};
|
|
473
527
|
}
|
|
474
|
-
function
|
|
475
|
-
|
|
476
|
-
|
|
528
|
+
function isExistingSessionError(error) {
|
|
529
|
+
return error instanceof Error && "code" in error && error.code === "SESSION_ALREADY_RUNNING";
|
|
530
|
+
}
|
|
531
|
+
function existingTunnelPort(error) {
|
|
532
|
+
if (!isExistingSessionError(error)) {
|
|
477
533
|
return void 0;
|
|
478
534
|
}
|
|
479
|
-
const rawPort =
|
|
535
|
+
const rawPort = /\bon port (\d+)\b/iu.exec(error.message)?.[1];
|
|
480
536
|
if (rawPort === void 0) {
|
|
481
537
|
return void 0;
|
|
482
538
|
}
|
|
483
539
|
const port = Number.parseInt(rawPort, 10);
|
|
484
|
-
return Number.
|
|
540
|
+
return Number.isInteger(port) && port >= 1 && port <= 65535 ? port : void 0;
|
|
541
|
+
}
|
|
542
|
+
async function openCfTunnel(target) {
|
|
543
|
+
try {
|
|
544
|
+
return await openOwnedCfTunnel(target);
|
|
545
|
+
} catch (error) {
|
|
546
|
+
const localPort = existingTunnelPort(error);
|
|
547
|
+
if (localPort === void 0) {
|
|
548
|
+
throw error;
|
|
549
|
+
}
|
|
550
|
+
target.onStatus?.("ready", `Reusing existing tunnel on port ${localPort.toString()}`);
|
|
551
|
+
return { localPort, dispose: () => Promise.resolve() };
|
|
552
|
+
}
|
|
485
553
|
}
|
|
486
554
|
|
|
487
555
|
// src/inspector/session.ts
|
|
488
|
-
import { performance } from "perf_hooks";
|
|
556
|
+
import { performance as performance2 } from "perf_hooks";
|
|
489
557
|
|
|
490
558
|
// src/cdp/client.ts
|
|
491
559
|
init_types();
|
|
@@ -588,54 +656,70 @@ var CdpClient = class _CdpClient {
|
|
|
588
656
|
if (this.closed) {
|
|
589
657
|
throw this.closeReason ?? new CfInspectorError("INSPECTOR_CONNECTION_FAILED", "Connection closed");
|
|
590
658
|
}
|
|
591
|
-
|
|
659
|
+
if (options.signal?.aborted === true) {
|
|
660
|
+
throw this.createWaitAbortError(method);
|
|
661
|
+
}
|
|
662
|
+
return await this.createEventWait(method, options);
|
|
663
|
+
}
|
|
664
|
+
createEventWait(method, options) {
|
|
665
|
+
return new Promise((resolve, reject) => {
|
|
592
666
|
let settled = false;
|
|
667
|
+
let offEvent = () => void 0;
|
|
668
|
+
let offClose = () => void 0;
|
|
593
669
|
const cleanup = () => {
|
|
594
670
|
clearTimeout(timer);
|
|
595
671
|
offEvent();
|
|
596
672
|
offClose();
|
|
673
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
597
674
|
};
|
|
598
|
-
const
|
|
675
|
+
const resolveOnce = (value) => {
|
|
676
|
+
if (settled) {
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
599
679
|
settled = true;
|
|
600
680
|
cleanup();
|
|
601
681
|
resolve(value);
|
|
602
682
|
};
|
|
603
|
-
const
|
|
604
|
-
if (settled) {
|
|
605
|
-
return;
|
|
606
|
-
}
|
|
607
|
-
const params = raw;
|
|
608
|
-
if (options.predicate) {
|
|
609
|
-
let accepted;
|
|
610
|
-
try {
|
|
611
|
-
accepted = options.predicate(params);
|
|
612
|
-
} catch {
|
|
613
|
-
return;
|
|
614
|
-
}
|
|
615
|
-
if (!accepted) {
|
|
616
|
-
return;
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
finish(params);
|
|
620
|
-
});
|
|
621
|
-
const offClose = this.onClose((err) => {
|
|
683
|
+
const rejectOnce = (error) => {
|
|
622
684
|
if (settled) {
|
|
623
685
|
return;
|
|
624
686
|
}
|
|
625
687
|
settled = true;
|
|
626
688
|
cleanup();
|
|
627
|
-
reject(
|
|
628
|
-
}
|
|
689
|
+
reject(error);
|
|
690
|
+
};
|
|
691
|
+
const onAbort = () => {
|
|
692
|
+
rejectOnce(this.createWaitAbortError(method));
|
|
693
|
+
};
|
|
629
694
|
const timer = setTimeout(() => {
|
|
630
|
-
|
|
695
|
+
rejectOnce(this.createWaitTimeoutError(method, options.timeoutMs));
|
|
696
|
+
}, options.timeoutMs);
|
|
697
|
+
offEvent = this.on(method, (raw) => {
|
|
698
|
+
const params = raw;
|
|
699
|
+
if (!this.eventMatches(params, options.predicate)) {
|
|
631
700
|
return;
|
|
632
701
|
}
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
702
|
+
resolveOnce(params);
|
|
703
|
+
});
|
|
704
|
+
offClose = this.onClose((error) => {
|
|
705
|
+
rejectOnce(error);
|
|
706
|
+
});
|
|
707
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
708
|
+
if (options.signal?.aborted === true) {
|
|
709
|
+
onAbort();
|
|
710
|
+
}
|
|
637
711
|
});
|
|
638
712
|
}
|
|
713
|
+
eventMatches(params, predicate) {
|
|
714
|
+
if (predicate === void 0) {
|
|
715
|
+
return true;
|
|
716
|
+
}
|
|
717
|
+
try {
|
|
718
|
+
return predicate(params);
|
|
719
|
+
} catch {
|
|
720
|
+
return false;
|
|
721
|
+
}
|
|
722
|
+
}
|
|
639
723
|
onClose(listener) {
|
|
640
724
|
if (this.closed) {
|
|
641
725
|
const reason = this.closeReason ?? new CfInspectorError("INSPECTOR_CONNECTION_FAILED", "Connection closed");
|
|
@@ -702,6 +786,9 @@ var CdpClient = class _CdpClient {
|
|
|
702
786
|
`Timed out waiting for ${method} after ${timeoutMs.toString()}ms`
|
|
703
787
|
);
|
|
704
788
|
}
|
|
789
|
+
createWaitAbortError(method) {
|
|
790
|
+
return new CfInspectorError("ABORTED", `Aborted while waiting for ${method}`);
|
|
791
|
+
}
|
|
705
792
|
sendPayload(id, method, payload, timer, reject) {
|
|
706
793
|
try {
|
|
707
794
|
this.transport.send(payload);
|
|
@@ -727,101 +814,378 @@ var CdpClient = class _CdpClient {
|
|
|
727
814
|
this.emitter.removeAllListeners();
|
|
728
815
|
}
|
|
729
816
|
};
|
|
817
|
+
var NodeWorkerTransport = class {
|
|
818
|
+
constructor(parent, sessionId) {
|
|
819
|
+
this.parent = parent;
|
|
820
|
+
this.sessionId = sessionId;
|
|
821
|
+
this.detachParentListeners = [
|
|
822
|
+
parent.on("NodeWorker.receivedMessageFromWorker", (raw) => {
|
|
823
|
+
this.forwardWorkerMessage(raw);
|
|
824
|
+
}),
|
|
825
|
+
parent.on("NodeWorker.detachedFromWorker", (raw) => {
|
|
826
|
+
this.handleWorkerDetach(raw);
|
|
827
|
+
}),
|
|
828
|
+
parent.onClose((error) => {
|
|
829
|
+
this.closeWithError(error);
|
|
830
|
+
})
|
|
831
|
+
];
|
|
832
|
+
}
|
|
833
|
+
parent;
|
|
834
|
+
sessionId;
|
|
835
|
+
emitter = new EventEmitter();
|
|
836
|
+
detachParentListeners;
|
|
837
|
+
readyState = 1;
|
|
838
|
+
send(payload) {
|
|
839
|
+
if (this.readyState !== 1) {
|
|
840
|
+
throw new CfInspectorError("INSPECTOR_CONNECTION_FAILED", "Worker inspector session is closed");
|
|
841
|
+
}
|
|
842
|
+
void this.parent.send("NodeWorker.sendMessageToWorker", {
|
|
843
|
+
sessionId: this.sessionId,
|
|
844
|
+
message: payload
|
|
845
|
+
}).catch((error) => {
|
|
846
|
+
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
847
|
+
this.closeWithError(normalized);
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
close() {
|
|
851
|
+
this.finishClose();
|
|
852
|
+
}
|
|
853
|
+
on(event, listener) {
|
|
854
|
+
this.emitter.on(event, listener);
|
|
855
|
+
}
|
|
856
|
+
off(event, listener) {
|
|
857
|
+
this.emitter.off(event, listener);
|
|
858
|
+
}
|
|
859
|
+
forwardWorkerMessage(raw) {
|
|
860
|
+
const params = asNodeWorkerEventParams(raw);
|
|
861
|
+
if (params.sessionId !== this.sessionId || typeof params.message !== "string") {
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
this.emitter.emit("message", params.message);
|
|
865
|
+
}
|
|
866
|
+
handleWorkerDetach(raw) {
|
|
867
|
+
const params = asNodeWorkerEventParams(raw);
|
|
868
|
+
if (params.sessionId === this.sessionId) {
|
|
869
|
+
this.finishClose();
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
closeWithError(error) {
|
|
873
|
+
if (this.readyState !== 1) {
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
this.emitter.emit("error", error);
|
|
877
|
+
this.finishClose();
|
|
878
|
+
}
|
|
879
|
+
finishClose() {
|
|
880
|
+
if (this.readyState !== 1) {
|
|
881
|
+
return;
|
|
882
|
+
}
|
|
883
|
+
this.readyState = 3;
|
|
884
|
+
for (const detach of this.detachParentListeners) {
|
|
885
|
+
detach();
|
|
886
|
+
}
|
|
887
|
+
this.emitter.emit("close");
|
|
888
|
+
this.emitter.removeAllListeners();
|
|
889
|
+
}
|
|
890
|
+
};
|
|
891
|
+
function asNodeWorkerEventParams(raw) {
|
|
892
|
+
if (!isUnknownRecord(raw)) {
|
|
893
|
+
return {};
|
|
894
|
+
}
|
|
895
|
+
const sessionId = raw["sessionId"];
|
|
896
|
+
const message = raw["message"];
|
|
897
|
+
return {
|
|
898
|
+
...typeof sessionId === "string" ? { sessionId } : {},
|
|
899
|
+
...typeof message === "string" ? { message } : {}
|
|
900
|
+
};
|
|
901
|
+
}
|
|
902
|
+
function isUnknownRecord(value) {
|
|
903
|
+
return typeof value === "object" && value !== null;
|
|
904
|
+
}
|
|
905
|
+
async function createNodeWorkerClient(parent, sessionId, requestTimeoutMs = DEFAULT_REQUEST_TIMEOUT_MS) {
|
|
906
|
+
const transport = new NodeWorkerTransport(parent, sessionId);
|
|
907
|
+
return await CdpClient.connect({
|
|
908
|
+
url: `node-worker://${sessionId}`,
|
|
909
|
+
transportFactory: () => Promise.resolve(transport),
|
|
910
|
+
requestTimeoutMs
|
|
911
|
+
});
|
|
912
|
+
}
|
|
730
913
|
|
|
731
914
|
// src/inspector/session.ts
|
|
732
915
|
init_types();
|
|
733
916
|
|
|
734
917
|
// src/inspector/conversions.ts
|
|
918
|
+
var INTERNAL_SLOT_SUBTYPES = /* @__PURE__ */ new Set([
|
|
919
|
+
"regexp",
|
|
920
|
+
"date",
|
|
921
|
+
"map",
|
|
922
|
+
"set",
|
|
923
|
+
"weakmap",
|
|
924
|
+
"weakset",
|
|
925
|
+
"iterator",
|
|
926
|
+
"generator",
|
|
927
|
+
"promise",
|
|
928
|
+
"typedarray",
|
|
929
|
+
"arraybuffer",
|
|
930
|
+
"dataview",
|
|
931
|
+
"webassemblymemory",
|
|
932
|
+
"wasmvalue",
|
|
933
|
+
"trustedtype"
|
|
934
|
+
]);
|
|
735
935
|
function asString(value, fallback = "") {
|
|
736
936
|
return typeof value === "string" ? value : fallback;
|
|
737
937
|
}
|
|
738
938
|
function asNumber(value, fallback = 0) {
|
|
739
939
|
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
740
940
|
}
|
|
941
|
+
function isRecord(value) {
|
|
942
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
943
|
+
}
|
|
741
944
|
function nonEmptyString(value) {
|
|
742
945
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
743
946
|
}
|
|
947
|
+
function optionalNumber(value) {
|
|
948
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
949
|
+
}
|
|
950
|
+
function optionalCoordinate(value) {
|
|
951
|
+
const number = optionalNumber(value);
|
|
952
|
+
return number !== void 0 && Number.isSafeInteger(number) && number >= 0 ? number : void 0;
|
|
953
|
+
}
|
|
954
|
+
function optionalBoolean(value) {
|
|
955
|
+
return typeof value === "boolean" ? value : void 0;
|
|
956
|
+
}
|
|
957
|
+
function toScriptLocation(value) {
|
|
958
|
+
if (!isRecord(value)) {
|
|
959
|
+
return void 0;
|
|
960
|
+
}
|
|
961
|
+
const scriptId = nonEmptyString(value["scriptId"]);
|
|
962
|
+
const lineNumber = optionalCoordinate(value["lineNumber"]);
|
|
963
|
+
if (scriptId === void 0 || lineNumber === void 0) {
|
|
964
|
+
return void 0;
|
|
965
|
+
}
|
|
966
|
+
const rawColumnNumber = value["columnNumber"];
|
|
967
|
+
const columnNumber = optionalCoordinate(rawColumnNumber);
|
|
968
|
+
if (rawColumnNumber !== void 0 && columnNumber === void 0) {
|
|
969
|
+
return void 0;
|
|
970
|
+
}
|
|
971
|
+
return columnNumber === void 0 ? { scriptId, lineNumber } : { scriptId, lineNumber, columnNumber };
|
|
972
|
+
}
|
|
744
973
|
function toResolvedLocations(value) {
|
|
745
974
|
if (!Array.isArray(value)) {
|
|
746
975
|
return [];
|
|
747
976
|
}
|
|
748
977
|
return value.flatMap((entry) => {
|
|
749
|
-
|
|
978
|
+
const location = toScriptLocation(entry);
|
|
979
|
+
if (location === void 0 || !isRecord(entry)) {
|
|
750
980
|
return [];
|
|
751
981
|
}
|
|
752
|
-
const
|
|
753
|
-
|
|
754
|
-
if (scriptId.length === 0) {
|
|
755
|
-
return [];
|
|
756
|
-
}
|
|
757
|
-
const url = typeof candidate.url === "string" ? candidate.url : void 0;
|
|
758
|
-
const lineNumber = asNumber(candidate.lineNumber);
|
|
759
|
-
const result = url === void 0 ? { scriptId, lineNumber, columnNumber: asNumber(candidate.columnNumber) } : { scriptId, url, lineNumber, columnNumber: asNumber(candidate.columnNumber) };
|
|
760
|
-
return [result];
|
|
982
|
+
const url = typeof entry["url"] === "string" ? entry["url"] : void 0;
|
|
983
|
+
return [url === void 0 ? location : { ...location, url }];
|
|
761
984
|
});
|
|
762
985
|
}
|
|
763
|
-
function
|
|
764
|
-
if (
|
|
765
|
-
return
|
|
986
|
+
function remoteCompleteness(subtype) {
|
|
987
|
+
if (subtype === "proxy") {
|
|
988
|
+
return "unavailable";
|
|
766
989
|
}
|
|
767
|
-
return
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
990
|
+
return subtype !== void 0 && INTERNAL_SLOT_SUBTYPES.has(subtype) ? "truncated" : void 0;
|
|
991
|
+
}
|
|
992
|
+
function optionalOwnField(key, value) {
|
|
993
|
+
return Object.hasOwn(value, key) ? { [key]: value[key] } : {};
|
|
994
|
+
}
|
|
995
|
+
function toRemoteObject(value) {
|
|
996
|
+
if (!isRecord(value)) {
|
|
997
|
+
return void 0;
|
|
998
|
+
}
|
|
999
|
+
const type = nonEmptyString(value["type"]);
|
|
1000
|
+
if (type === void 0) {
|
|
1001
|
+
return void 0;
|
|
1002
|
+
}
|
|
1003
|
+
const subtype = nonEmptyString(value["subtype"]);
|
|
1004
|
+
const completeness = remoteCompleteness(subtype);
|
|
1005
|
+
return {
|
|
1006
|
+
type,
|
|
1007
|
+
...subtype === void 0 ? {} : { subtype },
|
|
1008
|
+
...optionalTextField("className", value["className"]),
|
|
1009
|
+
...completeness === void 0 ? {} : { completeness },
|
|
1010
|
+
...optionalOwnField("value", value),
|
|
1011
|
+
...optionalTextField("unserializableValue", value["unserializableValue"]),
|
|
1012
|
+
...optionalTextField("description", value["description"]),
|
|
1013
|
+
...optionalOwnField("deepSerializedValue", value),
|
|
1014
|
+
...optionalTextField("objectId", value["objectId"]),
|
|
1015
|
+
...optionalOwnField("preview", value),
|
|
1016
|
+
...optionalOwnField("customPreview", value)
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
1019
|
+
function optionalTextField(key, value) {
|
|
1020
|
+
return typeof value === "string" ? { [key]: value } : {};
|
|
1021
|
+
}
|
|
1022
|
+
function toScope(value) {
|
|
1023
|
+
if (!isRecord(value)) {
|
|
1024
|
+
return void 0;
|
|
1025
|
+
}
|
|
1026
|
+
const type = nonEmptyString(value["type"]);
|
|
1027
|
+
if (type === void 0) {
|
|
1028
|
+
return void 0;
|
|
1029
|
+
}
|
|
1030
|
+
const object = toRemoteObject(value["object"]);
|
|
1031
|
+
const name = nonEmptyString(value["name"]);
|
|
1032
|
+
const startLocation = toScriptLocation(value["startLocation"]);
|
|
1033
|
+
const endLocation = toScriptLocation(value["endLocation"]);
|
|
1034
|
+
return {
|
|
1035
|
+
type,
|
|
1036
|
+
...name === void 0 ? {} : { name },
|
|
1037
|
+
...object === void 0 ? {} : { object },
|
|
1038
|
+
...object?.objectId === void 0 ? {} : { objectId: object.objectId },
|
|
1039
|
+
...startLocation === void 0 ? {} : { startLocation },
|
|
1040
|
+
...endLocation === void 0 ? {} : { endLocation }
|
|
1041
|
+
};
|
|
1042
|
+
}
|
|
1043
|
+
function toScopeChain(value) {
|
|
1044
|
+
return Array.isArray(value) ? value.flatMap((entry) => {
|
|
1045
|
+
const scope = toScope(entry);
|
|
1046
|
+
return scope === void 0 ? [] : [scope];
|
|
1047
|
+
}) : [];
|
|
781
1048
|
}
|
|
782
1049
|
function resolveCallFrameUrl(frame, scripts) {
|
|
783
|
-
const direct = nonEmptyString(frame
|
|
1050
|
+
const direct = nonEmptyString(frame["url"]);
|
|
784
1051
|
if (direct !== void 0) {
|
|
785
1052
|
return direct;
|
|
786
1053
|
}
|
|
787
|
-
const scriptId =
|
|
788
|
-
|
|
1054
|
+
const scriptId = toScriptLocation(frame["location"])?.scriptId;
|
|
1055
|
+
return scriptId === void 0 ? void 0 : nonEmptyString(scripts?.get(scriptId)?.url);
|
|
1056
|
+
}
|
|
1057
|
+
function toCallFrameMetadata(candidate, location, scripts) {
|
|
1058
|
+
const functionLocation = toScriptLocation(candidate["functionLocation"]);
|
|
1059
|
+
const thisObject = toRemoteObject(candidate["this"]);
|
|
1060
|
+
const returnValue = toRemoteObject(candidate["returnValue"]);
|
|
1061
|
+
const url = resolveCallFrameUrl(candidate, scripts);
|
|
1062
|
+
return {
|
|
1063
|
+
...location === void 0 ? {} : { scriptId: location.scriptId },
|
|
1064
|
+
...functionLocation === void 0 ? {} : { functionLocation },
|
|
1065
|
+
...url === void 0 ? {} : { url },
|
|
1066
|
+
...thisObject === void 0 ? {} : { thisObject },
|
|
1067
|
+
...returnValue === void 0 ? {} : { returnValue }
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
function toCallFrame(value, scripts) {
|
|
1071
|
+
if (!isRecord(value)) {
|
|
1072
|
+
return void 0;
|
|
1073
|
+
}
|
|
1074
|
+
const callFrameId = nonEmptyString(value["callFrameId"]);
|
|
1075
|
+
if (callFrameId === void 0) {
|
|
789
1076
|
return void 0;
|
|
790
1077
|
}
|
|
791
|
-
|
|
1078
|
+
const location = toScriptLocation(value["location"]);
|
|
1079
|
+
return {
|
|
1080
|
+
callFrameId,
|
|
1081
|
+
functionName: asString(value["functionName"]),
|
|
1082
|
+
...toCallFrameMetadata(value, location, scripts),
|
|
1083
|
+
lineNumber: location?.lineNumber ?? 0,
|
|
1084
|
+
columnNumber: location?.columnNumber ?? 0,
|
|
1085
|
+
scopeChain: toScopeChain(value["scopeChain"])
|
|
1086
|
+
};
|
|
792
1087
|
}
|
|
793
1088
|
function toCallFrames(value, scripts) {
|
|
794
|
-
|
|
795
|
-
|
|
1089
|
+
return Array.isArray(value) ? value.flatMap((entry) => {
|
|
1090
|
+
const frame = toCallFrame(entry, scripts);
|
|
1091
|
+
return frame === void 0 ? [] : [frame];
|
|
1092
|
+
}) : [];
|
|
1093
|
+
}
|
|
1094
|
+
function toStackTraceId(value) {
|
|
1095
|
+
if (!isRecord(value)) {
|
|
1096
|
+
return void 0;
|
|
796
1097
|
}
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
1098
|
+
const id = nonEmptyString(value["id"]);
|
|
1099
|
+
if (id === void 0) {
|
|
1100
|
+
return void 0;
|
|
1101
|
+
}
|
|
1102
|
+
const debuggerId = nonEmptyString(value["debuggerId"]);
|
|
1103
|
+
return debuggerId === void 0 ? { id } : { id, debuggerId };
|
|
1104
|
+
}
|
|
1105
|
+
function toStackTraceFrame(value) {
|
|
1106
|
+
if (!isRecord(value)) {
|
|
1107
|
+
return void 0;
|
|
1108
|
+
}
|
|
1109
|
+
const scriptId = nonEmptyString(value["scriptId"]);
|
|
1110
|
+
if (scriptId === void 0) {
|
|
1111
|
+
return void 0;
|
|
1112
|
+
}
|
|
1113
|
+
return {
|
|
1114
|
+
functionName: asString(value["functionName"]),
|
|
1115
|
+
scriptId,
|
|
1116
|
+
url: asString(value["url"]),
|
|
1117
|
+
lineNumber: asNumber(value["lineNumber"]),
|
|
1118
|
+
columnNumber: asNumber(value["columnNumber"])
|
|
1119
|
+
};
|
|
1120
|
+
}
|
|
1121
|
+
function toStackTrace(value) {
|
|
1122
|
+
if (!isRecord(value) || !Array.isArray(value["callFrames"])) {
|
|
1123
|
+
return void 0;
|
|
1124
|
+
}
|
|
1125
|
+
const callFrames = value["callFrames"].flatMap((entry) => {
|
|
1126
|
+
const frame = toStackTraceFrame(entry);
|
|
1127
|
+
return frame === void 0 ? [] : [frame];
|
|
815
1128
|
});
|
|
1129
|
+
const description = nonEmptyString(value["description"]);
|
|
1130
|
+
const parent = toStackTrace(value["parent"]);
|
|
1131
|
+
const parentId = toStackTraceId(value["parentId"]);
|
|
1132
|
+
return {
|
|
1133
|
+
callFrames,
|
|
1134
|
+
...description === void 0 ? {} : { description },
|
|
1135
|
+
...parent === void 0 ? {} : { parent },
|
|
1136
|
+
...parentId === void 0 ? {} : { parentId }
|
|
1137
|
+
};
|
|
816
1138
|
}
|
|
817
|
-
function toPauseEvent(
|
|
818
|
-
const
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
1139
|
+
function toPauseEvent(value, receivedAtMs, scripts) {
|
|
1140
|
+
const params = isRecord(value) ? value : {};
|
|
1141
|
+
const asyncStackTrace = toStackTrace(params["asyncStackTrace"]);
|
|
1142
|
+
const asyncStackTraceId = toStackTraceId(params["asyncStackTraceId"]);
|
|
1143
|
+
const asyncCallStackTraceId = toStackTraceId(params["asyncCallStackTraceId"]);
|
|
1144
|
+
return {
|
|
1145
|
+
reason: asString(params["reason"]),
|
|
1146
|
+
hitBreakpoints: Array.isArray(params["hitBreakpoints"]) ? params["hitBreakpoints"].filter((id) => typeof id === "string") : [],
|
|
1147
|
+
callFrames: toCallFrames(params["callFrames"], scripts),
|
|
1148
|
+
receivedAtMs,
|
|
1149
|
+
...params["data"] === void 0 ? {} : { data: params["data"] },
|
|
1150
|
+
...asyncStackTrace === void 0 ? {} : { asyncStackTrace },
|
|
1151
|
+
...asyncStackTraceId === void 0 ? {} : { asyncStackTraceId },
|
|
1152
|
+
...asyncCallStackTraceId === void 0 ? {} : { asyncCallStackTraceId }
|
|
1153
|
+
};
|
|
1154
|
+
}
|
|
1155
|
+
function toScriptInfo(value) {
|
|
1156
|
+
if (!isRecord(value)) {
|
|
1157
|
+
return void 0;
|
|
1158
|
+
}
|
|
1159
|
+
const scriptId = nonEmptyString(value["scriptId"]);
|
|
1160
|
+
if (scriptId === void 0) {
|
|
1161
|
+
return void 0;
|
|
1162
|
+
}
|
|
1163
|
+
const stackTrace = toStackTrace(value["stackTrace"]);
|
|
1164
|
+
return {
|
|
1165
|
+
scriptId,
|
|
1166
|
+
url: asString(value["url"]),
|
|
1167
|
+
...optionalNumericField("startLine", value["startLine"]),
|
|
1168
|
+
...optionalNumericField("startColumn", value["startColumn"]),
|
|
1169
|
+
...optionalNumericField("endLine", value["endLine"]),
|
|
1170
|
+
...optionalNumericField("endColumn", value["endColumn"]),
|
|
1171
|
+
...optionalNumericField("executionContextId", value["executionContextId"]),
|
|
1172
|
+
...optionalTextField("hash", value["hash"]),
|
|
1173
|
+
...optionalTextField("buildId", value["buildId"]),
|
|
1174
|
+
...value["executionContextAuxData"] === void 0 ? {} : { executionContextAuxData: value["executionContextAuxData"] },
|
|
1175
|
+
...optionalTextField("sourceMapURL", value["sourceMapURL"]),
|
|
1176
|
+
...optionalBooleanField("hasSourceURL", value["hasSourceURL"]),
|
|
1177
|
+
...optionalBooleanField("isModule", value["isModule"]),
|
|
1178
|
+
...optionalNumericField("length", value["length"]),
|
|
1179
|
+
...stackTrace === void 0 ? {} : { stackTrace }
|
|
823
1180
|
};
|
|
824
|
-
|
|
1181
|
+
}
|
|
1182
|
+
function optionalNumericField(key, value) {
|
|
1183
|
+
const number = optionalNumber(value);
|
|
1184
|
+
return number === void 0 ? {} : { [key]: number };
|
|
1185
|
+
}
|
|
1186
|
+
function optionalBooleanField(key, value) {
|
|
1187
|
+
const boolean = optionalBoolean(value);
|
|
1188
|
+
return boolean === void 0 ? {} : { [key]: boolean };
|
|
825
1189
|
}
|
|
826
1190
|
function topFrameLocation(pause) {
|
|
827
1191
|
const top = pause.callFrames[0];
|
|
@@ -843,6 +1207,101 @@ function pauseDetail(pause) {
|
|
|
843
1207
|
var DEFAULT_CONNECT_TIMEOUT_MS = 5e3;
|
|
844
1208
|
var DEFAULT_HOST = "127.0.0.1";
|
|
845
1209
|
var PAUSE_BUFFER_LIMIT = 32;
|
|
1210
|
+
var NodeWorkerDiscovery = class {
|
|
1211
|
+
constructor(client) {
|
|
1212
|
+
this.client = client;
|
|
1213
|
+
this.detachListeners = [
|
|
1214
|
+
client.on("NodeWorker.attachedToWorker", (raw) => {
|
|
1215
|
+
const worker = toInspectorWorkerTarget(raw);
|
|
1216
|
+
if (worker !== void 0) {
|
|
1217
|
+
this.workers.set(worker.sessionId, worker);
|
|
1218
|
+
}
|
|
1219
|
+
}),
|
|
1220
|
+
client.on("NodeWorker.detachedFromWorker", (raw) => {
|
|
1221
|
+
const sessionId = readField(raw, "sessionId");
|
|
1222
|
+
if (typeof sessionId === "string") {
|
|
1223
|
+
this.workers.delete(sessionId);
|
|
1224
|
+
}
|
|
1225
|
+
})
|
|
1226
|
+
];
|
|
1227
|
+
}
|
|
1228
|
+
client;
|
|
1229
|
+
workers = /* @__PURE__ */ new Map();
|
|
1230
|
+
detachListeners;
|
|
1231
|
+
supported = false;
|
|
1232
|
+
disposed = false;
|
|
1233
|
+
async enable() {
|
|
1234
|
+
try {
|
|
1235
|
+
await this.client.send("NodeWorker.enable", { waitForDebuggerOnStart: false });
|
|
1236
|
+
this.supported = true;
|
|
1237
|
+
} catch (error) {
|
|
1238
|
+
if (!isUnsupportedNodeWorkerDomain(error)) {
|
|
1239
|
+
throw error;
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
list() {
|
|
1244
|
+
return [...this.workers.values()].sort(compareWorkers);
|
|
1245
|
+
}
|
|
1246
|
+
async dispose() {
|
|
1247
|
+
if (this.disposed) {
|
|
1248
|
+
return;
|
|
1249
|
+
}
|
|
1250
|
+
this.disposed = true;
|
|
1251
|
+
if (this.supported && !this.client.isClosed) {
|
|
1252
|
+
try {
|
|
1253
|
+
await this.client.send("NodeWorker.disable");
|
|
1254
|
+
} catch {
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
for (const detach of this.detachListeners) {
|
|
1258
|
+
detach();
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
};
|
|
1262
|
+
function isUnsupportedNodeWorkerDomain(error) {
|
|
1263
|
+
if (!(error instanceof CfInspectorError) || error.code !== "CDP_REQUEST_FAILED") {
|
|
1264
|
+
return false;
|
|
1265
|
+
}
|
|
1266
|
+
return error.detail?.includes('"code":-32601') === true;
|
|
1267
|
+
}
|
|
1268
|
+
function compareWorkers(left, right) {
|
|
1269
|
+
const leftId = Number.parseInt(left.workerId, 10);
|
|
1270
|
+
const rightId = Number.parseInt(right.workerId, 10);
|
|
1271
|
+
if (!Number.isNaN(leftId) && !Number.isNaN(rightId) && leftId !== rightId) {
|
|
1272
|
+
return leftId - rightId;
|
|
1273
|
+
}
|
|
1274
|
+
return left.workerId.localeCompare(right.workerId);
|
|
1275
|
+
}
|
|
1276
|
+
function toInspectorWorkerTarget(raw) {
|
|
1277
|
+
const sessionId = readField(raw, "sessionId");
|
|
1278
|
+
const info = readField(raw, "workerInfo");
|
|
1279
|
+
if (typeof sessionId !== "string" || !isUnknownRecord2(info)) {
|
|
1280
|
+
return void 0;
|
|
1281
|
+
}
|
|
1282
|
+
const workerId = asString(info["workerId"]);
|
|
1283
|
+
if (workerId.length === 0) {
|
|
1284
|
+
return void 0;
|
|
1285
|
+
}
|
|
1286
|
+
return {
|
|
1287
|
+
sessionId,
|
|
1288
|
+
workerId,
|
|
1289
|
+
type: asString(info["type"]),
|
|
1290
|
+
title: asString(info["title"]),
|
|
1291
|
+
url: asString(info["url"])
|
|
1292
|
+
};
|
|
1293
|
+
}
|
|
1294
|
+
function readField(value, name) {
|
|
1295
|
+
return isUnknownRecord2(value) ? value[name] : void 0;
|
|
1296
|
+
}
|
|
1297
|
+
function isUnknownRecord2(value) {
|
|
1298
|
+
return typeof value === "object" && value !== null;
|
|
1299
|
+
}
|
|
1300
|
+
async function startNodeWorkerDiscovery(client) {
|
|
1301
|
+
const discovery = new NodeWorkerDiscovery(client);
|
|
1302
|
+
await discovery.enable();
|
|
1303
|
+
return discovery;
|
|
1304
|
+
}
|
|
846
1305
|
async function connectInspector(options) {
|
|
847
1306
|
const host = options.host ?? DEFAULT_HOST;
|
|
848
1307
|
const connectTimeoutMs = options.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS;
|
|
@@ -852,50 +1311,123 @@ async function connectInspector(options) {
|
|
|
852
1311
|
if (!target) {
|
|
853
1312
|
throw new CfInspectorError(
|
|
854
1313
|
"INSPECTOR_DISCOVERY_FAILED",
|
|
855
|
-
`No inspector target at index ${targetIndex.toString()} on ${host}:${options.port.toString()} (available: ${targets.length.toString()})`
|
|
1314
|
+
`No inspector target at index ${targetIndex.toString()} on ${host}:${options.port.toString()} (available: ${targets.length.toString()})`
|
|
1315
|
+
);
|
|
1316
|
+
}
|
|
1317
|
+
const client = await CdpClient.connect({
|
|
1318
|
+
url: target.webSocketDebuggerUrl,
|
|
1319
|
+
connectTimeoutMs
|
|
1320
|
+
});
|
|
1321
|
+
let workerDiscovery;
|
|
1322
|
+
try {
|
|
1323
|
+
workerDiscovery = await startNodeWorkerDiscovery(client);
|
|
1324
|
+
if (options.workerIndex === void 0) {
|
|
1325
|
+
const session = await initSession(client, target);
|
|
1326
|
+
return withWorkerMetadata(session, workerDiscovery, targetIndex, targets.length);
|
|
1327
|
+
}
|
|
1328
|
+
return await initWorkerSession(
|
|
1329
|
+
client,
|
|
1330
|
+
workerDiscovery,
|
|
1331
|
+
options.workerIndex,
|
|
1332
|
+
targetIndex,
|
|
1333
|
+
targets.length
|
|
1334
|
+
);
|
|
1335
|
+
} catch (err) {
|
|
1336
|
+
await workerDiscovery?.dispose();
|
|
1337
|
+
client.dispose();
|
|
1338
|
+
throw err;
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
async function initWorkerSession(parent, discovery, workerIndex, targetIndex, targetCount) {
|
|
1342
|
+
const workers = discovery.list();
|
|
1343
|
+
if (!discovery.supported) {
|
|
1344
|
+
throw new CfInspectorError(
|
|
1345
|
+
"INSPECTOR_DISCOVERY_FAILED",
|
|
1346
|
+
"This runtime does not expose the NodeWorker CDP domain; --worker cannot be used. Run list-targets for available raw targets."
|
|
1347
|
+
);
|
|
1348
|
+
}
|
|
1349
|
+
const worker = workers[workerIndex];
|
|
1350
|
+
if (worker === void 0) {
|
|
1351
|
+
throw new CfInspectorError(
|
|
1352
|
+
"INSPECTOR_DISCOVERY_FAILED",
|
|
1353
|
+
`No NodeWorker sub-session at index ${workerIndex.toString()} (available: ${workers.length.toString()}). Ensure the worker is alive, then rerun list-targets.`
|
|
856
1354
|
);
|
|
857
1355
|
}
|
|
858
|
-
const client = await
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
1356
|
+
const client = await createNodeWorkerClient(parent, worker.sessionId);
|
|
1357
|
+
const session = await initSession(client, workerToInspectorTarget(worker));
|
|
1358
|
+
return withWorkerMetadata(session, discovery, targetIndex, targetCount, workerIndex, parent);
|
|
1359
|
+
}
|
|
1360
|
+
function withWorkerMetadata(session, discovery, targetIndex, targetCount, workerIndex, parent) {
|
|
1361
|
+
return {
|
|
1362
|
+
...session,
|
|
1363
|
+
targetIndex,
|
|
1364
|
+
targetCount,
|
|
1365
|
+
...workerIndex === void 0 ? {} : { workerIndex },
|
|
1366
|
+
workerTargets: discovery.list(),
|
|
1367
|
+
workerDiscoverySupported: discovery.supported,
|
|
1368
|
+
dispose: async () => {
|
|
1369
|
+
await session.dispose();
|
|
1370
|
+
await discovery.dispose();
|
|
1371
|
+
parent?.dispose();
|
|
1372
|
+
}
|
|
1373
|
+
};
|
|
1374
|
+
}
|
|
1375
|
+
function workerToInspectorTarget(worker) {
|
|
1376
|
+
return {
|
|
1377
|
+
description: "Node worker sub-session",
|
|
1378
|
+
id: worker.workerId,
|
|
1379
|
+
title: worker.title,
|
|
1380
|
+
type: worker.type,
|
|
1381
|
+
url: worker.url,
|
|
1382
|
+
webSocketDebuggerUrl: `node-worker://${worker.sessionId}`
|
|
1383
|
+
};
|
|
1384
|
+
}
|
|
1385
|
+
async function discoverNodeWorkerTargets(target, connectTimeoutMs = DEFAULT_CONNECT_TIMEOUT_MS) {
|
|
1386
|
+
const client = await CdpClient.connect({ url: target.webSocketDebuggerUrl, connectTimeoutMs });
|
|
1387
|
+
let discovery;
|
|
862
1388
|
try {
|
|
863
|
-
|
|
864
|
-
|
|
1389
|
+
discovery = await startNodeWorkerDiscovery(client);
|
|
1390
|
+
return { supported: discovery.supported, workers: discovery.list() };
|
|
1391
|
+
} finally {
|
|
1392
|
+
await discovery?.dispose();
|
|
865
1393
|
client.dispose();
|
|
866
|
-
throw err;
|
|
867
1394
|
}
|
|
868
1395
|
}
|
|
869
1396
|
async function initSession(client, target) {
|
|
870
1397
|
const scripts = /* @__PURE__ */ new Map();
|
|
871
|
-
client
|
|
872
|
-
const params = raw;
|
|
873
|
-
const scriptId = asString(params.scriptId);
|
|
874
|
-
const url = asString(params.url);
|
|
875
|
-
if (scriptId.length === 0) {
|
|
876
|
-
return;
|
|
877
|
-
}
|
|
878
|
-
scripts.set(scriptId, { scriptId, url });
|
|
879
|
-
});
|
|
1398
|
+
registerScriptTracking(client, scripts);
|
|
880
1399
|
const pauseBuffer = [];
|
|
881
1400
|
const pauseWaitGate = { active: false };
|
|
882
1401
|
const debuggerState = {};
|
|
1402
|
+
registerPauseTracking(client, scripts, pauseBuffer, pauseWaitGate, debuggerState);
|
|
1403
|
+
await client.send("Runtime.enable");
|
|
1404
|
+
await client.send("Debugger.enable");
|
|
1405
|
+
return createSession(client, target, scripts, pauseBuffer, pauseWaitGate, debuggerState);
|
|
1406
|
+
}
|
|
1407
|
+
function registerScriptTracking(client, scripts) {
|
|
1408
|
+
client.on("Debugger.scriptParsed", (raw) => {
|
|
1409
|
+
const script = toScriptInfo(raw);
|
|
1410
|
+
if (script !== void 0) {
|
|
1411
|
+
scripts.set(script.scriptId, script);
|
|
1412
|
+
}
|
|
1413
|
+
});
|
|
1414
|
+
}
|
|
1415
|
+
function registerPauseTracking(client, scripts, pauseBuffer, pauseWaitGate, debuggerState) {
|
|
883
1416
|
client.on("Debugger.paused", (raw) => {
|
|
884
1417
|
if (pauseWaitGate.active) {
|
|
885
1418
|
return;
|
|
886
1419
|
}
|
|
887
|
-
const
|
|
888
|
-
const event = toPauseEvent(params, performance.now(), scripts);
|
|
1420
|
+
const event = toPauseEvent(raw, performance2.now(), scripts);
|
|
889
1421
|
if (pauseBuffer.length >= PAUSE_BUFFER_LIMIT) {
|
|
890
1422
|
pauseBuffer.shift();
|
|
891
1423
|
}
|
|
892
1424
|
pauseBuffer.push(event);
|
|
893
1425
|
});
|
|
894
1426
|
client.on("Debugger.resumed", () => {
|
|
895
|
-
debuggerState.lastResumedAtMs =
|
|
1427
|
+
debuggerState.lastResumedAtMs = performance2.now();
|
|
896
1428
|
});
|
|
897
|
-
|
|
898
|
-
|
|
1429
|
+
}
|
|
1430
|
+
function createSession(client, target, scripts, pauseBuffer, pauseWaitGate, debuggerState) {
|
|
899
1431
|
return {
|
|
900
1432
|
client,
|
|
901
1433
|
target,
|
|
@@ -921,6 +1453,223 @@ var DEFAULT_BREAKPOINT_TIMEOUT_SEC = 30;
|
|
|
921
1453
|
var DEFAULT_CF_TIMEOUT_SEC = 180;
|
|
922
1454
|
var DEFAULT_EXCEPTION_TIMEOUT_SEC = 30;
|
|
923
1455
|
|
|
1456
|
+
// src/cli/warnings.ts
|
|
1457
|
+
init_types();
|
|
1458
|
+
import process2 from "process";
|
|
1459
|
+
|
|
1460
|
+
// src/cli/captureParser.ts
|
|
1461
|
+
function parseCaptureList(raw) {
|
|
1462
|
+
if (raw === void 0 || raw.trim().length === 0) {
|
|
1463
|
+
return [];
|
|
1464
|
+
}
|
|
1465
|
+
return splitCaptureExpressions(raw);
|
|
1466
|
+
}
|
|
1467
|
+
function isQuoteChar(value) {
|
|
1468
|
+
return value === "'" || value === '"' || value === "`";
|
|
1469
|
+
}
|
|
1470
|
+
function consumeQuotedChar(state, char) {
|
|
1471
|
+
if (state.quote === void 0) {
|
|
1472
|
+
return false;
|
|
1473
|
+
}
|
|
1474
|
+
if (state.escaped) {
|
|
1475
|
+
state.escaped = false;
|
|
1476
|
+
return true;
|
|
1477
|
+
}
|
|
1478
|
+
if (char === "\\") {
|
|
1479
|
+
state.escaped = true;
|
|
1480
|
+
return true;
|
|
1481
|
+
}
|
|
1482
|
+
if (char === state.quote) {
|
|
1483
|
+
state.quote = void 0;
|
|
1484
|
+
}
|
|
1485
|
+
return true;
|
|
1486
|
+
}
|
|
1487
|
+
function stripQuotedText(expression) {
|
|
1488
|
+
const state = { quote: void 0, escaped: false };
|
|
1489
|
+
let stripped = "";
|
|
1490
|
+
for (const char of expression) {
|
|
1491
|
+
if (consumeQuotedChar(state, char)) {
|
|
1492
|
+
stripped += " ";
|
|
1493
|
+
continue;
|
|
1494
|
+
}
|
|
1495
|
+
if (isQuoteChar(char)) {
|
|
1496
|
+
state.quote = char;
|
|
1497
|
+
stripped += " ";
|
|
1498
|
+
continue;
|
|
1499
|
+
}
|
|
1500
|
+
stripped += char;
|
|
1501
|
+
}
|
|
1502
|
+
return stripped;
|
|
1503
|
+
}
|
|
1504
|
+
function looksLikeMutation(expression) {
|
|
1505
|
+
const stripped = stripQuotedText(expression);
|
|
1506
|
+
const hasUpdate = /(?:\+\+|--)/u.test(stripped);
|
|
1507
|
+
const hasAssignment = /(?:\*\*=|&&=|\|\|=|\?\?=|[+\-*/%&|^]=|(?:^|[^=!<>])=(?!=|>))/u.test(stripped);
|
|
1508
|
+
const hasDelete = /\bdelete\b/u.test(stripped);
|
|
1509
|
+
const hasMutatingMethod = /\.\s*(?:push|pop|shift|unshift|splice|sort|reverse|fill|copyWithin|set|add|delete|clear)\s*\(/u.test(stripped);
|
|
1510
|
+
const hasObjectMutation = /\bObject\s*\.\s*(?:assign|defineProperty|defineProperties)\s*\(/u.test(stripped);
|
|
1511
|
+
return hasUpdate || hasAssignment || hasDelete || hasMutatingMethod || hasObjectMutation;
|
|
1512
|
+
}
|
|
1513
|
+
function updateCaptureDepth(state, char) {
|
|
1514
|
+
if (char === "(") {
|
|
1515
|
+
state.parenDepth += 1;
|
|
1516
|
+
} else if (char === ")") {
|
|
1517
|
+
state.parenDepth = Math.max(0, state.parenDepth - 1);
|
|
1518
|
+
} else if (char === "[") {
|
|
1519
|
+
state.bracketDepth += 1;
|
|
1520
|
+
} else if (char === "]") {
|
|
1521
|
+
state.bracketDepth = Math.max(0, state.bracketDepth - 1);
|
|
1522
|
+
} else if (char === "{") {
|
|
1523
|
+
state.braceDepth += 1;
|
|
1524
|
+
} else if (char === "}") {
|
|
1525
|
+
state.braceDepth = Math.max(0, state.braceDepth - 1);
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
function isTopLevel(state) {
|
|
1529
|
+
return state.parenDepth === 0 && state.bracketDepth === 0 && state.braceDepth === 0;
|
|
1530
|
+
}
|
|
1531
|
+
function appendCapturePiece(raw, state, end) {
|
|
1532
|
+
const piece = raw.slice(state.start, end).trim();
|
|
1533
|
+
if (piece.length > 0) {
|
|
1534
|
+
state.pieces.push(piece);
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
function splitCaptureExpressions(raw) {
|
|
1538
|
+
const state = {
|
|
1539
|
+
escaped: false,
|
|
1540
|
+
parenDepth: 0,
|
|
1541
|
+
bracketDepth: 0,
|
|
1542
|
+
braceDepth: 0,
|
|
1543
|
+
quote: void 0,
|
|
1544
|
+
start: 0,
|
|
1545
|
+
pieces: []
|
|
1546
|
+
};
|
|
1547
|
+
for (let idx = 0; idx < raw.length; idx += 1) {
|
|
1548
|
+
const char = raw.charAt(idx);
|
|
1549
|
+
if (consumeQuotedChar(state, char)) {
|
|
1550
|
+
continue;
|
|
1551
|
+
}
|
|
1552
|
+
if (isQuoteChar(char)) {
|
|
1553
|
+
state.quote = char;
|
|
1554
|
+
continue;
|
|
1555
|
+
}
|
|
1556
|
+
updateCaptureDepth(state, char);
|
|
1557
|
+
if (char === "," && isTopLevel(state)) {
|
|
1558
|
+
appendCapturePiece(raw, state, idx);
|
|
1559
|
+
state.start = idx + 1;
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
appendCapturePiece(raw, state, raw.length);
|
|
1563
|
+
return state.pieces;
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1566
|
+
// src/cli/warnings.ts
|
|
1567
|
+
function warnOnCaptureMutationRisk(expressions, allowMutation) {
|
|
1568
|
+
const riskyCount = expressions.filter(looksLikeMutation).length;
|
|
1569
|
+
if (riskyCount === 0) {
|
|
1570
|
+
return;
|
|
1571
|
+
}
|
|
1572
|
+
const suffix = allowMutation ? "will run without the V8 side-effect guard because --allow-mutation was passed." : "will be checked by the V8 side-effect guard and blocked unless V8 proves them safe; pass --allow-mutation to run them unrestricted.";
|
|
1573
|
+
process2.stderr.write(
|
|
1574
|
+
`[cf-inspector] warning: ${riskyCount.toString()} capture ${riskyCount === 1 ? "expression looks" : "expressions look"} mutation-capable and ${suffix}
|
|
1575
|
+
`
|
|
1576
|
+
);
|
|
1577
|
+
}
|
|
1578
|
+
function enforceNativeConditionMutationPolicy(expression, allowMutation, context) {
|
|
1579
|
+
if (!looksLikeMutation(expression)) {
|
|
1580
|
+
return;
|
|
1581
|
+
}
|
|
1582
|
+
if (!allowMutation) {
|
|
1583
|
+
throw new CfInspectorError(
|
|
1584
|
+
"MUTATION_NOT_ALLOWED",
|
|
1585
|
+
`${context} looks mutation-capable. Native breakpoint conditions cannot be protected by V8's side-effect guard; pass --allow-mutation to arm it explicitly.`
|
|
1586
|
+
);
|
|
1587
|
+
}
|
|
1588
|
+
process2.stderr.write(
|
|
1589
|
+
`[cf-inspector] warning: ${context} looks mutation-capable and will run as a native breakpoint condition; native conditions cannot be side-effect-gated.
|
|
1590
|
+
`
|
|
1591
|
+
);
|
|
1592
|
+
}
|
|
1593
|
+
function warnOnMutationRisk(expression, context) {
|
|
1594
|
+
if (!looksLikeMutation(expression)) {
|
|
1595
|
+
return;
|
|
1596
|
+
}
|
|
1597
|
+
process2.stderr.write(
|
|
1598
|
+
`[cf-inspector] warning: ${context} looks mutation-capable and will execute against the live inspectee without a side-effect guard.
|
|
1599
|
+
`
|
|
1600
|
+
);
|
|
1601
|
+
}
|
|
1602
|
+
function warnOnUnboundBreakpoints(handles) {
|
|
1603
|
+
for (const handle of handles) {
|
|
1604
|
+
if (handle.resolvedLocations.length === 0) {
|
|
1605
|
+
const tsHint = handle.file.endsWith(".ts") ? " Hint: Source TS breakpoints may not bind. Try inspecting loaded scripts with list-scripts and target the compiled .js file instead." : "";
|
|
1606
|
+
process2.stderr.write(
|
|
1607
|
+
`[cf-inspector] warning: breakpoint ${handle.file}:${handle.line.toString()} did not bind to any loaded script. Check the path or pass --remote-root. Use 'list-scripts' to inspect what V8 currently has loaded.${tsHint}
|
|
1608
|
+
`
|
|
1609
|
+
);
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
function warnOnImplicitInspectorSelection(session, targetWasExplicit, workerWasExplicit) {
|
|
1614
|
+
const targetCount = session.targetCount ?? 1;
|
|
1615
|
+
const targetIndex = session.targetIndex ?? 0;
|
|
1616
|
+
if (!targetWasExplicit && targetCount > 1) {
|
|
1617
|
+
process2.stderr.write(
|
|
1618
|
+
`[cf-inspector] notice: attached to inspector target ${targetIndex.toString()} of ${targetCount.toString()}; pass --target <index> to pick another.
|
|
1619
|
+
`
|
|
1620
|
+
);
|
|
1621
|
+
}
|
|
1622
|
+
const workerCount = session.workerTargets?.length ?? 0;
|
|
1623
|
+
if (!workerWasExplicit && workerCount > 0) {
|
|
1624
|
+
process2.stderr.write(
|
|
1625
|
+
`[cf-inspector] notice: attached to the main isolate; ${workerCount.toString()} Node ${workerCount === 1 ? "worker is" : "workers are"} available. Run list-targets and pass --worker <index> to inspect one.
|
|
1626
|
+
`
|
|
1627
|
+
);
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
function warnOnBoundBreakpointWithoutHit(handles) {
|
|
1631
|
+
const boundCount = handles.reduce((count, handle) => {
|
|
1632
|
+
return count + handle.resolvedLocations.length;
|
|
1633
|
+
}, 0);
|
|
1634
|
+
if (boundCount === 0) {
|
|
1635
|
+
return;
|
|
1636
|
+
}
|
|
1637
|
+
process2.stderr.write(
|
|
1638
|
+
`[cf-inspector] warning: ${boundCount.toString()} breakpoint ${boundCount === 1 ? "location bound" : "locations bound"}, but no hit was observed. The code may be running in another worker isolate. Run list-targets and retry with --worker <index> for a NodeWorker sub-session or --target <index> for a raw target.
|
|
1639
|
+
`
|
|
1640
|
+
);
|
|
1641
|
+
}
|
|
1642
|
+
function roundDurationMs(durationMs) {
|
|
1643
|
+
return Math.round(durationMs * 1e3) / 1e3;
|
|
1644
|
+
}
|
|
1645
|
+
function warnOnUnmatchedPause(pause) {
|
|
1646
|
+
const reason = pause.reason.length > 0 ? pause.reason : "unknown";
|
|
1647
|
+
process2.stderr.write(
|
|
1648
|
+
`[cf-inspector] warning: target is paused by another debugger event (${reason} at ${formatPauseLocation(pause)}); waiting for it to resume...
|
|
1649
|
+
`
|
|
1650
|
+
);
|
|
1651
|
+
}
|
|
1652
|
+
function withPausedDuration(snapshot, pausedDurationMs) {
|
|
1653
|
+
const base = {
|
|
1654
|
+
reason: snapshot.reason,
|
|
1655
|
+
hitBreakpoints: snapshot.hitBreakpoints,
|
|
1656
|
+
capturedAt: snapshot.capturedAt,
|
|
1657
|
+
pausedDurationMs,
|
|
1658
|
+
captures: snapshot.captures
|
|
1659
|
+
};
|
|
1660
|
+
const withFrame = snapshot.topFrame === void 0 ? base : { ...base, topFrame: snapshot.topFrame };
|
|
1661
|
+
const withStack = snapshot.stack === void 0 ? withFrame : { ...withFrame, stack: snapshot.stack };
|
|
1662
|
+
return snapshot.exception === void 0 ? withStack : { ...withStack, exception: snapshot.exception };
|
|
1663
|
+
}
|
|
1664
|
+
function formatPauseLocation(pause) {
|
|
1665
|
+
const top = pause.callFrames[0];
|
|
1666
|
+
if (top === void 0) {
|
|
1667
|
+
return "(no call frame)";
|
|
1668
|
+
}
|
|
1669
|
+
const url = top.url !== void 0 && top.url.length > 0 ? top.url : "(unknown)";
|
|
1670
|
+
return `${url}:${(top.lineNumber + 1).toString()}:${(top.columnNumber + 1).toString()}`;
|
|
1671
|
+
}
|
|
1672
|
+
|
|
924
1673
|
// src/cli/target.ts
|
|
925
1674
|
var CF_TUNNEL_STATUS_MESSAGES = {
|
|
926
1675
|
starting: "Preparing the Cloud Foundry debugger...",
|
|
@@ -948,41 +1697,48 @@ function parsePositiveInt(raw, label) {
|
|
|
948
1697
|
}
|
|
949
1698
|
return value;
|
|
950
1699
|
}
|
|
951
|
-
|
|
1700
|
+
function resolveTarget(opts, options = {}) {
|
|
952
1701
|
const port = parsePositiveInt(opts.port, "--port");
|
|
953
1702
|
const targetIndex = parseTargetIndex(opts.target);
|
|
1703
|
+
const workerIndex = parseSelectionIndex(opts.worker, "--worker");
|
|
954
1704
|
if (port !== void 0) {
|
|
955
|
-
return {
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
1705
|
+
return {
|
|
1706
|
+
kind: "port",
|
|
1707
|
+
port,
|
|
1708
|
+
host: opts.host ?? "127.0.0.1",
|
|
1709
|
+
...selectionOptions(targetIndex, workerIndex)
|
|
1710
|
+
};
|
|
960
1711
|
}
|
|
961
|
-
const tunnelTimeoutSec = parseTunnelTimeout(opts, options);
|
|
962
1712
|
const region = optionalText(opts.region);
|
|
963
|
-
const apiEndpoint = optionalText(opts.apiEndpoint);
|
|
964
1713
|
const org = optionalText(opts.org);
|
|
965
1714
|
const space = optionalText(opts.space);
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
1715
|
+
const app = optionalText(opts.app);
|
|
1716
|
+
const missingFlags = [
|
|
1717
|
+
...region === void 0 ? ["--region"] : [],
|
|
1718
|
+
...org === void 0 ? ["--org"] : [],
|
|
1719
|
+
...space === void 0 ? ["--space"] : [],
|
|
1720
|
+
...app === void 0 ? ["--app"] : []
|
|
1721
|
+
];
|
|
1722
|
+
if (region === void 0 || org === void 0 || space === void 0 || app === void 0) {
|
|
971
1723
|
throw new CfInspectorError(
|
|
972
1724
|
"MISSING_TARGET",
|
|
973
|
-
|
|
1725
|
+
`Cloud Foundry targeting requires explicit selectors. Missing: ${missingFlags.join(", ")}. cf-inspector does not consult ambient \`cf target\` because it can silently change between runs.`
|
|
974
1726
|
);
|
|
975
1727
|
}
|
|
976
1728
|
return buildCfTarget(
|
|
977
|
-
region
|
|
978
|
-
|
|
979
|
-
org
|
|
980
|
-
space
|
|
1729
|
+
region,
|
|
1730
|
+
optionalText(opts.apiEndpoint),
|
|
1731
|
+
org,
|
|
1732
|
+
space,
|
|
981
1733
|
app,
|
|
982
|
-
|
|
983
|
-
targetIndex
|
|
1734
|
+
parseTunnelTimeout(opts, options),
|
|
1735
|
+
targetIndex,
|
|
1736
|
+
workerIndex
|
|
984
1737
|
);
|
|
985
1738
|
}
|
|
1739
|
+
async function resolveTargetWithCurrentCfTarget(opts, options = {}) {
|
|
1740
|
+
return await Promise.resolve(resolveTarget(opts, options));
|
|
1741
|
+
}
|
|
986
1742
|
function parseTunnelTimeout(opts, options) {
|
|
987
1743
|
if (options.useTimeoutForTunnel === false) {
|
|
988
1744
|
return DEFAULT_CF_TIMEOUT_SEC;
|
|
@@ -990,19 +1746,31 @@ function parseTunnelTimeout(opts, options) {
|
|
|
990
1746
|
return parsePositiveInt(opts.timeout, "--timeout") ?? DEFAULT_CF_TIMEOUT_SEC;
|
|
991
1747
|
}
|
|
992
1748
|
function parseTargetIndex(raw) {
|
|
1749
|
+
return parseSelectionIndex(raw, "--target");
|
|
1750
|
+
}
|
|
1751
|
+
function parseSelectionIndex(raw, label) {
|
|
993
1752
|
if (raw === void 0) {
|
|
994
1753
|
return void 0;
|
|
995
1754
|
}
|
|
996
1755
|
const value = Number.parseInt(raw, 10);
|
|
997
1756
|
if (Number.isNaN(value) || value < 0 || value.toString() !== raw.trim()) {
|
|
998
|
-
throw new CfInspectorError(
|
|
1757
|
+
throw new CfInspectorError(
|
|
1758
|
+
"INVALID_ARGUMENT",
|
|
1759
|
+
`Invalid ${label}: "${raw}" \u2014 expected a non-negative integer`
|
|
1760
|
+
);
|
|
999
1761
|
}
|
|
1000
1762
|
return value;
|
|
1001
1763
|
}
|
|
1002
1764
|
function targetIndexOption(targetIndex) {
|
|
1003
1765
|
return targetIndex === void 0 ? {} : { targetIndex };
|
|
1004
1766
|
}
|
|
1005
|
-
function
|
|
1767
|
+
function selectionOptions(targetIndex, workerIndex) {
|
|
1768
|
+
return {
|
|
1769
|
+
...targetIndexOption(targetIndex),
|
|
1770
|
+
...workerIndex === void 0 ? {} : { workerIndex }
|
|
1771
|
+
};
|
|
1772
|
+
}
|
|
1773
|
+
function buildCfTarget(region, apiEndpoint, org, space, app, tunnelTimeoutSec, targetIndex, workerIndex) {
|
|
1006
1774
|
return {
|
|
1007
1775
|
kind: "cf",
|
|
1008
1776
|
region,
|
|
@@ -1011,44 +1779,15 @@ function buildCfTarget(region, apiEndpoint, org, space, app, tunnelTimeoutSec, t
|
|
|
1011
1779
|
space,
|
|
1012
1780
|
app,
|
|
1013
1781
|
tunnelTimeoutMs: tunnelTimeoutSec * 1e3,
|
|
1014
|
-
...
|
|
1782
|
+
...selectionOptions(targetIndex, workerIndex)
|
|
1015
1783
|
};
|
|
1016
1784
|
}
|
|
1017
1785
|
function optionalText(value) {
|
|
1018
1786
|
const trimmed = value?.trim();
|
|
1019
1787
|
return trimmed === void 0 || trimmed.length === 0 ? void 0 : trimmed;
|
|
1020
1788
|
}
|
|
1021
|
-
function
|
|
1022
|
-
const
|
|
1023
|
-
return command === void 0 ? void 0 : { command };
|
|
1024
|
-
}
|
|
1025
|
-
async function readCurrentTarget() {
|
|
1026
|
-
try {
|
|
1027
|
-
return await readCurrentCfTarget(currentCfOptions());
|
|
1028
|
-
} catch (error) {
|
|
1029
|
-
throw new CfInspectorError(
|
|
1030
|
-
"MISSING_TARGET",
|
|
1031
|
-
"No current CF target found. Run `cf target -o <org> -s <space>` or pass --region/--org/--space.",
|
|
1032
|
-
error instanceof Error ? error.message : String(error)
|
|
1033
|
-
);
|
|
1034
|
-
}
|
|
1035
|
-
}
|
|
1036
|
-
function currentRegion(current) {
|
|
1037
|
-
try {
|
|
1038
|
-
return requireCurrentCfRegion(current, "Pass --region explicitly.");
|
|
1039
|
-
} catch (error) {
|
|
1040
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1041
|
-
throw new CfInspectorError("MISSING_TARGET", message);
|
|
1042
|
-
}
|
|
1043
|
-
}
|
|
1044
|
-
function missingTargetError() {
|
|
1045
|
-
return new CfInspectorError(
|
|
1046
|
-
"MISSING_TARGET",
|
|
1047
|
-
"Provide either --port (and optionally --host), an --app with current cf target, or all of --region, --org, --space, --app."
|
|
1048
|
-
);
|
|
1049
|
-
}
|
|
1050
|
-
async function withSession(target, fn, reportProgress) {
|
|
1051
|
-
const tunnel = await openTarget(target, reportProgress);
|
|
1789
|
+
async function withSession(target, fn, reportProgress, signal) {
|
|
1790
|
+
const tunnel = await openTarget(target, reportProgress, signal);
|
|
1052
1791
|
let session;
|
|
1053
1792
|
try {
|
|
1054
1793
|
reportProgress?.(
|
|
@@ -1057,8 +1796,13 @@ async function withSession(target, fn, reportProgress) {
|
|
|
1057
1796
|
session = await connectInspector({
|
|
1058
1797
|
port: tunnel.port,
|
|
1059
1798
|
host: tunnel.host,
|
|
1060
|
-
...
|
|
1799
|
+
...selectionOptions(target.targetIndex, target.workerIndex)
|
|
1061
1800
|
});
|
|
1801
|
+
warnOnImplicitInspectorSelection(
|
|
1802
|
+
session,
|
|
1803
|
+
target.targetIndex !== void 0,
|
|
1804
|
+
target.workerIndex !== void 0
|
|
1805
|
+
);
|
|
1062
1806
|
reportProgress?.("Inspector session is ready.");
|
|
1063
1807
|
return await fn(session, tunnel.port);
|
|
1064
1808
|
} finally {
|
|
@@ -1070,7 +1814,7 @@ async function withSession(target, fn, reportProgress) {
|
|
|
1070
1814
|
await tunnel.dispose();
|
|
1071
1815
|
}
|
|
1072
1816
|
}
|
|
1073
|
-
async function openTarget(target, reportProgress) {
|
|
1817
|
+
async function openTarget(target, reportProgress, signal) {
|
|
1074
1818
|
if (target.kind === "port") {
|
|
1075
1819
|
return {
|
|
1076
1820
|
port: target.port,
|
|
@@ -1086,6 +1830,7 @@ async function openTarget(target, reportProgress) {
|
|
|
1086
1830
|
space: target.space,
|
|
1087
1831
|
app: target.app,
|
|
1088
1832
|
tunnelReadyTimeoutMs: target.tunnelTimeoutMs,
|
|
1833
|
+
...signal === void 0 ? {} : { signal },
|
|
1089
1834
|
...reportProgress === void 0 ? {} : {
|
|
1090
1835
|
onStatus: (status, message) => {
|
|
1091
1836
|
reportProgress(message ?? formatCfTunnelStatus(status));
|
|
@@ -1133,15 +1878,31 @@ async function resume(session) {
|
|
|
1133
1878
|
async function setPauseOnExceptions(session, state) {
|
|
1134
1879
|
await session.client.send("Debugger.setPauseOnExceptions", { state });
|
|
1135
1880
|
}
|
|
1136
|
-
async function evaluateOnFrame(session, callFrameId, expression) {
|
|
1881
|
+
async function evaluateOnFrame(session, callFrameId, expression, options = {}) {
|
|
1137
1882
|
return await session.client.send("Debugger.evaluateOnCallFrame", {
|
|
1138
1883
|
callFrameId,
|
|
1139
1884
|
expression,
|
|
1140
1885
|
returnByValue: false,
|
|
1141
1886
|
generatePreview: true,
|
|
1142
|
-
silent: true
|
|
1887
|
+
silent: true,
|
|
1888
|
+
...options.throwOnSideEffect === void 0 ? {} : { throwOnSideEffect: options.throwOnSideEffect },
|
|
1889
|
+
...options.objectGroup === void 0 ? {} : { objectGroup: options.objectGroup }
|
|
1143
1890
|
});
|
|
1144
1891
|
}
|
|
1892
|
+
function isSideEffectRefusal(result) {
|
|
1893
|
+
const classNames = [
|
|
1894
|
+
result.result?.className,
|
|
1895
|
+
result.exceptionDetails?.exception?.className
|
|
1896
|
+
];
|
|
1897
|
+
const descriptions = [
|
|
1898
|
+
result.result?.description,
|
|
1899
|
+
result.exceptionDetails?.exception?.description
|
|
1900
|
+
];
|
|
1901
|
+
const isEvalError = classNames.includes("EvalError");
|
|
1902
|
+
return isEvalError && descriptions.some(
|
|
1903
|
+
(description) => typeof description === "string" && description.toLowerCase().includes("possible side-effect in debug-evaluate")
|
|
1904
|
+
);
|
|
1905
|
+
}
|
|
1145
1906
|
async function evaluateGlobal(session, expression) {
|
|
1146
1907
|
return await session.client.send("Runtime.evaluate", {
|
|
1147
1908
|
expression,
|
|
@@ -1194,6 +1955,7 @@ async function getProperties(session, objectId) {
|
|
|
1194
1955
|
|
|
1195
1956
|
// src/cli/commands/eval.ts
|
|
1196
1957
|
async function handleEval(opts) {
|
|
1958
|
+
warnOnMutationRisk(opts.expr, "eval --expr");
|
|
1197
1959
|
const target = await resolveTargetWithCurrentCfTarget(opts);
|
|
1198
1960
|
const result = await withSession(target, async (session) => {
|
|
1199
1961
|
return await evaluateGlobal(session, opts.expr);
|
|
@@ -1235,8 +1997,8 @@ function writeHumanEvalResult(result) {
|
|
|
1235
1997
|
}
|
|
1236
1998
|
|
|
1237
1999
|
// src/cli/commands/exception.ts
|
|
1238
|
-
import { performance as
|
|
1239
|
-
import
|
|
2000
|
+
import { performance as performance4 } from "perf_hooks";
|
|
2001
|
+
import process5 from "process";
|
|
1240
2002
|
|
|
1241
2003
|
// src/pathMapper.ts
|
|
1242
2004
|
init_types();
|
|
@@ -1448,7 +2210,7 @@ async function removeBreakpoint(session, breakpointId) {
|
|
|
1448
2210
|
|
|
1449
2211
|
// src/inspector/pause.ts
|
|
1450
2212
|
init_types();
|
|
1451
|
-
import { performance as
|
|
2213
|
+
import { performance as performance3 } from "perf_hooks";
|
|
1452
2214
|
function pauseMatches(pause, breakpointIds, pauseReasons) {
|
|
1453
2215
|
if (pauseReasons !== void 0 && pauseReasons.length > 0) {
|
|
1454
2216
|
return pauseReasons.includes(pause.reason);
|
|
@@ -1459,7 +2221,12 @@ function pauseMatches(pause, breakpointIds, pauseReasons) {
|
|
|
1459
2221
|
return pause.hitBreakpoints.some((id) => breakpointIds.includes(id));
|
|
1460
2222
|
}
|
|
1461
2223
|
function remainingUntil(deadlineMs) {
|
|
1462
|
-
return Math.max(0, deadlineMs -
|
|
2224
|
+
return Math.max(0, deadlineMs - performance3.now());
|
|
2225
|
+
}
|
|
2226
|
+
function throwIfAborted(signal) {
|
|
2227
|
+
if (signal?.aborted === true) {
|
|
2228
|
+
throw new CfInspectorError("ABORTED", "Aborted while waiting for Debugger.paused");
|
|
2229
|
+
}
|
|
1463
2230
|
}
|
|
1464
2231
|
function hasResumedSincePause(session, pause) {
|
|
1465
2232
|
const pauseAt = pause.receivedAtMs;
|
|
@@ -1479,20 +2246,23 @@ function throwUnrelatedPauseTimeout(pause, timeoutMs) {
|
|
|
1479
2246
|
pauseDetail(pause)
|
|
1480
2247
|
);
|
|
1481
2248
|
}
|
|
1482
|
-
async function waitForUnmatchedPauseToResume(session, pause, deadlineMs,
|
|
2249
|
+
async function waitForUnmatchedPauseToResume(session, pause, deadlineMs, options) {
|
|
1483
2250
|
if (hasResumedSincePause(session, pause)) {
|
|
1484
2251
|
return;
|
|
1485
2252
|
}
|
|
1486
2253
|
const remainingMs = remainingUntil(deadlineMs);
|
|
1487
2254
|
if (remainingMs <= 0) {
|
|
1488
|
-
throwUnrelatedPauseTimeout(pause, timeoutMs);
|
|
2255
|
+
throwUnrelatedPauseTimeout(pause, options.timeoutMs);
|
|
1489
2256
|
}
|
|
1490
2257
|
try {
|
|
1491
|
-
await session.client.waitFor("Debugger.resumed", {
|
|
1492
|
-
|
|
2258
|
+
await session.client.waitFor("Debugger.resumed", {
|
|
2259
|
+
timeoutMs: remainingMs,
|
|
2260
|
+
...options.signal === void 0 ? {} : { signal: options.signal }
|
|
2261
|
+
});
|
|
2262
|
+
session.debuggerState.lastResumedAtMs = performance3.now();
|
|
1493
2263
|
} catch (err) {
|
|
1494
2264
|
if (err instanceof CfInspectorError && err.code === "BREAKPOINT_NOT_HIT") {
|
|
1495
|
-
throwUnrelatedPauseTimeout(pause, timeoutMs);
|
|
2265
|
+
throwUnrelatedPauseTimeout(pause, options.timeoutMs);
|
|
1496
2266
|
}
|
|
1497
2267
|
throw err;
|
|
1498
2268
|
}
|
|
@@ -1509,13 +2279,16 @@ async function handleUnmatchedPause(session, pause, options, deadlineMs) {
|
|
|
1509
2279
|
return;
|
|
1510
2280
|
}
|
|
1511
2281
|
options.onUnmatchedPause?.(pause);
|
|
1512
|
-
await waitForUnmatchedPauseToResume(session, pause, deadlineMs, options
|
|
2282
|
+
await waitForUnmatchedPauseToResume(session, pause, deadlineMs, options);
|
|
1513
2283
|
}
|
|
1514
2284
|
async function waitForPause(session, options) {
|
|
1515
|
-
|
|
2285
|
+
throwIfAborted(options.signal);
|
|
2286
|
+
const deadlineMs = performance3.now() + options.timeoutMs;
|
|
1516
2287
|
const buffer = session.pauseBuffer;
|
|
1517
2288
|
while (buffer.length > 0 || remainingUntil(deadlineMs) > 0) {
|
|
2289
|
+
throwIfAborted(options.signal);
|
|
1518
2290
|
while (buffer.length > 0) {
|
|
2291
|
+
throwIfAborted(options.signal);
|
|
1519
2292
|
const buffered = buffer.shift();
|
|
1520
2293
|
if (buffered === void 0) {
|
|
1521
2294
|
continue;
|
|
@@ -1544,20 +2317,25 @@ async function waitForLivePause(session, options, deadlineMs) {
|
|
|
1544
2317
|
try {
|
|
1545
2318
|
params = await session.client.waitFor("Debugger.paused", {
|
|
1546
2319
|
timeoutMs: remainingMs,
|
|
2320
|
+
...options.signal === void 0 ? {} : { signal: options.signal },
|
|
1547
2321
|
predicate: () => {
|
|
1548
|
-
receivedAtMs =
|
|
2322
|
+
receivedAtMs = performance3.now();
|
|
1549
2323
|
return true;
|
|
1550
2324
|
}
|
|
1551
2325
|
});
|
|
1552
2326
|
} finally {
|
|
1553
2327
|
session.pauseWaitGate.active = false;
|
|
1554
2328
|
}
|
|
1555
|
-
return toPauseEvent(params, receivedAtMs ??
|
|
2329
|
+
return toPauseEvent(params, receivedAtMs ?? performance3.now(), session.scripts);
|
|
1556
2330
|
}
|
|
1557
2331
|
|
|
2332
|
+
// src/snapshot/evaluation.ts
|
|
2333
|
+
init_types();
|
|
2334
|
+
|
|
1558
2335
|
// src/snapshot/values.ts
|
|
1559
2336
|
init_types();
|
|
1560
|
-
var DEFAULT_MAX_VALUE_LENGTH =
|
|
2337
|
+
var DEFAULT_MAX_VALUE_LENGTH = 131072;
|
|
2338
|
+
var DEFAULT_STREAM_MAX_VALUE_LENGTH = 4096;
|
|
1561
2339
|
function isPrimitive(value) {
|
|
1562
2340
|
const t = typeof value;
|
|
1563
2341
|
return t === "string" || t === "number" || t === "boolean" || t === "bigint" || t === "symbol";
|
|
@@ -1585,9 +2363,16 @@ function resolveMaxValueLength(value) {
|
|
|
1585
2363
|
}
|
|
1586
2364
|
function limitValueLength(raw, maxValueLength = DEFAULT_MAX_VALUE_LENGTH) {
|
|
1587
2365
|
if (raw.length <= maxValueLength) {
|
|
1588
|
-
return raw;
|
|
2366
|
+
return { text: raw, truncated: false };
|
|
1589
2367
|
}
|
|
1590
|
-
return
|
|
2368
|
+
return {
|
|
2369
|
+
text: raw.slice(0, maxValueLength),
|
|
2370
|
+
truncated: true,
|
|
2371
|
+
originalLength: raw.length
|
|
2372
|
+
};
|
|
2373
|
+
}
|
|
2374
|
+
function textTruncationFields(limited) {
|
|
2375
|
+
return limited.truncated ? { truncated: true, originalLength: limited.originalLength } : {};
|
|
1591
2376
|
}
|
|
1592
2377
|
function parseQuotedString(value) {
|
|
1593
2378
|
try {
|
|
@@ -1672,7 +2457,12 @@ function toStructuredValue(variable) {
|
|
|
1672
2457
|
// src/snapshot/evaluation.ts
|
|
1673
2458
|
function evalResultToCaptured(expression, result, maxValueLength = DEFAULT_MAX_VALUE_LENGTH) {
|
|
1674
2459
|
if (result.exceptionDetails !== void 0) {
|
|
1675
|
-
|
|
2460
|
+
const limited = readEvalError(result, maxValueLength);
|
|
2461
|
+
return {
|
|
2462
|
+
expression,
|
|
2463
|
+
error: limited.text,
|
|
2464
|
+
...textTruncationFields(limited)
|
|
2465
|
+
};
|
|
1676
2466
|
}
|
|
1677
2467
|
const inner = result.result;
|
|
1678
2468
|
if (!inner) {
|
|
@@ -1680,8 +2470,12 @@ function evalResultToCaptured(expression, result, maxValueLength = DEFAULT_MAX_V
|
|
|
1680
2470
|
}
|
|
1681
2471
|
const type = typeof inner.type === "string" ? inner.type : void 0;
|
|
1682
2472
|
const buildCaptured = (rendered) => {
|
|
1683
|
-
const
|
|
1684
|
-
const base = {
|
|
2473
|
+
const limited = limitValueLength(rendered, maxValueLength);
|
|
2474
|
+
const base = {
|
|
2475
|
+
expression,
|
|
2476
|
+
value: limited.text,
|
|
2477
|
+
...textTruncationFields(limited)
|
|
2478
|
+
};
|
|
1685
2479
|
return type === void 0 ? base : { ...base, type };
|
|
1686
2480
|
};
|
|
1687
2481
|
if (type === "string" && typeof inner.value === "string") {
|
|
@@ -1698,6 +2492,18 @@ function evalResultToCaptured(expression, result, maxValueLength = DEFAULT_MAX_V
|
|
|
1698
2492
|
}
|
|
1699
2493
|
return buildCaptured("undefined");
|
|
1700
2494
|
}
|
|
2495
|
+
function sideEffectRefusalToCaptured(expression) {
|
|
2496
|
+
const error = new CfInspectorError(
|
|
2497
|
+
"MUTATION_NOT_ALLOWED",
|
|
2498
|
+
`V8 blocked the capture expression "${expression}" because it may have side effects. Pass --allow-mutation to run it explicitly.`
|
|
2499
|
+
);
|
|
2500
|
+
return {
|
|
2501
|
+
expression,
|
|
2502
|
+
error: `${error.code}: ${error.message}`,
|
|
2503
|
+
mutationRisk: true,
|
|
2504
|
+
blocked: true
|
|
2505
|
+
};
|
|
2506
|
+
}
|
|
1701
2507
|
function readEvalError(result, maxValueLength) {
|
|
1702
2508
|
const text = typeof result.exceptionDetails?.exception?.description === "string" ? result.exceptionDetails.exception.description : typeof result.exceptionDetails?.text === "string" ? result.exceptionDetails.text : "evaluation failed";
|
|
1703
2509
|
return limitValueLength(text, maxValueLength);
|
|
@@ -1755,56 +2561,88 @@ async function captureProperties(session, objectId, limit, depth, maxValueLength
|
|
|
1755
2561
|
return await captureProperty(session, prop, depth, maxValueLength);
|
|
1756
2562
|
})
|
|
1757
2563
|
);
|
|
1758
|
-
|
|
2564
|
+
const omittedCount = Math.max(properties.length - limited.length, 0);
|
|
2565
|
+
return omittedCount === 0 ? { variables } : { variables, omittedCount };
|
|
1759
2566
|
}
|
|
1760
2567
|
async function captureProperty(session, prop, depth, maxValueLength) {
|
|
1761
2568
|
const name = typeof prop.name === "string" ? prop.name : "?";
|
|
1762
2569
|
const described = describeProperty(prop);
|
|
1763
|
-
const
|
|
1764
|
-
|
|
1765
|
-
|
|
2570
|
+
const capturedChildren = await capturePropertyChildren(
|
|
2571
|
+
session,
|
|
2572
|
+
described,
|
|
2573
|
+
depth,
|
|
2574
|
+
maxValueLength
|
|
2575
|
+
);
|
|
2576
|
+
const limited = limitValueLength(described.value, maxValueLength);
|
|
2577
|
+
const base = {
|
|
2578
|
+
name,
|
|
2579
|
+
value: limited.text,
|
|
2580
|
+
...textTruncationFields(limited)
|
|
2581
|
+
};
|
|
1766
2582
|
const withType = described.type === void 0 ? base : { ...base, type: described.type };
|
|
1767
|
-
|
|
2583
|
+
const children = capturedChildren?.variables;
|
|
2584
|
+
const withChildren = children === void 0 || children.length === 0 ? withType : { ...withType, children };
|
|
2585
|
+
const omittedCount = capturedChildren?.omittedCount ?? 0;
|
|
2586
|
+
return omittedCount === 0 ? withChildren : { ...withChildren, truncated: true, omittedCount };
|
|
1768
2587
|
}
|
|
1769
2588
|
async function capturePropertyChildren(session, described, depth, maxValueLength) {
|
|
1770
|
-
if (
|
|
2589
|
+
if (described.objectId === void 0 || !isExpandable(described.type)) {
|
|
1771
2590
|
return void 0;
|
|
1772
2591
|
}
|
|
2592
|
+
if (depth <= 0) {
|
|
2593
|
+
return await countDepthOmissions(session, described.objectId);
|
|
2594
|
+
}
|
|
1773
2595
|
try {
|
|
1774
|
-
|
|
2596
|
+
return await captureProperties(
|
|
1775
2597
|
session,
|
|
1776
2598
|
described.objectId,
|
|
1777
2599
|
MAX_CHILD_VARIABLES,
|
|
1778
2600
|
depth - 1,
|
|
1779
2601
|
maxValueLength
|
|
1780
2602
|
);
|
|
1781
|
-
return nested.length > 0 ? nested : void 0;
|
|
1782
2603
|
} catch {
|
|
1783
2604
|
return void 0;
|
|
1784
2605
|
}
|
|
1785
2606
|
}
|
|
2607
|
+
async function countDepthOmissions(session, objectId) {
|
|
2608
|
+
try {
|
|
2609
|
+
const properties = await getProperties(session, objectId);
|
|
2610
|
+
return properties.length === 0 ? void 0 : { variables: [], omittedCount: properties.length };
|
|
2611
|
+
} catch {
|
|
2612
|
+
return void 0;
|
|
2613
|
+
}
|
|
2614
|
+
}
|
|
2615
|
+
function countPropertyOmissions(captured) {
|
|
2616
|
+
return (captured.omittedCount ?? 0) + captured.variables.reduce((total, variable) => {
|
|
2617
|
+
const childOmissions = variable.children === void 0 ? 0 : countPropertyOmissions({ variables: variable.children });
|
|
2618
|
+
return total + (variable.omittedCount ?? 0) + childOmissions;
|
|
2619
|
+
}, 0);
|
|
2620
|
+
}
|
|
1786
2621
|
|
|
1787
2622
|
// src/snapshot/exception.ts
|
|
1788
2623
|
function asString2(value) {
|
|
1789
2624
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
1790
2625
|
}
|
|
1791
|
-
async function materializeObject(session, objectId
|
|
2626
|
+
async function materializeObject(session, objectId) {
|
|
1792
2627
|
try {
|
|
1793
|
-
const
|
|
2628
|
+
const captured = await captureProperties(
|
|
1794
2629
|
session,
|
|
1795
2630
|
objectId,
|
|
1796
2631
|
MAX_SCOPE_VARIABLES,
|
|
1797
2632
|
MAX_VARIABLE_DEPTH,
|
|
1798
|
-
|
|
2633
|
+
Number.MAX_SAFE_INTEGER
|
|
1799
2634
|
);
|
|
1800
|
-
if (
|
|
2635
|
+
if (captured.variables.length === 0) {
|
|
1801
2636
|
return void 0;
|
|
1802
2637
|
}
|
|
1803
2638
|
const structured = {};
|
|
1804
|
-
for (const variable of
|
|
2639
|
+
for (const variable of captured.variables) {
|
|
1805
2640
|
structured[variable.name] = toStructuredValue(variable);
|
|
1806
2641
|
}
|
|
1807
|
-
return
|
|
2642
|
+
return {
|
|
2643
|
+
value: JSON.stringify(structured),
|
|
2644
|
+
omittedCount: countPropertyOmissions(captured)
|
|
2645
|
+
};
|
|
1808
2646
|
} catch {
|
|
1809
2647
|
return void 0;
|
|
1810
2648
|
}
|
|
@@ -1857,18 +2695,44 @@ async function captureException(session, pause, maxValueLength) {
|
|
|
1857
2695
|
return { error: "exception data has no objectId or value" };
|
|
1858
2696
|
}
|
|
1859
2697
|
const message = await readPropertyDescription(session, objectId, "message");
|
|
1860
|
-
const rendered = await materializeObject(session, objectId
|
|
2698
|
+
const rendered = await materializeObject(session, objectId);
|
|
1861
2699
|
if (rendered !== void 0) {
|
|
1862
|
-
|
|
1863
|
-
|
|
2700
|
+
return buildResult(
|
|
2701
|
+
type,
|
|
2702
|
+
message ?? description,
|
|
2703
|
+
rendered.value,
|
|
2704
|
+
maxValueLength,
|
|
2705
|
+
rendered.omittedCount
|
|
2706
|
+
);
|
|
1864
2707
|
}
|
|
1865
2708
|
return buildResult(type, description, description ?? "[exception]", maxValueLength);
|
|
1866
2709
|
}
|
|
1867
|
-
function buildResult(type, description, value, maxValueLength) {
|
|
1868
|
-
const
|
|
1869
|
-
const
|
|
2710
|
+
function buildResult(type, description, value, maxValueLength, omittedCount = 0) {
|
|
2711
|
+
const limitedValue = limitValueLength(value, maxValueLength);
|
|
2712
|
+
const limitedDescription = description === void 0 ? void 0 : limitValueLength(description, maxValueLength);
|
|
2713
|
+
const base = {
|
|
2714
|
+
value: limitedValue.text,
|
|
2715
|
+
...exceptionTruncationFields(limitedValue, limitedDescription)
|
|
2716
|
+
};
|
|
1870
2717
|
const withType = type === void 0 ? base : { ...base, type };
|
|
1871
|
-
|
|
2718
|
+
const withDescription = limitedDescription === void 0 ? withType : { ...withType, description: limitedDescription.text };
|
|
2719
|
+
return omittedCount === 0 ? withDescription : { ...withDescription, truncated: true, omittedCount };
|
|
2720
|
+
}
|
|
2721
|
+
function exceptionTruncationFields(value, description) {
|
|
2722
|
+
const valueLength = value.truncated ? value.originalLength : void 0;
|
|
2723
|
+
const descriptionLength = description?.truncated === true ? description.originalLength : void 0;
|
|
2724
|
+
const lengths = [valueLength, descriptionLength].filter(
|
|
2725
|
+
(length) => length !== void 0
|
|
2726
|
+
);
|
|
2727
|
+
if (lengths.length === 0) {
|
|
2728
|
+
return {};
|
|
2729
|
+
}
|
|
2730
|
+
return {
|
|
2731
|
+
truncated: true,
|
|
2732
|
+
originalLength: Math.max(...lengths),
|
|
2733
|
+
...valueLength === void 0 ? {} : { valueOriginalLength: valueLength },
|
|
2734
|
+
...descriptionLength === void 0 ? {} : { descriptionOriginalLength: descriptionLength }
|
|
2735
|
+
};
|
|
1872
2736
|
}
|
|
1873
2737
|
|
|
1874
2738
|
// src/snapshot/objects.ts
|
|
@@ -1883,20 +2747,23 @@ function objectIdFromEvalResult(result) {
|
|
|
1883
2747
|
}
|
|
1884
2748
|
return objectId;
|
|
1885
2749
|
}
|
|
1886
|
-
async function renderObjectCapture(session, objectId
|
|
2750
|
+
async function renderObjectCapture(session, objectId) {
|
|
1887
2751
|
try {
|
|
1888
|
-
const
|
|
2752
|
+
const captured = await captureProperties(
|
|
1889
2753
|
session,
|
|
1890
2754
|
objectId,
|
|
1891
2755
|
MAX_SCOPE_VARIABLES,
|
|
1892
2756
|
MAX_VARIABLE_DEPTH,
|
|
1893
|
-
|
|
2757
|
+
Number.MAX_SAFE_INTEGER
|
|
1894
2758
|
);
|
|
1895
2759
|
const structured = {};
|
|
1896
|
-
for (const variable of
|
|
2760
|
+
for (const variable of captured.variables) {
|
|
1897
2761
|
structured[variable.name] = toStructuredValue(variable);
|
|
1898
2762
|
}
|
|
1899
|
-
return
|
|
2763
|
+
return {
|
|
2764
|
+
value: JSON.stringify(structured),
|
|
2765
|
+
omittedCount: countPropertyOmissions(captured)
|
|
2766
|
+
};
|
|
1900
2767
|
} catch {
|
|
1901
2768
|
return void 0;
|
|
1902
2769
|
}
|
|
@@ -1918,16 +2785,22 @@ async function withSerializedObjectCapture(session, expression, evalResult, capt
|
|
|
1918
2785
|
if (objectId === void 0) {
|
|
1919
2786
|
return captured;
|
|
1920
2787
|
}
|
|
1921
|
-
const rendered = await renderObjectCapture(session, objectId
|
|
2788
|
+
const rendered = await renderObjectCapture(session, objectId);
|
|
1922
2789
|
if (rendered === void 0) {
|
|
1923
2790
|
return captured;
|
|
1924
2791
|
}
|
|
1925
|
-
const normalized = normalizeRenderedObjectCapture(rendered, captured.value);
|
|
2792
|
+
const normalized = normalizeRenderedObjectCapture(rendered.value, captured.value);
|
|
1926
2793
|
if (normalized === void 0) {
|
|
1927
2794
|
return captured;
|
|
1928
2795
|
}
|
|
1929
|
-
const
|
|
1930
|
-
|
|
2796
|
+
const limited = limitValueLength(normalized, maxValueLength);
|
|
2797
|
+
const base = {
|
|
2798
|
+
expression,
|
|
2799
|
+
value: limited.text,
|
|
2800
|
+
...textTruncationFields(limited),
|
|
2801
|
+
...captured.type === void 0 ? {} : { type: captured.type }
|
|
2802
|
+
};
|
|
2803
|
+
return rendered.omittedCount === 0 ? base : { ...base, truncated: true, omittedCount: rendered.omittedCount };
|
|
1931
2804
|
}
|
|
1932
2805
|
|
|
1933
2806
|
// src/snapshot/scopes.ts
|
|
@@ -1942,35 +2815,39 @@ var PRIORITY_BY_TYPE = {
|
|
|
1942
2815
|
module: 6,
|
|
1943
2816
|
script: 7
|
|
1944
2817
|
};
|
|
1945
|
-
function
|
|
2818
|
+
function rankedScopes(scopeChain) {
|
|
1946
2819
|
const eligible = scopeChain.filter((scope) => scope.objectId !== void 0 && scope.type !== "global");
|
|
1947
|
-
return [...eligible].sort((a, b) => priorityOf(a.type) - priorityOf(b.type))
|
|
2820
|
+
return [...eligible].sort((a, b) => priorityOf(a.type) - priorityOf(b.type));
|
|
1948
2821
|
}
|
|
1949
2822
|
function priorityOf(type) {
|
|
1950
2823
|
return PRIORITY_BY_TYPE[type] ?? Number.MAX_SAFE_INTEGER;
|
|
1951
2824
|
}
|
|
1952
2825
|
async function captureScopes(session, frame, maxValueLength) {
|
|
1953
|
-
const
|
|
1954
|
-
|
|
2826
|
+
const ranked = rankedScopes(frame.scopeChain);
|
|
2827
|
+
const scopes = ranked.slice(0, MAX_SCOPES);
|
|
2828
|
+
const capturedScopes = await Promise.all(
|
|
1955
2829
|
scopes.map(async (scope) => {
|
|
1956
2830
|
const objectId = scope.objectId;
|
|
1957
2831
|
if (objectId === void 0) {
|
|
1958
2832
|
return { type: scope.type, variables: [] };
|
|
1959
2833
|
}
|
|
1960
2834
|
try {
|
|
1961
|
-
const
|
|
2835
|
+
const captured = await captureProperties(
|
|
1962
2836
|
session,
|
|
1963
2837
|
objectId,
|
|
1964
2838
|
MAX_SCOPE_VARIABLES,
|
|
1965
2839
|
MAX_VARIABLE_DEPTH,
|
|
1966
2840
|
maxValueLength
|
|
1967
2841
|
);
|
|
1968
|
-
|
|
2842
|
+
const base = { type: scope.type, variables: captured.variables };
|
|
2843
|
+
return captured.omittedCount === void 0 ? base : { ...base, truncated: true, omittedCount: captured.omittedCount };
|
|
1969
2844
|
} catch {
|
|
1970
2845
|
return { type: scope.type, variables: [] };
|
|
1971
2846
|
}
|
|
1972
2847
|
})
|
|
1973
2848
|
);
|
|
2849
|
+
const omittedCount = Math.max(ranked.length - capturedScopes.length, 0);
|
|
2850
|
+
return omittedCount === 0 ? { scopes: capturedScopes } : { scopes: capturedScopes, omittedCount };
|
|
1974
2851
|
}
|
|
1975
2852
|
|
|
1976
2853
|
// src/snapshot/stack.ts
|
|
@@ -1990,23 +2867,48 @@ function buildBaseFrame(frame) {
|
|
|
1990
2867
|
};
|
|
1991
2868
|
return frame.url === void 0 ? base : { ...base, url: frame.url };
|
|
1992
2869
|
}
|
|
1993
|
-
async function captureFrameExpression(session, callFrameId, expression, maxValueLength) {
|
|
2870
|
+
async function captureFrameExpression(session, callFrameId, expression, maxValueLength, throwOnSideEffect) {
|
|
2871
|
+
const mutationRisk = throwOnSideEffect === false && looksLikeMutation(expression);
|
|
1994
2872
|
try {
|
|
1995
|
-
const result = await evaluateOnFrame(session, callFrameId, expression
|
|
2873
|
+
const result = await evaluateOnFrame(session, callFrameId, expression, {
|
|
2874
|
+
...throwOnSideEffect === void 0 ? {} : { throwOnSideEffect }
|
|
2875
|
+
});
|
|
2876
|
+
if (isSideEffectRefusal(result)) {
|
|
2877
|
+
return sideEffectRefusalToCaptured(expression);
|
|
2878
|
+
}
|
|
1996
2879
|
const captured = evalResultToCaptured(expression, result, maxValueLength);
|
|
1997
|
-
|
|
2880
|
+
const serialized = await withSerializedObjectCapture(
|
|
2881
|
+
session,
|
|
2882
|
+
expression,
|
|
2883
|
+
result,
|
|
2884
|
+
captured,
|
|
2885
|
+
maxValueLength
|
|
2886
|
+
);
|
|
2887
|
+
return mutationRisk ? { ...serialized, mutationRisk: true } : serialized;
|
|
1998
2888
|
} catch (err) {
|
|
1999
2889
|
const message = err instanceof Error ? err.message : String(err);
|
|
2000
|
-
|
|
2890
|
+
const limited = limitValueLength(message, maxValueLength);
|
|
2891
|
+
const captured = {
|
|
2892
|
+
expression,
|
|
2893
|
+
error: limited.text,
|
|
2894
|
+
...textTruncationFields(limited)
|
|
2895
|
+
};
|
|
2896
|
+
return mutationRisk ? { ...captured, mutationRisk: true } : captured;
|
|
2001
2897
|
}
|
|
2002
2898
|
}
|
|
2003
|
-
async function captureFrameExpressions(session, frame, expressions, maxValueLength) {
|
|
2899
|
+
async function captureFrameExpressions(session, frame, expressions, maxValueLength, throwOnSideEffect) {
|
|
2004
2900
|
if (expressions.length === 0) {
|
|
2005
2901
|
return [];
|
|
2006
2902
|
}
|
|
2007
2903
|
return await Promise.all(
|
|
2008
2904
|
expressions.map(
|
|
2009
|
-
(expression) => captureFrameExpression(
|
|
2905
|
+
(expression) => captureFrameExpression(
|
|
2906
|
+
session,
|
|
2907
|
+
frame.callFrameId,
|
|
2908
|
+
expression,
|
|
2909
|
+
maxValueLength,
|
|
2910
|
+
throwOnSideEffect
|
|
2911
|
+
)
|
|
2010
2912
|
)
|
|
2011
2913
|
);
|
|
2012
2914
|
}
|
|
@@ -2026,7 +2928,8 @@ async function walkStack(session, callFrames, options) {
|
|
|
2026
2928
|
session,
|
|
2027
2929
|
frame,
|
|
2028
2930
|
options.stackCaptures,
|
|
2029
|
-
options.maxValueLength
|
|
2931
|
+
options.maxValueLength,
|
|
2932
|
+
options.throwOnSideEffect
|
|
2030
2933
|
);
|
|
2031
2934
|
return { ...base, captures };
|
|
2032
2935
|
})
|
|
@@ -2048,14 +2951,25 @@ async function captureSnapshot(session, pause, options = {}) {
|
|
|
2048
2951
|
column: top.columnNumber + 1
|
|
2049
2952
|
};
|
|
2050
2953
|
if (options.includeScopes === true) {
|
|
2051
|
-
const
|
|
2052
|
-
topFrame = {
|
|
2954
|
+
const capturedScopes = await captureScopes(session, top, maxValueLength);
|
|
2955
|
+
topFrame = {
|
|
2956
|
+
...topFrame,
|
|
2957
|
+
scopes: capturedScopes.scopes,
|
|
2958
|
+
...capturedScopes.omittedCount === void 0 ? {} : { truncated: true, omittedCount: capturedScopes.omittedCount }
|
|
2959
|
+
};
|
|
2053
2960
|
}
|
|
2054
|
-
captures = await captureExpressions(
|
|
2961
|
+
captures = await captureExpressions(
|
|
2962
|
+
session,
|
|
2963
|
+
top.callFrameId,
|
|
2964
|
+
options.captures,
|
|
2965
|
+
maxValueLength,
|
|
2966
|
+
options.throwOnSideEffect
|
|
2967
|
+
);
|
|
2055
2968
|
stack = await walkStack(session, pause.callFrames, {
|
|
2056
2969
|
stackDepth: options.stackDepth ?? DEFAULT_STACK_DEPTH,
|
|
2057
2970
|
stackCaptures: options.stackCaptures ?? [],
|
|
2058
|
-
maxValueLength
|
|
2971
|
+
maxValueLength,
|
|
2972
|
+
...options.throwOnSideEffect === void 0 ? {} : { throwOnSideEffect: options.throwOnSideEffect }
|
|
2059
2973
|
});
|
|
2060
2974
|
}
|
|
2061
2975
|
const exception = await captureException(session, pause, maxValueLength);
|
|
@@ -2078,159 +2992,62 @@ function buildResult2(input) {
|
|
|
2078
2992
|
const withStack = input.stack.length > 0 ? { ...withFrame, stack: input.stack } : withFrame;
|
|
2079
2993
|
return input.exception === void 0 ? withStack : { ...withStack, exception: input.exception };
|
|
2080
2994
|
}
|
|
2081
|
-
async function captureExpressions(session, callFrameId, captures, maxValueLength) {
|
|
2995
|
+
async function captureExpressions(session, callFrameId, captures, maxValueLength, throwOnSideEffect) {
|
|
2082
2996
|
if (captures === void 0 || captures.length === 0) {
|
|
2083
2997
|
return [];
|
|
2084
2998
|
}
|
|
2085
2999
|
return await Promise.all(
|
|
2086
3000
|
captures.map(async (expression) => {
|
|
2087
|
-
return await captureExpression(
|
|
3001
|
+
return await captureExpression(
|
|
3002
|
+
session,
|
|
3003
|
+
callFrameId,
|
|
3004
|
+
expression,
|
|
3005
|
+
maxValueLength,
|
|
3006
|
+
throwOnSideEffect
|
|
3007
|
+
);
|
|
2088
3008
|
})
|
|
2089
3009
|
);
|
|
2090
3010
|
}
|
|
2091
|
-
async function captureExpression(session, callFrameId, expression, maxValueLength) {
|
|
3011
|
+
async function captureExpression(session, callFrameId, expression, maxValueLength, throwOnSideEffect) {
|
|
3012
|
+
const mutationRisk = throwOnSideEffect === false && looksLikeMutation(expression);
|
|
2092
3013
|
try {
|
|
2093
|
-
const result = await evaluateOnFrame(session, callFrameId, expression
|
|
3014
|
+
const result = await evaluateOnFrame(session, callFrameId, expression, {
|
|
3015
|
+
...throwOnSideEffect === void 0 ? {} : { throwOnSideEffect }
|
|
3016
|
+
});
|
|
3017
|
+
if (isSideEffectRefusal(result)) {
|
|
3018
|
+
return sideEffectRefusalToCaptured(expression);
|
|
3019
|
+
}
|
|
2094
3020
|
const captured = evalResultToCaptured(expression, result, maxValueLength);
|
|
2095
|
-
|
|
3021
|
+
const serialized = await withSerializedObjectCapture(
|
|
3022
|
+
session,
|
|
3023
|
+
expression,
|
|
3024
|
+
result,
|
|
3025
|
+
captured,
|
|
3026
|
+
maxValueLength
|
|
3027
|
+
);
|
|
3028
|
+
return mutationRisk ? { ...serialized, mutationRisk: true } : serialized;
|
|
2096
3029
|
} catch (err) {
|
|
2097
3030
|
const message = err instanceof Error ? err.message : String(err);
|
|
2098
|
-
|
|
3031
|
+
const limited = limitValueLength(message, maxValueLength);
|
|
3032
|
+
const captured = {
|
|
3033
|
+
expression,
|
|
3034
|
+
error: limited.text,
|
|
3035
|
+
...textTruncationFields(limited)
|
|
3036
|
+
};
|
|
3037
|
+
return mutationRisk ? { ...captured, mutationRisk: true } : captured;
|
|
2099
3038
|
}
|
|
2100
3039
|
}
|
|
2101
3040
|
|
|
2102
3041
|
// src/cli/commands/exception.ts
|
|
2103
3042
|
init_types();
|
|
2104
|
-
|
|
2105
|
-
// src/cli/captureParser.ts
|
|
2106
|
-
function parseCaptureList(raw) {
|
|
2107
|
-
if (raw === void 0 || raw.trim().length === 0) {
|
|
2108
|
-
return [];
|
|
2109
|
-
}
|
|
2110
|
-
return splitCaptureExpressions(raw);
|
|
2111
|
-
}
|
|
2112
|
-
function isQuoteChar(value) {
|
|
2113
|
-
return value === "'" || value === '"' || value === "`";
|
|
2114
|
-
}
|
|
2115
|
-
function consumeQuotedChar(state, char) {
|
|
2116
|
-
if (state.quote === void 0) {
|
|
2117
|
-
return false;
|
|
2118
|
-
}
|
|
2119
|
-
if (state.escaped) {
|
|
2120
|
-
state.escaped = false;
|
|
2121
|
-
return true;
|
|
2122
|
-
}
|
|
2123
|
-
if (char === "\\") {
|
|
2124
|
-
state.escaped = true;
|
|
2125
|
-
return true;
|
|
2126
|
-
}
|
|
2127
|
-
if (char === state.quote) {
|
|
2128
|
-
state.quote = void 0;
|
|
2129
|
-
}
|
|
2130
|
-
return true;
|
|
2131
|
-
}
|
|
2132
|
-
function updateCaptureDepth(state, char) {
|
|
2133
|
-
if (char === "(") {
|
|
2134
|
-
state.parenDepth += 1;
|
|
2135
|
-
} else if (char === ")") {
|
|
2136
|
-
state.parenDepth = Math.max(0, state.parenDepth - 1);
|
|
2137
|
-
} else if (char === "[") {
|
|
2138
|
-
state.bracketDepth += 1;
|
|
2139
|
-
} else if (char === "]") {
|
|
2140
|
-
state.bracketDepth = Math.max(0, state.bracketDepth - 1);
|
|
2141
|
-
} else if (char === "{") {
|
|
2142
|
-
state.braceDepth += 1;
|
|
2143
|
-
} else if (char === "}") {
|
|
2144
|
-
state.braceDepth = Math.max(0, state.braceDepth - 1);
|
|
2145
|
-
}
|
|
2146
|
-
}
|
|
2147
|
-
function isTopLevel(state) {
|
|
2148
|
-
return state.parenDepth === 0 && state.bracketDepth === 0 && state.braceDepth === 0;
|
|
2149
|
-
}
|
|
2150
|
-
function appendCapturePiece(raw, state, end) {
|
|
2151
|
-
const piece = raw.slice(state.start, end).trim();
|
|
2152
|
-
if (piece.length > 0) {
|
|
2153
|
-
state.pieces.push(piece);
|
|
2154
|
-
}
|
|
2155
|
-
}
|
|
2156
|
-
function splitCaptureExpressions(raw) {
|
|
2157
|
-
const state = {
|
|
2158
|
-
escaped: false,
|
|
2159
|
-
parenDepth: 0,
|
|
2160
|
-
bracketDepth: 0,
|
|
2161
|
-
braceDepth: 0,
|
|
2162
|
-
quote: void 0,
|
|
2163
|
-
start: 0,
|
|
2164
|
-
pieces: []
|
|
2165
|
-
};
|
|
2166
|
-
for (let idx = 0; idx < raw.length; idx += 1) {
|
|
2167
|
-
const char = raw.charAt(idx);
|
|
2168
|
-
if (consumeQuotedChar(state, char)) {
|
|
2169
|
-
continue;
|
|
2170
|
-
}
|
|
2171
|
-
if (isQuoteChar(char)) {
|
|
2172
|
-
state.quote = char;
|
|
2173
|
-
continue;
|
|
2174
|
-
}
|
|
2175
|
-
updateCaptureDepth(state, char);
|
|
2176
|
-
if (char === "," && isTopLevel(state)) {
|
|
2177
|
-
appendCapturePiece(raw, state, idx);
|
|
2178
|
-
state.start = idx + 1;
|
|
2179
|
-
}
|
|
2180
|
-
}
|
|
2181
|
-
appendCapturePiece(raw, state, raw.length);
|
|
2182
|
-
return state.pieces;
|
|
2183
|
-
}
|
|
2184
|
-
|
|
2185
|
-
// src/cli/warnings.ts
|
|
2186
|
-
import process5 from "process";
|
|
2187
|
-
function warnOnUnboundBreakpoints(handles) {
|
|
2188
|
-
for (const handle of handles) {
|
|
2189
|
-
if (handle.resolvedLocations.length === 0) {
|
|
2190
|
-
const tsHint = handle.file.endsWith(".ts") ? " Hint: Source TS breakpoints may not bind. Try inspecting loaded scripts with list-scripts and target the compiled .js file instead." : "";
|
|
2191
|
-
process5.stderr.write(
|
|
2192
|
-
`[cf-inspector] warning: breakpoint ${handle.file}:${handle.line.toString()} did not bind to any loaded script. Check the path or pass --remote-root. Use 'list-scripts' to inspect what V8 currently has loaded.${tsHint}
|
|
2193
|
-
`
|
|
2194
|
-
);
|
|
2195
|
-
}
|
|
2196
|
-
}
|
|
2197
|
-
}
|
|
2198
|
-
function roundDurationMs(durationMs) {
|
|
2199
|
-
return Math.round(durationMs * 1e3) / 1e3;
|
|
2200
|
-
}
|
|
2201
|
-
function warnOnUnmatchedPause(pause) {
|
|
2202
|
-
const reason = pause.reason.length > 0 ? pause.reason : "unknown";
|
|
2203
|
-
process5.stderr.write(
|
|
2204
|
-
`[cf-inspector] warning: target is paused by another debugger event (${reason} at ${formatPauseLocation(pause)}); waiting for it to resume...
|
|
2205
|
-
`
|
|
2206
|
-
);
|
|
2207
|
-
}
|
|
2208
|
-
function withPausedDuration(snapshot, pausedDurationMs) {
|
|
2209
|
-
const base = {
|
|
2210
|
-
reason: snapshot.reason,
|
|
2211
|
-
hitBreakpoints: snapshot.hitBreakpoints,
|
|
2212
|
-
capturedAt: snapshot.capturedAt,
|
|
2213
|
-
pausedDurationMs,
|
|
2214
|
-
captures: snapshot.captures
|
|
2215
|
-
};
|
|
2216
|
-
const withFrame = snapshot.topFrame === void 0 ? base : { ...base, topFrame: snapshot.topFrame };
|
|
2217
|
-
const withStack = snapshot.stack === void 0 ? withFrame : { ...withFrame, stack: snapshot.stack };
|
|
2218
|
-
return snapshot.exception === void 0 ? withStack : { ...withStack, exception: snapshot.exception };
|
|
2219
|
-
}
|
|
2220
|
-
function formatPauseLocation(pause) {
|
|
2221
|
-
const top = pause.callFrames[0];
|
|
2222
|
-
if (top === void 0) {
|
|
2223
|
-
return "(no call frame)";
|
|
2224
|
-
}
|
|
2225
|
-
const url = top.url !== void 0 && top.url.length > 0 ? top.url : "(unknown)";
|
|
2226
|
-
return `${url}:${(top.lineNumber + 1).toString()}:${(top.columnNumber + 1).toString()}`;
|
|
2227
|
-
}
|
|
2228
|
-
|
|
2229
|
-
// src/cli/commands/exception.ts
|
|
2230
3043
|
var VALID_PAUSE_TYPES = ["uncaught", "caught", "all"];
|
|
2231
3044
|
async function handleException(opts) {
|
|
2232
3045
|
const target = await resolveTargetWithCurrentCfTarget(opts, { useTimeoutForTunnel: false });
|
|
2233
3046
|
const prepared = prepareExceptionCommand(opts, target);
|
|
3047
|
+
warnOnCaptureMutationRisk(
|
|
3048
|
+
[...prepared.captures, ...prepared.stackCaptures],
|
|
3049
|
+
opts.allowMutation === true
|
|
3050
|
+
);
|
|
2234
3051
|
const result = await runExceptionCommand(prepared, opts);
|
|
2235
3052
|
if (opts.json) {
|
|
2236
3053
|
writeJson(result);
|
|
@@ -2247,7 +3064,7 @@ function prepareExceptionCommand(opts, target) {
|
|
|
2247
3064
|
);
|
|
2248
3065
|
}
|
|
2249
3066
|
const timeoutSec = parsePositiveInt(opts.timeout, "--timeout") ?? DEFAULT_EXCEPTION_TIMEOUT_SEC;
|
|
2250
|
-
const maxValueLength = parsePositiveInt(opts.maxValueLength, "--max-value-length");
|
|
3067
|
+
const maxValueLength = parsePositiveInt(opts.maxValueLength, "--max-value-length") ?? DEFAULT_MAX_VALUE_LENGTH;
|
|
2251
3068
|
const stackDepth = parsePositiveInt(opts.stackDepth, "--stack-depth");
|
|
2252
3069
|
return {
|
|
2253
3070
|
target,
|
|
@@ -2255,9 +3072,10 @@ function prepareExceptionCommand(opts, target) {
|
|
|
2255
3072
|
captures: parseCaptureList(opts.capture),
|
|
2256
3073
|
remoteRoot: parseRemoteRoot(opts.remoteRoot),
|
|
2257
3074
|
timeoutMs: timeoutSec * 1e3,
|
|
2258
|
-
|
|
3075
|
+
maxValueLength,
|
|
2259
3076
|
...stackDepth === void 0 ? {} : { stackDepth },
|
|
2260
|
-
stackCaptures: parseCaptureList(opts.stackCaptures)
|
|
3077
|
+
stackCaptures: parseCaptureList(opts.stackCaptures),
|
|
3078
|
+
throwOnSideEffect: opts.allowMutation !== true
|
|
2261
3079
|
};
|
|
2262
3080
|
}
|
|
2263
3081
|
async function runExceptionCommand(command, opts) {
|
|
@@ -2269,13 +3087,14 @@ async function runExceptionCommand(command, opts) {
|
|
|
2269
3087
|
pauseReasons: ["exception", "promiseRejection"],
|
|
2270
3088
|
unmatchedPausePolicy: "wait-for-resume"
|
|
2271
3089
|
});
|
|
2272
|
-
const pausedStartedAt = pause.receivedAtMs ??
|
|
3090
|
+
const pausedStartedAt = pause.receivedAtMs ?? performance4.now();
|
|
2273
3091
|
const snapshot = await captureSnapshot(session, pause, {
|
|
2274
3092
|
captures: command.captures,
|
|
2275
3093
|
includeScopes: opts.includeScopes === true,
|
|
2276
|
-
|
|
3094
|
+
maxValueLength: command.maxValueLength,
|
|
2277
3095
|
...command.stackDepth === void 0 ? {} : { stackDepth: command.stackDepth },
|
|
2278
|
-
stackCaptures: command.stackCaptures
|
|
3096
|
+
stackCaptures: command.stackCaptures,
|
|
3097
|
+
throwOnSideEffect: command.throwOnSideEffect
|
|
2279
3098
|
});
|
|
2280
3099
|
if (opts.keepPaused === true) {
|
|
2281
3100
|
return withPausedDuration(snapshot, null);
|
|
@@ -2289,9 +3108,9 @@ async function runExceptionCommand(command, opts) {
|
|
|
2289
3108
|
async function resumeAfterException(session, snapshot, pausedStartedAt) {
|
|
2290
3109
|
try {
|
|
2291
3110
|
await resume(session);
|
|
2292
|
-
return withPausedDuration(snapshot, roundDurationMs(
|
|
3111
|
+
return withPausedDuration(snapshot, roundDurationMs(performance4.now() - pausedStartedAt));
|
|
2293
3112
|
} catch {
|
|
2294
|
-
|
|
3113
|
+
process5.stderr.write(
|
|
2295
3114
|
"[cf-inspector] warning: Debugger.resume failed after exception capture; pausedDurationMs is unknown.\n"
|
|
2296
3115
|
);
|
|
2297
3116
|
return withPausedDuration(snapshot, null);
|
|
@@ -2305,7 +3124,7 @@ async function disablePauseOnExceptionsBestEffort(session) {
|
|
|
2305
3124
|
}
|
|
2306
3125
|
|
|
2307
3126
|
// src/cli/commands/listScripts.ts
|
|
2308
|
-
import
|
|
3127
|
+
import process6 from "process";
|
|
2309
3128
|
async function handleListScripts(opts) {
|
|
2310
3129
|
const target = await resolveTargetWithCurrentCfTarget(opts);
|
|
2311
3130
|
const filter = compileScriptUrlFilter(opts.filter);
|
|
@@ -2315,7 +3134,7 @@ async function handleListScripts(opts) {
|
|
|
2315
3134
|
return;
|
|
2316
3135
|
}
|
|
2317
3136
|
for (const script of scripts) {
|
|
2318
|
-
|
|
3137
|
+
process6.stdout.write(`${script.scriptId} ${script.url}
|
|
2319
3138
|
`);
|
|
2320
3139
|
}
|
|
2321
3140
|
}
|
|
@@ -2324,19 +3143,86 @@ async function handleListTargets(opts) {
|
|
|
2324
3143
|
const tunnel = await openTarget(target);
|
|
2325
3144
|
try {
|
|
2326
3145
|
const targets = await discoverInspectorTargets(tunnel.host, tunnel.port, 5e3);
|
|
2327
|
-
const indexedTargets =
|
|
3146
|
+
const indexedTargets = await buildListedTargets(targets);
|
|
3147
|
+
const workerCount = indexedTargets.reduce((count, targetEntry) => {
|
|
3148
|
+
return count + targetEntry.workers.length;
|
|
3149
|
+
}, 0);
|
|
3150
|
+
writeTargetCountSummary(indexedTargets.length, workerCount);
|
|
3151
|
+
warnOnMissingWorkers(indexedTargets.length, workerCount, indexedTargets);
|
|
2328
3152
|
if (opts.json) {
|
|
2329
3153
|
writeJson(indexedTargets);
|
|
2330
3154
|
return;
|
|
2331
3155
|
}
|
|
2332
|
-
|
|
2333
|
-
process7.stdout.write(`${entry.index.toString()} ${entry.type} ${entry.title} ${entry.url}
|
|
2334
|
-
`);
|
|
2335
|
-
}
|
|
3156
|
+
writeHumanTargets(indexedTargets);
|
|
2336
3157
|
} finally {
|
|
2337
3158
|
await tunnel.dispose();
|
|
2338
3159
|
}
|
|
2339
3160
|
}
|
|
3161
|
+
async function buildListedTargets(targets) {
|
|
3162
|
+
return await Promise.all(targets.map(async (target, index) => {
|
|
3163
|
+
try {
|
|
3164
|
+
const workerResult = await discoverNodeWorkerTargets(target);
|
|
3165
|
+
return buildListedTarget(target, index, workerResult.supported, workerResult.workers);
|
|
3166
|
+
} catch (error) {
|
|
3167
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3168
|
+
process6.stderr.write(
|
|
3169
|
+
`[cf-inspector] warning: worker discovery failed for raw target ${index.toString()}: ${message}
|
|
3170
|
+
`
|
|
3171
|
+
);
|
|
3172
|
+
return buildListedTarget(target, index, false, []);
|
|
3173
|
+
}
|
|
3174
|
+
}));
|
|
3175
|
+
}
|
|
3176
|
+
function buildListedTarget(target, index, workerDiscoverySupported, workers) {
|
|
3177
|
+
return {
|
|
3178
|
+
index,
|
|
3179
|
+
...target,
|
|
3180
|
+
likelyWorker: looksLikeWorkerTarget(target),
|
|
3181
|
+
workerDiscoverySupported,
|
|
3182
|
+
workers: workers.map((worker, workerIndex) => ({
|
|
3183
|
+
index: workerIndex,
|
|
3184
|
+
workerId: worker.workerId,
|
|
3185
|
+
type: worker.type,
|
|
3186
|
+
title: worker.title,
|
|
3187
|
+
url: worker.url
|
|
3188
|
+
}))
|
|
3189
|
+
};
|
|
3190
|
+
}
|
|
3191
|
+
function looksLikeWorkerTarget(target) {
|
|
3192
|
+
return `${target.type} ${target.title} ${target.url}`.toLowerCase().includes("worker");
|
|
3193
|
+
}
|
|
3194
|
+
function writeTargetCountSummary(targetCount, workerCount) {
|
|
3195
|
+
process6.stderr.write(
|
|
3196
|
+
`[cf-inspector] ${targetCount.toString()} raw inspector ${targetCount === 1 ? "target" : "targets"}; ${workerCount.toString()} ${workerCount === 1 ? "worker" : "workers"}.
|
|
3197
|
+
`
|
|
3198
|
+
);
|
|
3199
|
+
}
|
|
3200
|
+
function warnOnMissingWorkers(targetCount, workerCount, targets) {
|
|
3201
|
+
if (targetCount !== 1 || workerCount !== 0) {
|
|
3202
|
+
return;
|
|
3203
|
+
}
|
|
3204
|
+
const supported = targets[0]?.workerDiscoverySupported === true;
|
|
3205
|
+
const supportHint = supported ? "NodeWorker discovery is available, but no live worker attached." : "This runtime did not expose NodeWorker discovery.";
|
|
3206
|
+
process6.stderr.write(
|
|
3207
|
+
`[cf-inspector] warning: only the main inspector target is reachable. ${supportHint} If worker code is expected, ensure the worker is alive and rerun list-targets. A worker on a separate inspector port is not carried by a single Cloud Foundry tunnel.
|
|
3208
|
+
`
|
|
3209
|
+
);
|
|
3210
|
+
}
|
|
3211
|
+
function writeHumanTargets(targets) {
|
|
3212
|
+
for (const target of targets) {
|
|
3213
|
+
const workerLabel = target.likelyWorker ? " likely-worker" : "";
|
|
3214
|
+
process6.stdout.write(
|
|
3215
|
+
`${target.index.toString()} target ${target.type} ${target.title} ${target.url}${workerLabel}
|
|
3216
|
+
`
|
|
3217
|
+
);
|
|
3218
|
+
for (const worker of target.workers) {
|
|
3219
|
+
process6.stdout.write(
|
|
3220
|
+
` ${worker.index.toString()} worker ${worker.type} ${worker.title} ${worker.url}
|
|
3221
|
+
`
|
|
3222
|
+
);
|
|
3223
|
+
}
|
|
3224
|
+
}
|
|
3225
|
+
}
|
|
2340
3226
|
function compileScriptUrlFilter(pattern) {
|
|
2341
3227
|
if (pattern === void 0 || pattern.length === 0) {
|
|
2342
3228
|
return void 0;
|
|
@@ -2407,7 +3293,7 @@ function matchesFilterTokens(value, tokens) {
|
|
|
2407
3293
|
}
|
|
2408
3294
|
|
|
2409
3295
|
// src/cli/commands/log.ts
|
|
2410
|
-
import
|
|
3296
|
+
import process8 from "process";
|
|
2411
3297
|
|
|
2412
3298
|
// src/logpoint/stream.ts
|
|
2413
3299
|
init_types();
|
|
@@ -2493,7 +3379,7 @@ function readArg(arg, index) {
|
|
|
2493
3379
|
}
|
|
2494
3380
|
return index === 0 ? void 0 : "";
|
|
2495
3381
|
}
|
|
2496
|
-
function parseLogEvent(rawArgs, sentinel, location, timestamp) {
|
|
3382
|
+
function parseLogEvent(rawArgs, sentinel, location, timestamp, maxValueLength = DEFAULT_STREAM_MAX_VALUE_LENGTH) {
|
|
2497
3383
|
if (!Array.isArray(rawArgs) || rawArgs.length < 2) {
|
|
2498
3384
|
return void 0;
|
|
2499
3385
|
}
|
|
@@ -2505,21 +3391,37 @@ function parseLogEvent(rawArgs, sentinel, location, timestamp) {
|
|
|
2505
3391
|
const ts = new Date(typeof timestamp === "number" ? timestamp : Date.now()).toISOString();
|
|
2506
3392
|
const at = `${location.file}:${location.line.toString()}`;
|
|
2507
3393
|
if (payload.startsWith("!err:")) {
|
|
2508
|
-
|
|
3394
|
+
const limited = limitValueLength(payload.slice("!err:".length), maxValueLength);
|
|
3395
|
+
return {
|
|
3396
|
+
ts,
|
|
3397
|
+
at,
|
|
3398
|
+
error: limited.text,
|
|
3399
|
+
...textTruncationFields(limited)
|
|
3400
|
+
};
|
|
2509
3401
|
}
|
|
2510
|
-
return parsePayload(ts, at, payload);
|
|
3402
|
+
return parsePayload(ts, at, payload, maxValueLength);
|
|
2511
3403
|
}
|
|
2512
|
-
function parsePayload(ts, at, payload) {
|
|
3404
|
+
function parsePayload(ts, at, payload, maxValueLength) {
|
|
2513
3405
|
try {
|
|
2514
3406
|
const parsed = JSON.parse(payload);
|
|
2515
3407
|
if (typeof parsed === "string") {
|
|
2516
|
-
return
|
|
3408
|
+
return buildValueEvent(ts, at, parsed, maxValueLength);
|
|
2517
3409
|
}
|
|
2518
|
-
return
|
|
3410
|
+
return buildValueEvent(ts, at, JSON.stringify(parsed), maxValueLength);
|
|
2519
3411
|
} catch {
|
|
2520
|
-
return
|
|
3412
|
+
return buildValueEvent(ts, at, payload, maxValueLength, true);
|
|
2521
3413
|
}
|
|
2522
3414
|
}
|
|
3415
|
+
function buildValueEvent(ts, at, value, maxValueLength, includeRaw = false) {
|
|
3416
|
+
const limited = limitValueLength(value, maxValueLength);
|
|
3417
|
+
return {
|
|
3418
|
+
ts,
|
|
3419
|
+
at,
|
|
3420
|
+
value: limited.text,
|
|
3421
|
+
...includeRaw ? { raw: limited.text } : {},
|
|
3422
|
+
...textTruncationFields(limited)
|
|
3423
|
+
};
|
|
3424
|
+
}
|
|
2523
3425
|
|
|
2524
3426
|
// src/logpoint/stream.ts
|
|
2525
3427
|
function validateMaxEvents(maxEvents) {
|
|
@@ -2549,6 +3451,9 @@ function validateHitCount2(hitCount) {
|
|
|
2549
3451
|
async function streamLogpoint(session, options) {
|
|
2550
3452
|
const maxEvents = validateMaxEvents(options.maxEvents);
|
|
2551
3453
|
const hitCount = validateHitCount2(options.hitCount);
|
|
3454
|
+
const maxValueLength = resolveMaxValueLength(
|
|
3455
|
+
options.maxValueLength ?? DEFAULT_STREAM_MAX_VALUE_LENGTH
|
|
3456
|
+
);
|
|
2552
3457
|
const sentinel = generateSentinel();
|
|
2553
3458
|
const condition = buildLogpointCondition(sentinel, options.expression, {
|
|
2554
3459
|
...options.condition === void 0 ? {} : { predicate: options.condition },
|
|
@@ -2561,7 +3466,7 @@ async function streamLogpoint(session, options) {
|
|
|
2561
3466
|
if (maxEventsReached) {
|
|
2562
3467
|
return;
|
|
2563
3468
|
}
|
|
2564
|
-
const event = toLogpointEvent(raw, sentinel, options.location);
|
|
3469
|
+
const event = toLogpointEvent(raw, sentinel, options.location, maxValueLength);
|
|
2565
3470
|
if (event === void 0) {
|
|
2566
3471
|
return;
|
|
2567
3472
|
}
|
|
@@ -2601,13 +3506,13 @@ async function streamLogpoint(session, options) {
|
|
|
2601
3506
|
await removeBreakpointBestEffort(session, handle.breakpointId);
|
|
2602
3507
|
}
|
|
2603
3508
|
}
|
|
2604
|
-
function toLogpointEvent(raw, sentinel, location) {
|
|
3509
|
+
function toLogpointEvent(raw, sentinel, location, maxValueLength) {
|
|
2605
3510
|
const params = raw;
|
|
2606
3511
|
if (asString3(params.type) !== "log") {
|
|
2607
3512
|
return void 0;
|
|
2608
3513
|
}
|
|
2609
3514
|
const ts = typeof params.timestamp === "number" ? params.timestamp : void 0;
|
|
2610
|
-
return parseLogEvent(params.args, sentinel, location, ts);
|
|
3515
|
+
return parseLogEvent(params.args, sentinel, location, ts, maxValueLength);
|
|
2611
3516
|
}
|
|
2612
3517
|
async function removeBreakpointBestEffort(session, breakpointId) {
|
|
2613
3518
|
try {
|
|
@@ -2656,19 +3561,19 @@ async function waitForStop(session, options, registerMaxEventsSignal) {
|
|
|
2656
3561
|
init_types();
|
|
2657
3562
|
|
|
2658
3563
|
// src/cli/signals.ts
|
|
2659
|
-
import
|
|
3564
|
+
import process7 from "process";
|
|
2660
3565
|
async function withTerminationSignal(fn) {
|
|
2661
3566
|
const abort = new AbortController();
|
|
2662
3567
|
const onSignal = () => {
|
|
2663
3568
|
abort.abort();
|
|
2664
3569
|
};
|
|
2665
|
-
|
|
2666
|
-
|
|
3570
|
+
process7.once("SIGINT", onSignal);
|
|
3571
|
+
process7.once("SIGTERM", onSignal);
|
|
2667
3572
|
try {
|
|
2668
3573
|
return await fn(abort.signal);
|
|
2669
3574
|
} finally {
|
|
2670
|
-
|
|
2671
|
-
|
|
3575
|
+
process7.off("SIGINT", onSignal);
|
|
3576
|
+
process7.off("SIGTERM", onSignal);
|
|
2672
3577
|
}
|
|
2673
3578
|
}
|
|
2674
3579
|
|
|
@@ -2680,11 +3585,16 @@ async function handleLog(opts) {
|
|
|
2680
3585
|
const durationSec = parsePositiveInt(opts.duration, "--duration");
|
|
2681
3586
|
const maxEvents = parsePositiveInt(opts.maxEvents, "--max-events");
|
|
2682
3587
|
const hitCount = parsePositiveInt(opts.hitCount, "--hit-count");
|
|
3588
|
+
const maxValueLength = parsePositiveInt(opts.maxValueLength, "--max-value-length") ?? DEFAULT_STREAM_MAX_VALUE_LENGTH;
|
|
2683
3589
|
const expression = opts.expr.trim();
|
|
2684
3590
|
if (expression.length === 0) {
|
|
2685
3591
|
throw new CfInspectorError("INVALID_EXPRESSION", "--expr must not be empty");
|
|
2686
3592
|
}
|
|
2687
3593
|
const condition = opts.condition !== void 0 && opts.condition.trim().length > 0 ? opts.condition.trim() : void 0;
|
|
3594
|
+
warnOnMutationRisk(expression, "log --expr");
|
|
3595
|
+
if (condition !== void 0) {
|
|
3596
|
+
warnOnMutationRisk(condition, "log --condition");
|
|
3597
|
+
}
|
|
2688
3598
|
await withTerminationSignal(async (signal) => {
|
|
2689
3599
|
await withSession(target, async (session) => {
|
|
2690
3600
|
await validateExpression(session, expression);
|
|
@@ -2699,6 +3609,7 @@ async function handleLog(opts) {
|
|
|
2699
3609
|
...maxEvents === void 0 ? {} : { maxEvents },
|
|
2700
3610
|
...hitCount === void 0 ? {} : { hitCount },
|
|
2701
3611
|
...condition === void 0 ? {} : { condition },
|
|
3612
|
+
maxValueLength,
|
|
2702
3613
|
signal,
|
|
2703
3614
|
onEvent: (event) => {
|
|
2704
3615
|
writeLogEvent(event, opts.json);
|
|
@@ -2707,29 +3618,39 @@ async function handleLog(opts) {
|
|
|
2707
3618
|
warnOnUnboundBreakpoints([handle]);
|
|
2708
3619
|
}
|
|
2709
3620
|
});
|
|
3621
|
+
if (result.emitted === 0 && (result.stoppedReason === "duration" || result.stoppedReason === "signal")) {
|
|
3622
|
+
warnOnBoundBreakpointWithoutHit([result.handle]);
|
|
3623
|
+
}
|
|
2710
3624
|
writeLogSummary(result.stoppedReason, result.emitted, opts.json);
|
|
2711
|
-
});
|
|
3625
|
+
}, void 0, signal);
|
|
2712
3626
|
});
|
|
2713
3627
|
}
|
|
2714
3628
|
function writeLogSummary(stoppedReason, emitted, json) {
|
|
2715
3629
|
if (json) {
|
|
2716
|
-
|
|
3630
|
+
process8.stderr.write(`${JSON.stringify({ stopped: stoppedReason, emitted })}
|
|
2717
3631
|
`);
|
|
2718
3632
|
return;
|
|
2719
3633
|
}
|
|
2720
|
-
|
|
3634
|
+
process8.stderr.write(
|
|
2721
3635
|
`Stopped (${stoppedReason}); emitted ${emitted.toString()} log ${emitted === 1 ? "entry" : "entries"}.
|
|
2722
3636
|
`
|
|
2723
3637
|
);
|
|
2724
3638
|
}
|
|
2725
3639
|
|
|
2726
3640
|
// src/cli/commands/snapshot.ts
|
|
2727
|
-
import { performance as
|
|
2728
|
-
import
|
|
3641
|
+
import { performance as performance5 } from "perf_hooks";
|
|
3642
|
+
import process9 from "process";
|
|
2729
3643
|
init_types();
|
|
2730
3644
|
async function handleSnapshot(opts) {
|
|
2731
3645
|
const target = await resolveTargetWithCurrentCfTarget(opts, { useTimeoutForTunnel: false });
|
|
2732
3646
|
const prepared = prepareSnapshotCommand(opts, target);
|
|
3647
|
+
warnOnCaptureMutationRisk(
|
|
3648
|
+
[...prepared.captures, ...prepared.stackCaptures],
|
|
3649
|
+
opts.allowMutation === true
|
|
3650
|
+
);
|
|
3651
|
+
for (const expression of prepared.setupEvals) {
|
|
3652
|
+
warnOnMutationRisk(expression, "snapshot --setup-eval");
|
|
3653
|
+
}
|
|
2733
3654
|
const reportProgress = opts.quiet === true ? void 0 : writeProgress;
|
|
2734
3655
|
const result = await runSnapshotCommand(prepared, opts, reportProgress);
|
|
2735
3656
|
if (opts.json) {
|
|
@@ -2747,11 +3668,16 @@ function prepareSnapshotCommand(opts, target) {
|
|
|
2747
3668
|
);
|
|
2748
3669
|
}
|
|
2749
3670
|
const timeoutSec = parsePositiveInt(opts.timeout, "--timeout") ?? DEFAULT_BREAKPOINT_TIMEOUT_SEC;
|
|
2750
|
-
const maxValueLength = parsePositiveInt(opts.maxValueLength, "--max-value-length");
|
|
3671
|
+
const maxValueLength = parsePositiveInt(opts.maxValueLength, "--max-value-length") ?? DEFAULT_MAX_VALUE_LENGTH;
|
|
2751
3672
|
const condition = opts.condition !== void 0 && opts.condition.trim().length > 0 ? opts.condition.trim() : void 0;
|
|
2752
3673
|
const hitCount = parsePositiveInt(opts.hitCount, "--hit-count");
|
|
2753
3674
|
const stackDepth = parsePositiveInt(opts.stackDepth, "--stack-depth");
|
|
2754
3675
|
const setupEvals = parseSetupEvals(opts.setupEval);
|
|
3676
|
+
enforceNativeConditionMutationPolicy(
|
|
3677
|
+
condition ?? "",
|
|
3678
|
+
opts.allowMutation === true,
|
|
3679
|
+
"snapshot --condition"
|
|
3680
|
+
);
|
|
2755
3681
|
return {
|
|
2756
3682
|
target,
|
|
2757
3683
|
setupEvals,
|
|
@@ -2760,10 +3686,11 @@ function prepareSnapshotCommand(opts, target) {
|
|
|
2760
3686
|
remoteRoot: parseRemoteRoot(opts.remoteRoot),
|
|
2761
3687
|
timeoutMs: timeoutSec * 1e3,
|
|
2762
3688
|
...condition === void 0 ? {} : { condition },
|
|
2763
|
-
|
|
3689
|
+
maxValueLength,
|
|
2764
3690
|
...hitCount === void 0 ? {} : { hitCount },
|
|
2765
3691
|
...stackDepth === void 0 ? {} : { stackDepth },
|
|
2766
|
-
stackCaptures: parseCaptureList(opts.stackCaptures)
|
|
3692
|
+
stackCaptures: parseCaptureList(opts.stackCaptures),
|
|
3693
|
+
throwOnSideEffect: opts.allowMutation !== true
|
|
2767
3694
|
};
|
|
2768
3695
|
}
|
|
2769
3696
|
async function runSnapshotCommand(command, opts, reportProgress) {
|
|
@@ -2804,13 +3731,14 @@ async function runSnapshotOnSession(session, command, opts, reportProgress) {
|
|
|
2804
3731
|
reportProgress?.(
|
|
2805
3732
|
`Breakpoint hit; capturing ${captureCount.toString()} ${captureCount === 1 ? "expression" : "expressions"}...`
|
|
2806
3733
|
);
|
|
2807
|
-
const pausedStartedAt = pause.receivedAtMs ??
|
|
3734
|
+
const pausedStartedAt = pause.receivedAtMs ?? performance5.now();
|
|
2808
3735
|
const snapshot = await captureSnapshot(session, pause, {
|
|
2809
3736
|
captures: command.captures,
|
|
2810
3737
|
includeScopes: opts.includeScopes === true,
|
|
2811
|
-
|
|
3738
|
+
maxValueLength: command.maxValueLength,
|
|
2812
3739
|
...command.stackDepth === void 0 ? {} : { stackDepth: command.stackDepth },
|
|
2813
|
-
stackCaptures: command.stackCaptures
|
|
3740
|
+
stackCaptures: command.stackCaptures,
|
|
3741
|
+
throwOnSideEffect: command.throwOnSideEffect
|
|
2814
3742
|
});
|
|
2815
3743
|
if (opts.keepPaused === true) {
|
|
2816
3744
|
reportProgress?.("Snapshot captured; leaving the target paused as requested.");
|
|
@@ -2834,26 +3762,33 @@ async function setCommandBreakpoints(session, command) {
|
|
|
2834
3762
|
}
|
|
2835
3763
|
async function waitForCommandPause(session, opts, handles, timeoutMs) {
|
|
2836
3764
|
let warnedUnmatchedPause = false;
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
3765
|
+
try {
|
|
3766
|
+
return await waitForPause(session, {
|
|
3767
|
+
timeoutMs,
|
|
3768
|
+
breakpointIds: handles.map((h) => h.breakpointId),
|
|
3769
|
+
unmatchedPausePolicy: opts.failOnUnmatchedPause === true ? "fail" : "wait-for-resume",
|
|
3770
|
+
onUnmatchedPause: (unmatchedPause) => {
|
|
3771
|
+
if (warnedUnmatchedPause || opts.failOnUnmatchedPause === true) {
|
|
3772
|
+
return;
|
|
3773
|
+
}
|
|
3774
|
+
warnedUnmatchedPause = true;
|
|
3775
|
+
warnOnUnmatchedPause(unmatchedPause);
|
|
2844
3776
|
}
|
|
2845
|
-
|
|
2846
|
-
|
|
3777
|
+
});
|
|
3778
|
+
} catch (error) {
|
|
3779
|
+
if (error instanceof CfInspectorError && (error.code === "BREAKPOINT_NOT_HIT" || error.code === "UNRELATED_PAUSE_TIMEOUT")) {
|
|
3780
|
+
warnOnBoundBreakpointWithoutHit(handles);
|
|
2847
3781
|
}
|
|
2848
|
-
|
|
3782
|
+
throw error;
|
|
3783
|
+
}
|
|
2849
3784
|
}
|
|
2850
3785
|
async function resumeAfterSnapshot(session, snapshot, pausedStartedAt, reportProgress) {
|
|
2851
3786
|
try {
|
|
2852
3787
|
await resume(session);
|
|
2853
3788
|
reportProgress?.("Target resumed.");
|
|
2854
|
-
return withPausedDuration(snapshot, roundDurationMs(
|
|
3789
|
+
return withPausedDuration(snapshot, roundDurationMs(performance5.now() - pausedStartedAt));
|
|
2855
3790
|
} catch {
|
|
2856
|
-
|
|
3791
|
+
process9.stderr.write(
|
|
2857
3792
|
"[cf-inspector] warning: Debugger.resume failed after snapshot; pausedDurationMs is unknown.\n"
|
|
2858
3793
|
);
|
|
2859
3794
|
return withPausedDuration(snapshot, null);
|
|
@@ -2865,12 +3800,19 @@ function parseSetupEvals(raw) {
|
|
|
2865
3800
|
}
|
|
2866
3801
|
|
|
2867
3802
|
// src/cli/commands/watch.ts
|
|
2868
|
-
import { performance as
|
|
2869
|
-
import
|
|
3803
|
+
import { performance as performance6 } from "perf_hooks";
|
|
3804
|
+
import process10 from "process";
|
|
2870
3805
|
init_types();
|
|
2871
3806
|
async function handleWatch(opts) {
|
|
2872
3807
|
const target = await resolveTargetWithCurrentCfTarget(opts, { useTimeoutForTunnel: false });
|
|
2873
3808
|
const prepared = prepareWatchCommand(opts, target);
|
|
3809
|
+
warnOnCaptureMutationRisk(
|
|
3810
|
+
[...prepared.captures, ...prepared.stackCaptures],
|
|
3811
|
+
opts.allowMutation === true
|
|
3812
|
+
);
|
|
3813
|
+
for (const expression of prepared.setupEvals) {
|
|
3814
|
+
warnOnMutationRisk(expression, "watch --setup-eval");
|
|
3815
|
+
}
|
|
2874
3816
|
let stoppedReason = "signal";
|
|
2875
3817
|
let emitted = 0;
|
|
2876
3818
|
await withTerminationSignal(async (signal) => {
|
|
@@ -2878,7 +3820,7 @@ async function handleWatch(opts) {
|
|
|
2878
3820
|
const result = await runWatchLoop(session, prepared, opts, signal);
|
|
2879
3821
|
stoppedReason = result.stoppedReason;
|
|
2880
3822
|
emitted = result.emitted;
|
|
2881
|
-
});
|
|
3823
|
+
}, void 0, signal);
|
|
2882
3824
|
});
|
|
2883
3825
|
writeWatchSummary(stoppedReason, emitted, opts.json);
|
|
2884
3826
|
}
|
|
@@ -2892,11 +3834,16 @@ function prepareWatchCommand(opts, target) {
|
|
|
2892
3834
|
const perHitTimeoutSec = parsePositiveInt(opts.timeout, "--timeout") ?? DEFAULT_BREAKPOINT_TIMEOUT_SEC;
|
|
2893
3835
|
const durationSec = parsePositiveInt(opts.duration, "--duration");
|
|
2894
3836
|
const maxEvents = parsePositiveInt(opts.maxEvents, "--max-events");
|
|
2895
|
-
const maxValueLength = parsePositiveInt(opts.maxValueLength, "--max-value-length");
|
|
3837
|
+
const maxValueLength = parsePositiveInt(opts.maxValueLength, "--max-value-length") ?? DEFAULT_STREAM_MAX_VALUE_LENGTH;
|
|
2896
3838
|
const hitCount = parsePositiveInt(opts.hitCount, "--hit-count");
|
|
2897
3839
|
const stackDepth = parsePositiveInt(opts.stackDepth, "--stack-depth");
|
|
2898
3840
|
const condition = opts.condition !== void 0 && opts.condition.trim().length > 0 ? opts.condition.trim() : void 0;
|
|
2899
3841
|
const setupEvals = parseSetupEvals2(opts.setupEval);
|
|
3842
|
+
enforceNativeConditionMutationPolicy(
|
|
3843
|
+
condition ?? "",
|
|
3844
|
+
opts.allowMutation === true,
|
|
3845
|
+
"watch --condition"
|
|
3846
|
+
);
|
|
2900
3847
|
return {
|
|
2901
3848
|
target,
|
|
2902
3849
|
setupEvals,
|
|
@@ -2906,11 +3853,12 @@ function prepareWatchCommand(opts, target) {
|
|
|
2906
3853
|
perHitTimeoutMs: perHitTimeoutSec * 1e3,
|
|
2907
3854
|
...durationSec === void 0 ? {} : { durationMs: durationSec * 1e3 },
|
|
2908
3855
|
...maxEvents === void 0 ? {} : { maxEvents },
|
|
2909
|
-
|
|
3856
|
+
maxValueLength,
|
|
2910
3857
|
...condition === void 0 ? {} : { condition },
|
|
2911
3858
|
...hitCount === void 0 ? {} : { hitCount },
|
|
2912
3859
|
...stackDepth === void 0 ? {} : { stackDepth },
|
|
2913
|
-
stackCaptures: parseCaptureList(opts.stackCaptures)
|
|
3860
|
+
stackCaptures: parseCaptureList(opts.stackCaptures),
|
|
3861
|
+
throwOnSideEffect: opts.allowMutation !== true
|
|
2914
3862
|
};
|
|
2915
3863
|
}
|
|
2916
3864
|
async function runWatchLoop(session, command, opts, signal) {
|
|
@@ -2964,7 +3912,7 @@ async function runWatchLoop(session, command, opts, signal) {
|
|
|
2964
3912
|
break;
|
|
2965
3913
|
}
|
|
2966
3914
|
if (pause === "timeout") {
|
|
2967
|
-
if (deadline !== void 0 &&
|
|
3915
|
+
if (deadline !== void 0 && performance6.now() >= deadline) {
|
|
2968
3916
|
setStop("duration");
|
|
2969
3917
|
break;
|
|
2970
3918
|
}
|
|
@@ -2976,7 +3924,7 @@ async function runWatchLoop(session, command, opts, signal) {
|
|
|
2976
3924
|
try {
|
|
2977
3925
|
await resume(session);
|
|
2978
3926
|
} catch {
|
|
2979
|
-
|
|
3927
|
+
process10.stderr.write("[cf-inspector] warning: Debugger.resume failed during watch.\n");
|
|
2980
3928
|
setStop("transport-closed");
|
|
2981
3929
|
break;
|
|
2982
3930
|
}
|
|
@@ -2988,19 +3936,22 @@ async function runWatchLoop(session, command, opts, signal) {
|
|
|
2988
3936
|
} finally {
|
|
2989
3937
|
transportClosed.cancel();
|
|
2990
3938
|
}
|
|
3939
|
+
if (emitted === 0 && (state.reason === "duration" || state.reason === "signal")) {
|
|
3940
|
+
warnOnBoundBreakpointWithoutHit(handles);
|
|
3941
|
+
}
|
|
2991
3942
|
return { emitted, stoppedReason: state.reason };
|
|
2992
3943
|
}
|
|
2993
3944
|
function computeDeadline(durationMs) {
|
|
2994
3945
|
if (durationMs === void 0) {
|
|
2995
3946
|
return void 0;
|
|
2996
3947
|
}
|
|
2997
|
-
return
|
|
3948
|
+
return performance6.now() + durationMs;
|
|
2998
3949
|
}
|
|
2999
3950
|
function remainingForLoop(deadline, perHitTimeoutMs) {
|
|
3000
3951
|
if (deadline === void 0) {
|
|
3001
3952
|
return perHitTimeoutMs;
|
|
3002
3953
|
}
|
|
3003
|
-
const remaining = deadline -
|
|
3954
|
+
const remaining = deadline - performance6.now();
|
|
3004
3955
|
if (remaining <= 0) {
|
|
3005
3956
|
return 0;
|
|
3006
3957
|
}
|
|
@@ -3034,10 +3985,14 @@ async function waitForNextWatchPause(session, handles, timeoutMs, signal) {
|
|
|
3034
3985
|
return await waitForPause(session, {
|
|
3035
3986
|
timeoutMs,
|
|
3036
3987
|
breakpointIds: handles.map((h) => h.breakpointId),
|
|
3037
|
-
unmatchedPausePolicy: "wait-for-resume"
|
|
3988
|
+
unmatchedPausePolicy: "wait-for-resume",
|
|
3989
|
+
signal
|
|
3038
3990
|
});
|
|
3039
3991
|
} catch (err) {
|
|
3040
3992
|
if (err instanceof CfInspectorError) {
|
|
3993
|
+
if (err.code === "ABORTED") {
|
|
3994
|
+
return "signal";
|
|
3995
|
+
}
|
|
3041
3996
|
if (err.code === "BREAKPOINT_NOT_HIT") {
|
|
3042
3997
|
return "timeout";
|
|
3043
3998
|
}
|
|
@@ -3052,9 +4007,10 @@ async function captureWatchEvent(session, command, pause, hit, opts) {
|
|
|
3052
4007
|
const snapshot = await captureSnapshot(session, pause, {
|
|
3053
4008
|
captures: command.captures,
|
|
3054
4009
|
includeScopes: opts.includeScopes === true,
|
|
3055
|
-
|
|
4010
|
+
maxValueLength: command.maxValueLength,
|
|
3056
4011
|
...command.stackDepth === void 0 ? {} : { stackDepth: command.stackDepth },
|
|
3057
|
-
stackCaptures: command.stackCaptures
|
|
4012
|
+
stackCaptures: command.stackCaptures,
|
|
4013
|
+
throwOnSideEffect: command.throwOnSideEffect
|
|
3058
4014
|
});
|
|
3059
4015
|
const at = formatLocation(command, snapshot.topFrame);
|
|
3060
4016
|
const base = {
|
|
@@ -3081,11 +4037,11 @@ function formatLocation(command, topFrame) {
|
|
|
3081
4037
|
}
|
|
3082
4038
|
function writeWatchSummary(reason, emitted, json) {
|
|
3083
4039
|
if (json) {
|
|
3084
|
-
|
|
4040
|
+
process10.stderr.write(`${JSON.stringify({ stopped: reason, emitted })}
|
|
3085
4041
|
`);
|
|
3086
4042
|
return;
|
|
3087
4043
|
}
|
|
3088
|
-
|
|
4044
|
+
process10.stderr.write(
|
|
3089
4045
|
`Stopped (${reason}); emitted ${emitted.toString()} watch ${emitted === 1 ? "event" : "events"}.
|
|
3090
4046
|
`
|
|
3091
4047
|
);
|
|
@@ -3097,8 +4053,16 @@ function parseSetupEvals2(raw) {
|
|
|
3097
4053
|
|
|
3098
4054
|
// src/cli/program.ts
|
|
3099
4055
|
function applyTargetOptions(cmd, options = {}) {
|
|
3100
|
-
const
|
|
3101
|
-
|
|
4056
|
+
const withEndpointOptions = cmd.option("--port <number>", "Local port the inspector or tunnel listens on").option("--host <host>", "Hostname (default: 127.0.0.1)", "127.0.0.1").option("--region <key>", "CF region key (required with --app)").option("--api-endpoint <url>", "CF API endpoint override for --region").option("--org <name>", "CF org name (required with --app)").option("--space <name>", "CF space name (required with --app)").option(
|
|
4057
|
+
"--app <name>",
|
|
4058
|
+
"CF app name; requires explicit --region/--org/--space (ambient cf target is ignored)"
|
|
4059
|
+
);
|
|
4060
|
+
const withTargetOption = options.includeTarget === false ? withEndpointOptions : withEndpointOptions.option(
|
|
4061
|
+
"--target <index>",
|
|
4062
|
+
"Inspector target index from /json/list (default: 0)"
|
|
4063
|
+
);
|
|
4064
|
+
const withWorkerOption = options.includeWorker === false ? withTargetOption : withTargetOption.option("--worker <index>", "NodeWorker sub-session index listed by list-targets");
|
|
4065
|
+
return options.includeTimeout === false ? withWorkerOption : withWorkerOption.option("--timeout <seconds>", "Timeout for CF tunnel readiness in seconds (default: 180)");
|
|
3102
4066
|
}
|
|
3103
4067
|
var collectStrings = (value, prev = []) => [
|
|
3104
4068
|
...prev,
|
|
@@ -3139,14 +4103,14 @@ function registerSnapshot(program) {
|
|
|
3139
4103
|
applyTargetOptions(
|
|
3140
4104
|
program.command("snapshot").description("Set a breakpoint, wait for it to hit, capture expressions, and resume"),
|
|
3141
4105
|
{ includeTimeout: false }
|
|
3142
|
-
).option("--bp <file:line>", "Breakpoint location (repeatable; first hit wins), e.g. src/handler.ts:42", collectStrings, []).option("--capture <expr,\u2026>", "Top-level comma-separated expressions to evaluate in the paused frame").option("--setup-eval <expr>", "Evaluate a global setup expression before breakpoint setup (repeatable)", collectStrings, []).option("--timeout <seconds>", "How long to wait for the breakpoint to hit (default: 30)").option("--max-value-length <chars>", "Maximum characters per captured value before truncation (default:
|
|
4106
|
+
).option("--bp <file:line>", "Breakpoint location (repeatable; first hit wins), e.g. src/handler.ts:42", collectStrings, []).option("--capture <expr,\u2026>", "Top-level comma-separated expressions to evaluate in the paused frame").option("--setup-eval <expr>", "Evaluate a global setup expression before breakpoint setup (repeatable)", collectStrings, []).option("--timeout <seconds>", "How long to wait for the breakpoint to hit (default: 30)").option("--max-value-length <chars>", "Maximum characters per captured value before truncation (default: 131072)").option("--remote-root <value>", "Path-mapping anchor: literal path or regex:<pattern> / /pattern/flags").option("--condition <expr>", "Only pause when this JS expression evaluates truthy in the paused frame").option("--hit-count <n>", "Only pause after the breakpoint has been hit N or more times").option("--stack-depth <n>", "Walk this many call frames when capturing (default: 1, only top frame)").option("--stack-captures <expr,\u2026>", "Expressions to evaluate on each call frame in the stack").option("--allow-mutation", "Allow mutation-capable captures and native breakpoint conditions to run").option("--include-scopes", "Include expanded paused-frame scopes in the snapshot").option("--no-json", "Print a human-readable summary instead of JSON").option("--quiet", "Suppress progress messages on stderr").option("--keep-paused", "Skip Debugger.resume after capture; Node may resume when this CLI disconnects").option("--fail-on-unmatched-pause", "Fail immediately if the target pauses somewhere else").action(async (opts) => {
|
|
3143
4107
|
await handleSnapshot(opts);
|
|
3144
4108
|
});
|
|
3145
4109
|
}
|
|
3146
4110
|
function registerLog(program) {
|
|
3147
4111
|
applyTargetOptions(
|
|
3148
4112
|
program.command("log").description("Stream a non-pausing logpoint: log an expression each time a line executes")
|
|
3149
|
-
).requiredOption("--at <file:line>", "Logpoint location, e.g. src/handler.ts:42").requiredOption("--expr <expression>", "JavaScript expression to log on each hit").option("--remote-root <value>", "Path-mapping anchor: literal path or regex:<pattern> / /pattern/flags").option("--duration <seconds>", "Stop streaming after N seconds (default: run until SIGINT)").option("--max-events <n>", "Stop streaming after emitting N log events").option("--hit-count <n>", "Start logging once the line has been hit N or more times").option("--condition <expr>", "Only log when this JS expression evaluates truthy on the inspectee").option("--no-json", "Print human-readable lines instead of JSON Lines").action(async (opts) => {
|
|
4113
|
+
).requiredOption("--at <file:line>", "Logpoint location, e.g. src/handler.ts:42").requiredOption("--expr <expression>", "JavaScript expression to log on each hit").option("--remote-root <value>", "Path-mapping anchor: literal path or regex:<pattern> / /pattern/flags").option("--duration <seconds>", "Stop streaming after N seconds (default: run until SIGINT)").option("--max-events <n>", "Stop streaming after emitting N log events").option("--hit-count <n>", "Start logging once the line has been hit N or more times").option("--condition <expr>", "Only log when this JS expression evaluates truthy on the inspectee").option("--max-value-length <chars>", "Maximum characters per log value before truncation (default: 4096)").option("--no-json", "Print human-readable lines instead of JSON Lines").action(async (opts) => {
|
|
3150
4114
|
await handleLog(opts);
|
|
3151
4115
|
});
|
|
3152
4116
|
}
|
|
@@ -3154,7 +4118,7 @@ function registerWatch(program) {
|
|
|
3154
4118
|
applyTargetOptions(
|
|
3155
4119
|
program.command("watch").description("Stream a snapshot per breakpoint hit (multi-shot watch); resume between hits"),
|
|
3156
4120
|
{ includeTimeout: false }
|
|
3157
|
-
).option("--bp <file:line>", "Breakpoint location (repeatable), e.g. src/handler.ts:42", collectStrings, []).option("--capture <expr,\u2026>", "Top-level comma-separated expressions to evaluate per hit").option("--setup-eval <expr>", "Evaluate a global setup expression before breakpoint setup (repeatable)", collectStrings, []).option("--condition <expr>", "Only emit hits where this JS expression evaluates truthy").option("--hit-count <n>", "Start emitting after the line has been hit N or more times").option("--remote-root <value>", "Path-mapping anchor: literal path or regex:<pattern> / /pattern/flags").option("--duration <seconds>", "Stop streaming after N seconds (default: run until SIGINT)").option("--max-events <n>", "Stop streaming after emitting N watch events").option("--timeout <seconds>", "How long to wait for the next hit before giving up (default: 30)").option("--max-value-length <chars>", "Maximum characters per captured value before truncation (default: 4096)").option("--stack-depth <n>", "Walk this many call frames per hit (default: 1)").option("--stack-captures <expr,\u2026>", "Expressions to evaluate on each call frame").option("--include-scopes", "Include expanded paused-frame scopes per hit").option("--no-json", "Print human-readable lines instead of JSON Lines").action(async (opts) => {
|
|
4121
|
+
).option("--bp <file:line>", "Breakpoint location (repeatable), e.g. src/handler.ts:42", collectStrings, []).option("--capture <expr,\u2026>", "Top-level comma-separated expressions to evaluate per hit").option("--setup-eval <expr>", "Evaluate a global setup expression before breakpoint setup (repeatable)", collectStrings, []).option("--condition <expr>", "Only emit hits where this JS expression evaluates truthy").option("--hit-count <n>", "Start emitting after the line has been hit N or more times").option("--remote-root <value>", "Path-mapping anchor: literal path or regex:<pattern> / /pattern/flags").option("--duration <seconds>", "Stop streaming after N seconds (default: run until SIGINT)").option("--max-events <n>", "Stop streaming after emitting N watch events").option("--timeout <seconds>", "How long to wait for the next hit before giving up (default: 30)").option("--max-value-length <chars>", "Maximum characters per captured value before truncation (default: 4096)").option("--stack-depth <n>", "Walk this many call frames per hit (default: 1)").option("--stack-captures <expr,\u2026>", "Expressions to evaluate on each call frame").option("--allow-mutation", "Allow mutation-capable captures and native breakpoint conditions to run").option("--include-scopes", "Include expanded paused-frame scopes per hit").option("--no-json", "Print human-readable lines instead of JSON Lines").action(async (opts) => {
|
|
3158
4122
|
await handleWatch(opts);
|
|
3159
4123
|
});
|
|
3160
4124
|
}
|
|
@@ -3162,7 +4126,7 @@ function registerException(program) {
|
|
|
3162
4126
|
applyTargetOptions(
|
|
3163
4127
|
program.command("exception").description("Pause on a thrown exception, capture the value and frame, then resume"),
|
|
3164
4128
|
{ includeTimeout: false }
|
|
3165
|
-
).option("--type <state>", "Pause type: uncaught (default), caught, or all").option("--capture <expr,\u2026>", "Top-level comma-separated expressions to evaluate in the paused frame").option("--remote-root <value>", "Path-mapping anchor: literal path or regex:<pattern> / /pattern/flags").option("--timeout <seconds>", "How long to wait for an exception (default: 30)").option("--max-value-length <chars>", "Maximum characters per captured value before truncation (default:
|
|
4129
|
+
).option("--type <state>", "Pause type: uncaught (default), caught, or all").option("--capture <expr,\u2026>", "Top-level comma-separated expressions to evaluate in the paused frame").option("--remote-root <value>", "Path-mapping anchor: literal path or regex:<pattern> / /pattern/flags").option("--timeout <seconds>", "How long to wait for an exception (default: 30)").option("--max-value-length <chars>", "Maximum characters per captured value before truncation (default: 131072)").option("--stack-depth <n>", "Walk this many call frames when capturing (default: 1)").option("--stack-captures <expr,\u2026>", "Expressions to evaluate on each call frame in the stack").option("--allow-mutation", "Allow mutation-capable capture expressions to run").option("--include-scopes", "Include expanded paused-frame scopes in the snapshot").option("--keep-paused", "Skip Debugger.resume after capture; Node may resume when this CLI disconnects").option("--no-json", "Print a human-readable summary instead of JSON").action(async (opts) => {
|
|
3166
4130
|
await handleException(opts);
|
|
3167
4131
|
});
|
|
3168
4132
|
}
|
|
@@ -3182,14 +4146,21 @@ function registerListScripts(program) {
|
|
|
3182
4146
|
}
|
|
3183
4147
|
function registerListTargets(program) {
|
|
3184
4148
|
applyTargetOptions(
|
|
3185
|
-
program.command("list-targets").description(
|
|
3186
|
-
|
|
4149
|
+
program.command("list-targets").description(
|
|
4150
|
+
"List raw /json/list targets and nested workers; use --target or --worker on other commands"
|
|
4151
|
+
),
|
|
4152
|
+
{ includeTarget: false, includeWorker: false }
|
|
4153
|
+
).option(
|
|
4154
|
+
"--no-json",
|
|
4155
|
+
"Print tab-separated target/worker rows: index, kind, type, title, and URL"
|
|
4156
|
+
).action(async (opts) => {
|
|
3187
4157
|
await handleListTargets(opts);
|
|
3188
4158
|
});
|
|
3189
4159
|
}
|
|
3190
4160
|
function registerAttach(program) {
|
|
3191
4161
|
applyTargetOptions(
|
|
3192
|
-
program.command("attach").description("Connect, fetch the inspector version, and disconnect (smoke-test)")
|
|
4162
|
+
program.command("attach").description("Connect, fetch the inspector version, and disconnect (smoke-test)"),
|
|
4163
|
+
{ includeTarget: false, includeWorker: false }
|
|
3193
4164
|
).option("--no-json", "Print a multi-line summary instead of JSON").action(async (opts) => {
|
|
3194
4165
|
await handleAttach(opts);
|
|
3195
4166
|
});
|
|
@@ -3198,20 +4169,20 @@ function registerAttach(program) {
|
|
|
3198
4169
|
// src/cli.ts
|
|
3199
4170
|
init_types();
|
|
3200
4171
|
try {
|
|
3201
|
-
await main(
|
|
4172
|
+
await main(process11.argv);
|
|
3202
4173
|
} catch (err) {
|
|
3203
4174
|
if (err instanceof CfInspectorError) {
|
|
3204
|
-
|
|
4175
|
+
process11.stderr.write(`Error [${err.code}]: ${err.message}
|
|
3205
4176
|
`);
|
|
3206
4177
|
if (err.detail !== void 0) {
|
|
3207
|
-
|
|
4178
|
+
process11.stderr.write(` detail: ${err.detail}
|
|
3208
4179
|
`);
|
|
3209
4180
|
}
|
|
3210
|
-
|
|
4181
|
+
process11.exit(1);
|
|
3211
4182
|
}
|
|
3212
4183
|
const message = err instanceof Error ? err.message : String(err);
|
|
3213
|
-
|
|
4184
|
+
process11.stderr.write(`Error: ${message}
|
|
3214
4185
|
`);
|
|
3215
|
-
|
|
4186
|
+
process11.exit(1);
|
|
3216
4187
|
}
|
|
3217
4188
|
//# sourceMappingURL=cli.js.map
|