@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/index.js
CHANGED
|
@@ -289,96 +289,290 @@ function buildBreakpointUrlRegex(input) {
|
|
|
289
289
|
init_types();
|
|
290
290
|
|
|
291
291
|
// src/inspector/conversions.ts
|
|
292
|
+
var INTERNAL_SLOT_SUBTYPES = /* @__PURE__ */ new Set([
|
|
293
|
+
"regexp",
|
|
294
|
+
"date",
|
|
295
|
+
"map",
|
|
296
|
+
"set",
|
|
297
|
+
"weakmap",
|
|
298
|
+
"weakset",
|
|
299
|
+
"iterator",
|
|
300
|
+
"generator",
|
|
301
|
+
"promise",
|
|
302
|
+
"typedarray",
|
|
303
|
+
"arraybuffer",
|
|
304
|
+
"dataview",
|
|
305
|
+
"webassemblymemory",
|
|
306
|
+
"wasmvalue",
|
|
307
|
+
"trustedtype"
|
|
308
|
+
]);
|
|
292
309
|
function asString(value, fallback = "") {
|
|
293
310
|
return typeof value === "string" ? value : fallback;
|
|
294
311
|
}
|
|
295
312
|
function asNumber(value, fallback = 0) {
|
|
296
313
|
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
297
314
|
}
|
|
315
|
+
function isRecord(value) {
|
|
316
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
317
|
+
}
|
|
298
318
|
function nonEmptyString(value) {
|
|
299
319
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
300
320
|
}
|
|
321
|
+
function optionalNumber(value) {
|
|
322
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
323
|
+
}
|
|
324
|
+
function optionalCoordinate(value) {
|
|
325
|
+
const number = optionalNumber(value);
|
|
326
|
+
return number !== void 0 && Number.isSafeInteger(number) && number >= 0 ? number : void 0;
|
|
327
|
+
}
|
|
328
|
+
function optionalBoolean(value) {
|
|
329
|
+
return typeof value === "boolean" ? value : void 0;
|
|
330
|
+
}
|
|
331
|
+
function toScriptLocation(value) {
|
|
332
|
+
if (!isRecord(value)) {
|
|
333
|
+
return void 0;
|
|
334
|
+
}
|
|
335
|
+
const scriptId = nonEmptyString(value["scriptId"]);
|
|
336
|
+
const lineNumber = optionalCoordinate(value["lineNumber"]);
|
|
337
|
+
if (scriptId === void 0 || lineNumber === void 0) {
|
|
338
|
+
return void 0;
|
|
339
|
+
}
|
|
340
|
+
const rawColumnNumber = value["columnNumber"];
|
|
341
|
+
const columnNumber = optionalCoordinate(rawColumnNumber);
|
|
342
|
+
if (rawColumnNumber !== void 0 && columnNumber === void 0) {
|
|
343
|
+
return void 0;
|
|
344
|
+
}
|
|
345
|
+
return columnNumber === void 0 ? { scriptId, lineNumber } : { scriptId, lineNumber, columnNumber };
|
|
346
|
+
}
|
|
301
347
|
function toResolvedLocations(value) {
|
|
302
348
|
if (!Array.isArray(value)) {
|
|
303
349
|
return [];
|
|
304
350
|
}
|
|
305
351
|
return value.flatMap((entry) => {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
}
|
|
309
|
-
const candidate = entry;
|
|
310
|
-
const scriptId = asString(candidate.scriptId);
|
|
311
|
-
if (scriptId.length === 0) {
|
|
352
|
+
const location = toScriptLocation(entry);
|
|
353
|
+
if (location === void 0 || !isRecord(entry)) {
|
|
312
354
|
return [];
|
|
313
355
|
}
|
|
314
|
-
const url = typeof
|
|
315
|
-
|
|
316
|
-
const result = url === void 0 ? { scriptId, lineNumber, columnNumber: asNumber(candidate.columnNumber) } : { scriptId, url, lineNumber, columnNumber: asNumber(candidate.columnNumber) };
|
|
317
|
-
return [result];
|
|
356
|
+
const url = typeof entry["url"] === "string" ? entry["url"] : void 0;
|
|
357
|
+
return [url === void 0 ? location : { ...location, url }];
|
|
318
358
|
});
|
|
319
359
|
}
|
|
320
|
-
function
|
|
360
|
+
function toBreakLocations(value) {
|
|
321
361
|
if (!Array.isArray(value)) {
|
|
322
362
|
return [];
|
|
323
363
|
}
|
|
324
364
|
return value.flatMap((entry) => {
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
}
|
|
328
|
-
const candidate = entry;
|
|
329
|
-
const type = asString(candidate.type);
|
|
330
|
-
if (type.length === 0) {
|
|
365
|
+
const location = toScriptLocation(entry);
|
|
366
|
+
if (location === void 0 || !isRecord(entry)) {
|
|
331
367
|
return [];
|
|
332
368
|
}
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
const base = name === void 0 ? { type } : { type, name };
|
|
336
|
-
return [objectId === void 0 ? base : { ...base, objectId }];
|
|
369
|
+
const type = nonEmptyString(entry["type"]);
|
|
370
|
+
return [type === void 0 ? location : { ...location, type }];
|
|
337
371
|
});
|
|
338
372
|
}
|
|
373
|
+
function remoteCompleteness(subtype) {
|
|
374
|
+
if (subtype === "proxy") {
|
|
375
|
+
return "unavailable";
|
|
376
|
+
}
|
|
377
|
+
return subtype !== void 0 && INTERNAL_SLOT_SUBTYPES.has(subtype) ? "truncated" : void 0;
|
|
378
|
+
}
|
|
379
|
+
function optionalOwnField(key, value) {
|
|
380
|
+
return Object.hasOwn(value, key) ? { [key]: value[key] } : {};
|
|
381
|
+
}
|
|
382
|
+
function toRemoteObject(value) {
|
|
383
|
+
if (!isRecord(value)) {
|
|
384
|
+
return void 0;
|
|
385
|
+
}
|
|
386
|
+
const type = nonEmptyString(value["type"]);
|
|
387
|
+
if (type === void 0) {
|
|
388
|
+
return void 0;
|
|
389
|
+
}
|
|
390
|
+
const subtype = nonEmptyString(value["subtype"]);
|
|
391
|
+
const completeness = remoteCompleteness(subtype);
|
|
392
|
+
return {
|
|
393
|
+
type,
|
|
394
|
+
...subtype === void 0 ? {} : { subtype },
|
|
395
|
+
...optionalTextField("className", value["className"]),
|
|
396
|
+
...completeness === void 0 ? {} : { completeness },
|
|
397
|
+
...optionalOwnField("value", value),
|
|
398
|
+
...optionalTextField("unserializableValue", value["unserializableValue"]),
|
|
399
|
+
...optionalTextField("description", value["description"]),
|
|
400
|
+
...optionalOwnField("deepSerializedValue", value),
|
|
401
|
+
...optionalTextField("objectId", value["objectId"]),
|
|
402
|
+
...optionalOwnField("preview", value),
|
|
403
|
+
...optionalOwnField("customPreview", value)
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
function optionalTextField(key, value) {
|
|
407
|
+
return typeof value === "string" ? { [key]: value } : {};
|
|
408
|
+
}
|
|
409
|
+
function toScope(value) {
|
|
410
|
+
if (!isRecord(value)) {
|
|
411
|
+
return void 0;
|
|
412
|
+
}
|
|
413
|
+
const type = nonEmptyString(value["type"]);
|
|
414
|
+
if (type === void 0) {
|
|
415
|
+
return void 0;
|
|
416
|
+
}
|
|
417
|
+
const object = toRemoteObject(value["object"]);
|
|
418
|
+
const name = nonEmptyString(value["name"]);
|
|
419
|
+
const startLocation = toScriptLocation(value["startLocation"]);
|
|
420
|
+
const endLocation = toScriptLocation(value["endLocation"]);
|
|
421
|
+
return {
|
|
422
|
+
type,
|
|
423
|
+
...name === void 0 ? {} : { name },
|
|
424
|
+
...object === void 0 ? {} : { object },
|
|
425
|
+
...object?.objectId === void 0 ? {} : { objectId: object.objectId },
|
|
426
|
+
...startLocation === void 0 ? {} : { startLocation },
|
|
427
|
+
...endLocation === void 0 ? {} : { endLocation }
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
function toScopeChain(value) {
|
|
431
|
+
return Array.isArray(value) ? value.flatMap((entry) => {
|
|
432
|
+
const scope = toScope(entry);
|
|
433
|
+
return scope === void 0 ? [] : [scope];
|
|
434
|
+
}) : [];
|
|
435
|
+
}
|
|
339
436
|
function resolveCallFrameUrl(frame, scripts) {
|
|
340
|
-
const direct = nonEmptyString(frame
|
|
437
|
+
const direct = nonEmptyString(frame["url"]);
|
|
341
438
|
if (direct !== void 0) {
|
|
342
439
|
return direct;
|
|
343
440
|
}
|
|
344
|
-
const scriptId =
|
|
345
|
-
|
|
441
|
+
const scriptId = toScriptLocation(frame["location"])?.scriptId;
|
|
442
|
+
return scriptId === void 0 ? void 0 : nonEmptyString(scripts?.get(scriptId)?.url);
|
|
443
|
+
}
|
|
444
|
+
function toCallFrameMetadata(candidate, location, scripts) {
|
|
445
|
+
const functionLocation = toScriptLocation(candidate["functionLocation"]);
|
|
446
|
+
const thisObject = toRemoteObject(candidate["this"]);
|
|
447
|
+
const returnValue = toRemoteObject(candidate["returnValue"]);
|
|
448
|
+
const url = resolveCallFrameUrl(candidate, scripts);
|
|
449
|
+
return {
|
|
450
|
+
...location === void 0 ? {} : { scriptId: location.scriptId },
|
|
451
|
+
...functionLocation === void 0 ? {} : { functionLocation },
|
|
452
|
+
...url === void 0 ? {} : { url },
|
|
453
|
+
...thisObject === void 0 ? {} : { thisObject },
|
|
454
|
+
...returnValue === void 0 ? {} : { returnValue }
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
function toCallFrame(value, scripts) {
|
|
458
|
+
if (!isRecord(value)) {
|
|
459
|
+
return void 0;
|
|
460
|
+
}
|
|
461
|
+
const callFrameId = nonEmptyString(value["callFrameId"]);
|
|
462
|
+
if (callFrameId === void 0) {
|
|
346
463
|
return void 0;
|
|
347
464
|
}
|
|
348
|
-
|
|
465
|
+
const location = toScriptLocation(value["location"]);
|
|
466
|
+
return {
|
|
467
|
+
callFrameId,
|
|
468
|
+
functionName: asString(value["functionName"]),
|
|
469
|
+
...toCallFrameMetadata(value, location, scripts),
|
|
470
|
+
lineNumber: location?.lineNumber ?? 0,
|
|
471
|
+
columnNumber: location?.columnNumber ?? 0,
|
|
472
|
+
scopeChain: toScopeChain(value["scopeChain"])
|
|
473
|
+
};
|
|
349
474
|
}
|
|
350
475
|
function toCallFrames(value, scripts) {
|
|
351
|
-
|
|
352
|
-
|
|
476
|
+
return Array.isArray(value) ? value.flatMap((entry) => {
|
|
477
|
+
const frame = toCallFrame(entry, scripts);
|
|
478
|
+
return frame === void 0 ? [] : [frame];
|
|
479
|
+
}) : [];
|
|
480
|
+
}
|
|
481
|
+
function toStackTraceId(value) {
|
|
482
|
+
if (!isRecord(value)) {
|
|
483
|
+
return void 0;
|
|
353
484
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
485
|
+
const id = nonEmptyString(value["id"]);
|
|
486
|
+
if (id === void 0) {
|
|
487
|
+
return void 0;
|
|
488
|
+
}
|
|
489
|
+
const debuggerId = nonEmptyString(value["debuggerId"]);
|
|
490
|
+
return debuggerId === void 0 ? { id } : { id, debuggerId };
|
|
491
|
+
}
|
|
492
|
+
function toStackTraceFrame(value) {
|
|
493
|
+
if (!isRecord(value)) {
|
|
494
|
+
return void 0;
|
|
495
|
+
}
|
|
496
|
+
const scriptId = nonEmptyString(value["scriptId"]);
|
|
497
|
+
if (scriptId === void 0) {
|
|
498
|
+
return void 0;
|
|
499
|
+
}
|
|
500
|
+
return {
|
|
501
|
+
functionName: asString(value["functionName"]),
|
|
502
|
+
scriptId,
|
|
503
|
+
url: asString(value["url"]),
|
|
504
|
+
lineNumber: asNumber(value["lineNumber"]),
|
|
505
|
+
columnNumber: asNumber(value["columnNumber"])
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
function toStackTrace(value) {
|
|
509
|
+
if (!isRecord(value) || !Array.isArray(value["callFrames"])) {
|
|
510
|
+
return void 0;
|
|
511
|
+
}
|
|
512
|
+
const callFrames = value["callFrames"].flatMap((entry) => {
|
|
513
|
+
const frame = toStackTraceFrame(entry);
|
|
514
|
+
return frame === void 0 ? [] : [frame];
|
|
372
515
|
});
|
|
516
|
+
const description = nonEmptyString(value["description"]);
|
|
517
|
+
const parent = toStackTrace(value["parent"]);
|
|
518
|
+
const parentId = toStackTraceId(value["parentId"]);
|
|
519
|
+
return {
|
|
520
|
+
callFrames,
|
|
521
|
+
...description === void 0 ? {} : { description },
|
|
522
|
+
...parent === void 0 ? {} : { parent },
|
|
523
|
+
...parentId === void 0 ? {} : { parentId }
|
|
524
|
+
};
|
|
373
525
|
}
|
|
374
|
-
function toPauseEvent(
|
|
375
|
-
const
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
526
|
+
function toPauseEvent(value, receivedAtMs, scripts) {
|
|
527
|
+
const params = isRecord(value) ? value : {};
|
|
528
|
+
const asyncStackTrace = toStackTrace(params["asyncStackTrace"]);
|
|
529
|
+
const asyncStackTraceId = toStackTraceId(params["asyncStackTraceId"]);
|
|
530
|
+
const asyncCallStackTraceId = toStackTraceId(params["asyncCallStackTraceId"]);
|
|
531
|
+
return {
|
|
532
|
+
reason: asString(params["reason"]),
|
|
533
|
+
hitBreakpoints: Array.isArray(params["hitBreakpoints"]) ? params["hitBreakpoints"].filter((id) => typeof id === "string") : [],
|
|
534
|
+
callFrames: toCallFrames(params["callFrames"], scripts),
|
|
535
|
+
receivedAtMs,
|
|
536
|
+
...params["data"] === void 0 ? {} : { data: params["data"] },
|
|
537
|
+
...asyncStackTrace === void 0 ? {} : { asyncStackTrace },
|
|
538
|
+
...asyncStackTraceId === void 0 ? {} : { asyncStackTraceId },
|
|
539
|
+
...asyncCallStackTraceId === void 0 ? {} : { asyncCallStackTraceId }
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
function toScriptInfo(value) {
|
|
543
|
+
if (!isRecord(value)) {
|
|
544
|
+
return void 0;
|
|
545
|
+
}
|
|
546
|
+
const scriptId = nonEmptyString(value["scriptId"]);
|
|
547
|
+
if (scriptId === void 0) {
|
|
548
|
+
return void 0;
|
|
549
|
+
}
|
|
550
|
+
const stackTrace = toStackTrace(value["stackTrace"]);
|
|
551
|
+
return {
|
|
552
|
+
scriptId,
|
|
553
|
+
url: asString(value["url"]),
|
|
554
|
+
...optionalNumericField("startLine", value["startLine"]),
|
|
555
|
+
...optionalNumericField("startColumn", value["startColumn"]),
|
|
556
|
+
...optionalNumericField("endLine", value["endLine"]),
|
|
557
|
+
...optionalNumericField("endColumn", value["endColumn"]),
|
|
558
|
+
...optionalNumericField("executionContextId", value["executionContextId"]),
|
|
559
|
+
...optionalTextField("hash", value["hash"]),
|
|
560
|
+
...optionalTextField("buildId", value["buildId"]),
|
|
561
|
+
...value["executionContextAuxData"] === void 0 ? {} : { executionContextAuxData: value["executionContextAuxData"] },
|
|
562
|
+
...optionalTextField("sourceMapURL", value["sourceMapURL"]),
|
|
563
|
+
...optionalBooleanField("hasSourceURL", value["hasSourceURL"]),
|
|
564
|
+
...optionalBooleanField("isModule", value["isModule"]),
|
|
565
|
+
...optionalNumericField("length", value["length"]),
|
|
566
|
+
...stackTrace === void 0 ? {} : { stackTrace }
|
|
380
567
|
};
|
|
381
|
-
|
|
568
|
+
}
|
|
569
|
+
function optionalNumericField(key, value) {
|
|
570
|
+
const number = optionalNumber(value);
|
|
571
|
+
return number === void 0 ? {} : { [key]: number };
|
|
572
|
+
}
|
|
573
|
+
function optionalBooleanField(key, value) {
|
|
574
|
+
const boolean = optionalBoolean(value);
|
|
575
|
+
return boolean === void 0 ? {} : { [key]: boolean };
|
|
382
576
|
}
|
|
383
577
|
function topFrameLocation(pause) {
|
|
384
578
|
const top = pause.callFrames[0];
|
|
@@ -470,41 +664,146 @@ async function setBreakpoint(session, input) {
|
|
|
470
664
|
async function removeBreakpoint(session, breakpointId) {
|
|
471
665
|
await session.client.send("Debugger.removeBreakpoint", { breakpointId });
|
|
472
666
|
}
|
|
667
|
+
function validateCoordinate(value, label) {
|
|
668
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
669
|
+
throw new CfInspectorError(
|
|
670
|
+
"INVALID_ARGUMENT",
|
|
671
|
+
`${label} must be a non-negative integer, received: ${value.toString()}`
|
|
672
|
+
);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
function validateScriptLocation(location, label) {
|
|
676
|
+
if (location.scriptId.trim().length === 0) {
|
|
677
|
+
throw new CfInspectorError("INVALID_ARGUMENT", `${label}.scriptId must not be empty`);
|
|
678
|
+
}
|
|
679
|
+
validateCoordinate(location.lineNumber, `${label}.lineNumber`);
|
|
680
|
+
if (location.columnNumber !== void 0) {
|
|
681
|
+
validateCoordinate(location.columnNumber, `${label}.columnNumber`);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
function isSameScriptLocation(requested, actual) {
|
|
685
|
+
return requested.scriptId === actual.scriptId && requested.lineNumber === actual.lineNumber && (requested.columnNumber ?? 0) === (actual.columnNumber ?? 0);
|
|
686
|
+
}
|
|
687
|
+
async function getPossibleBreakpoints(session, options) {
|
|
688
|
+
validateScriptLocation(options.start, "start");
|
|
689
|
+
if (options.end !== void 0) {
|
|
690
|
+
validateScriptLocation(options.end, "end");
|
|
691
|
+
if (options.end.scriptId !== options.start.scriptId) {
|
|
692
|
+
throw new CfInspectorError("INVALID_ARGUMENT", "start and end must refer to the same scriptId");
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
const result = await session.client.send(
|
|
696
|
+
"Debugger.getPossibleBreakpoints",
|
|
697
|
+
{
|
|
698
|
+
start: options.start,
|
|
699
|
+
...options.end === void 0 ? {} : { end: options.end },
|
|
700
|
+
...options.restrictToFunction === void 0 ? {} : { restrictToFunction: options.restrictToFunction }
|
|
701
|
+
}
|
|
702
|
+
);
|
|
703
|
+
if (!Array.isArray(result.locations)) {
|
|
704
|
+
throw new CfInspectorError(
|
|
705
|
+
"CDP_REQUEST_FAILED",
|
|
706
|
+
"Debugger.getPossibleBreakpoints did not return a locations array"
|
|
707
|
+
);
|
|
708
|
+
}
|
|
709
|
+
return toBreakLocations(result.locations);
|
|
710
|
+
}
|
|
711
|
+
async function setBreakpointAtLocation(session, input) {
|
|
712
|
+
validateScriptLocation(input.location, "location");
|
|
713
|
+
const result = await session.client.send("Debugger.setBreakpoint", {
|
|
714
|
+
location: input.location,
|
|
715
|
+
...input.condition === void 0 || input.condition.length === 0 ? {} : { condition: input.condition }
|
|
716
|
+
});
|
|
717
|
+
const breakpointId = asString(result.breakpointId);
|
|
718
|
+
const actualLocation = toScriptLocation(result.actualLocation);
|
|
719
|
+
const wrongLocation = actualLocation !== void 0 && !isSameScriptLocation(input.location, actualLocation);
|
|
720
|
+
if (breakpointId.length === 0 || actualLocation === void 0 || wrongLocation) {
|
|
721
|
+
if (breakpointId.length > 0) {
|
|
722
|
+
try {
|
|
723
|
+
await removeBreakpoint(session, breakpointId);
|
|
724
|
+
} catch {
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
if (wrongLocation) {
|
|
728
|
+
throw new CfInspectorError(
|
|
729
|
+
"INVALID_BREAKPOINT",
|
|
730
|
+
"Debugger.setBreakpoint resolved the breakpoint at a different script, line, or column"
|
|
731
|
+
);
|
|
732
|
+
}
|
|
733
|
+
throw new CfInspectorError(
|
|
734
|
+
"CDP_REQUEST_FAILED",
|
|
735
|
+
"Debugger.setBreakpoint did not return a breakpointId and actualLocation"
|
|
736
|
+
);
|
|
737
|
+
}
|
|
738
|
+
return {
|
|
739
|
+
breakpointId,
|
|
740
|
+
requestedLocation: input.location,
|
|
741
|
+
actualLocation
|
|
742
|
+
};
|
|
743
|
+
}
|
|
473
744
|
|
|
474
745
|
// src/inspector/discovery.ts
|
|
475
746
|
init_types();
|
|
476
747
|
import { request } from "http";
|
|
748
|
+
import { performance } from "perf_hooks";
|
|
749
|
+
var InvalidDiscoveryPayloadError = class extends CfInspectorError {
|
|
750
|
+
};
|
|
477
751
|
async function fetchJson(url, timeoutMs) {
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
752
|
+
const deadline = performance.now() + timeoutMs;
|
|
753
|
+
let lastError;
|
|
754
|
+
while (performance.now() < deadline) {
|
|
755
|
+
try {
|
|
756
|
+
const remainingMs = deadline - performance.now();
|
|
757
|
+
if (remainingMs <= 0) {
|
|
758
|
+
break;
|
|
759
|
+
}
|
|
760
|
+
return await new Promise((resolve, reject) => {
|
|
761
|
+
const req = request(url, { method: "GET" }, (res) => {
|
|
762
|
+
const chunks = [];
|
|
763
|
+
res.on("data", (chunk) => {
|
|
764
|
+
chunks.push(chunk);
|
|
765
|
+
});
|
|
766
|
+
res.on("end", () => {
|
|
767
|
+
try {
|
|
768
|
+
resolve(parseJsonResponse(chunks));
|
|
769
|
+
} catch (err) {
|
|
770
|
+
reject(parseDiscoveryError(url, err));
|
|
771
|
+
}
|
|
772
|
+
});
|
|
773
|
+
res.on("error", (err) => {
|
|
774
|
+
reject(newDiscoveryError(`Inspector discovery response error: ${err.message}`));
|
|
775
|
+
});
|
|
776
|
+
});
|
|
777
|
+
const attemptTimeoutMs = Math.min(2e3, remainingMs);
|
|
778
|
+
req.setTimeout(attemptTimeoutMs, () => {
|
|
779
|
+
req.destroy(
|
|
780
|
+
new CfInspectorError(
|
|
781
|
+
"INSPECTOR_DISCOVERY_FAILED",
|
|
782
|
+
`Inspector discovery at ${url} timed out after ${timeoutMs.toString()}ms`
|
|
783
|
+
)
|
|
784
|
+
);
|
|
785
|
+
});
|
|
786
|
+
req.on("error", (err) => {
|
|
787
|
+
reject(err instanceof CfInspectorError ? err : formatDiscoveryRequestError(url, err));
|
|
788
|
+
});
|
|
789
|
+
req.end();
|
|
493
790
|
});
|
|
494
|
-
})
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
791
|
+
} catch (err) {
|
|
792
|
+
if (err instanceof InvalidDiscoveryPayloadError) {
|
|
793
|
+
throw err;
|
|
794
|
+
}
|
|
795
|
+
lastError = err;
|
|
796
|
+
const now = performance.now();
|
|
797
|
+
if (now < deadline) {
|
|
798
|
+
const sleepMs = Math.min(1e3, deadline - now);
|
|
799
|
+
await new Promise((r) => setTimeout(r, sleepMs));
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
if (lastError instanceof Error) {
|
|
804
|
+
throw lastError;
|
|
805
|
+
}
|
|
806
|
+
throw new CfInspectorError("INSPECTOR_DISCOVERY_FAILED", `Inspector discovery at ${url} timed out after ${timeoutMs.toString()}ms`);
|
|
508
807
|
}
|
|
509
808
|
function isNodeSystemError(err) {
|
|
510
809
|
return err instanceof Error;
|
|
@@ -540,7 +839,10 @@ function parseJsonResponse(chunks) {
|
|
|
540
839
|
}
|
|
541
840
|
function parseDiscoveryError(url, err) {
|
|
542
841
|
const message = err instanceof Error ? err.message : String(err);
|
|
543
|
-
return
|
|
842
|
+
return new InvalidDiscoveryPayloadError(
|
|
843
|
+
"INSPECTOR_DISCOVERY_FAILED",
|
|
844
|
+
`Failed to parse inspector discovery response from ${url}: ${message}`
|
|
845
|
+
);
|
|
544
846
|
}
|
|
545
847
|
function newDiscoveryError(message) {
|
|
546
848
|
return new CfInspectorError("INSPECTOR_DISCOVERY_FAILED", message);
|
|
@@ -614,7 +916,7 @@ async function fetchInspectorVersion(host, port, timeoutMs) {
|
|
|
614
916
|
|
|
615
917
|
// src/inspector/pause.ts
|
|
616
918
|
init_types();
|
|
617
|
-
import { performance } from "perf_hooks";
|
|
919
|
+
import { performance as performance2 } from "perf_hooks";
|
|
618
920
|
function pauseMatches(pause, breakpointIds, pauseReasons) {
|
|
619
921
|
if (pauseReasons !== void 0 && pauseReasons.length > 0) {
|
|
620
922
|
return pauseReasons.includes(pause.reason);
|
|
@@ -625,7 +927,12 @@ function pauseMatches(pause, breakpointIds, pauseReasons) {
|
|
|
625
927
|
return pause.hitBreakpoints.some((id) => breakpointIds.includes(id));
|
|
626
928
|
}
|
|
627
929
|
function remainingUntil(deadlineMs) {
|
|
628
|
-
return Math.max(0, deadlineMs -
|
|
930
|
+
return Math.max(0, deadlineMs - performance2.now());
|
|
931
|
+
}
|
|
932
|
+
function throwIfAborted(signal) {
|
|
933
|
+
if (signal?.aborted === true) {
|
|
934
|
+
throw new CfInspectorError("ABORTED", "Aborted while waiting for Debugger.paused");
|
|
935
|
+
}
|
|
629
936
|
}
|
|
630
937
|
function hasResumedSincePause(session, pause) {
|
|
631
938
|
const pauseAt = pause.receivedAtMs;
|
|
@@ -645,20 +952,23 @@ function throwUnrelatedPauseTimeout(pause, timeoutMs) {
|
|
|
645
952
|
pauseDetail(pause)
|
|
646
953
|
);
|
|
647
954
|
}
|
|
648
|
-
async function waitForUnmatchedPauseToResume(session, pause, deadlineMs,
|
|
955
|
+
async function waitForUnmatchedPauseToResume(session, pause, deadlineMs, options) {
|
|
649
956
|
if (hasResumedSincePause(session, pause)) {
|
|
650
957
|
return;
|
|
651
958
|
}
|
|
652
959
|
const remainingMs = remainingUntil(deadlineMs);
|
|
653
960
|
if (remainingMs <= 0) {
|
|
654
|
-
throwUnrelatedPauseTimeout(pause, timeoutMs);
|
|
961
|
+
throwUnrelatedPauseTimeout(pause, options.timeoutMs);
|
|
655
962
|
}
|
|
656
963
|
try {
|
|
657
|
-
await session.client.waitFor("Debugger.resumed", {
|
|
658
|
-
|
|
964
|
+
await session.client.waitFor("Debugger.resumed", {
|
|
965
|
+
timeoutMs: remainingMs,
|
|
966
|
+
...options.signal === void 0 ? {} : { signal: options.signal }
|
|
967
|
+
});
|
|
968
|
+
session.debuggerState.lastResumedAtMs = performance2.now();
|
|
659
969
|
} catch (err) {
|
|
660
970
|
if (err instanceof CfInspectorError && err.code === "BREAKPOINT_NOT_HIT") {
|
|
661
|
-
throwUnrelatedPauseTimeout(pause, timeoutMs);
|
|
971
|
+
throwUnrelatedPauseTimeout(pause, options.timeoutMs);
|
|
662
972
|
}
|
|
663
973
|
throw err;
|
|
664
974
|
}
|
|
@@ -675,13 +985,16 @@ async function handleUnmatchedPause(session, pause, options, deadlineMs) {
|
|
|
675
985
|
return;
|
|
676
986
|
}
|
|
677
987
|
options.onUnmatchedPause?.(pause);
|
|
678
|
-
await waitForUnmatchedPauseToResume(session, pause, deadlineMs, options
|
|
988
|
+
await waitForUnmatchedPauseToResume(session, pause, deadlineMs, options);
|
|
679
989
|
}
|
|
680
990
|
async function waitForPause(session, options) {
|
|
681
|
-
|
|
991
|
+
throwIfAborted(options.signal);
|
|
992
|
+
const deadlineMs = performance2.now() + options.timeoutMs;
|
|
682
993
|
const buffer = session.pauseBuffer;
|
|
683
994
|
while (buffer.length > 0 || remainingUntil(deadlineMs) > 0) {
|
|
995
|
+
throwIfAborted(options.signal);
|
|
684
996
|
while (buffer.length > 0) {
|
|
997
|
+
throwIfAborted(options.signal);
|
|
685
998
|
const buffered = buffer.shift();
|
|
686
999
|
if (buffered === void 0) {
|
|
687
1000
|
continue;
|
|
@@ -710,15 +1023,16 @@ async function waitForLivePause(session, options, deadlineMs) {
|
|
|
710
1023
|
try {
|
|
711
1024
|
params = await session.client.waitFor("Debugger.paused", {
|
|
712
1025
|
timeoutMs: remainingMs,
|
|
1026
|
+
...options.signal === void 0 ? {} : { signal: options.signal },
|
|
713
1027
|
predicate: () => {
|
|
714
|
-
receivedAtMs =
|
|
1028
|
+
receivedAtMs = performance2.now();
|
|
715
1029
|
return true;
|
|
716
1030
|
}
|
|
717
1031
|
});
|
|
718
1032
|
} finally {
|
|
719
1033
|
session.pauseWaitGate.active = false;
|
|
720
1034
|
}
|
|
721
|
-
return toPauseEvent(params, receivedAtMs ??
|
|
1035
|
+
return toPauseEvent(params, receivedAtMs ?? performance2.now(), session.scripts);
|
|
722
1036
|
}
|
|
723
1037
|
|
|
724
1038
|
// src/inspector/runtime.ts
|
|
@@ -729,15 +1043,31 @@ async function resume(session) {
|
|
|
729
1043
|
async function setPauseOnExceptions(session, state) {
|
|
730
1044
|
await session.client.send("Debugger.setPauseOnExceptions", { state });
|
|
731
1045
|
}
|
|
732
|
-
async function evaluateOnFrame(session, callFrameId, expression) {
|
|
1046
|
+
async function evaluateOnFrame(session, callFrameId, expression, options = {}) {
|
|
733
1047
|
return await session.client.send("Debugger.evaluateOnCallFrame", {
|
|
734
1048
|
callFrameId,
|
|
735
1049
|
expression,
|
|
736
1050
|
returnByValue: false,
|
|
737
1051
|
generatePreview: true,
|
|
738
|
-
silent: true
|
|
1052
|
+
silent: true,
|
|
1053
|
+
...options.throwOnSideEffect === void 0 ? {} : { throwOnSideEffect: options.throwOnSideEffect },
|
|
1054
|
+
...options.objectGroup === void 0 ? {} : { objectGroup: options.objectGroup }
|
|
739
1055
|
});
|
|
740
1056
|
}
|
|
1057
|
+
function isSideEffectRefusal(result) {
|
|
1058
|
+
const classNames = [
|
|
1059
|
+
result.result?.className,
|
|
1060
|
+
result.exceptionDetails?.exception?.className
|
|
1061
|
+
];
|
|
1062
|
+
const descriptions = [
|
|
1063
|
+
result.result?.description,
|
|
1064
|
+
result.exceptionDetails?.exception?.description
|
|
1065
|
+
];
|
|
1066
|
+
const isEvalError = classNames.includes("EvalError");
|
|
1067
|
+
return isEvalError && descriptions.some(
|
|
1068
|
+
(description) => typeof description === "string" && description.toLowerCase().includes("possible side-effect in debug-evaluate")
|
|
1069
|
+
);
|
|
1070
|
+
}
|
|
741
1071
|
async function evaluateGlobal(session, expression) {
|
|
742
1072
|
return await session.client.send("Runtime.evaluate", {
|
|
743
1073
|
expression,
|
|
@@ -787,9 +1117,42 @@ async function getProperties(session, objectId) {
|
|
|
787
1117
|
}
|
|
788
1118
|
return result.result;
|
|
789
1119
|
}
|
|
1120
|
+
async function getScriptSource(session, scriptId) {
|
|
1121
|
+
if (scriptId.trim().length === 0) {
|
|
1122
|
+
throw new CfInspectorError("INVALID_ARGUMENT", "scriptId must not be empty");
|
|
1123
|
+
}
|
|
1124
|
+
const result = await session.client.send(
|
|
1125
|
+
"Debugger.getScriptSource",
|
|
1126
|
+
{ scriptId }
|
|
1127
|
+
);
|
|
1128
|
+
if (typeof result.scriptSource !== "string") {
|
|
1129
|
+
throw new CfInspectorError(
|
|
1130
|
+
"CDP_REQUEST_FAILED",
|
|
1131
|
+
"Debugger.getScriptSource did not return scriptSource"
|
|
1132
|
+
);
|
|
1133
|
+
}
|
|
1134
|
+
return result.scriptSource;
|
|
1135
|
+
}
|
|
1136
|
+
async function stepInto(session, options = {}) {
|
|
1137
|
+
await session.client.send("Debugger.stepInto", {
|
|
1138
|
+
...options.breakOnAsyncCall === void 0 ? {} : { breakOnAsyncCall: options.breakOnAsyncCall }
|
|
1139
|
+
});
|
|
1140
|
+
}
|
|
1141
|
+
async function stepOver(session) {
|
|
1142
|
+
await session.client.send("Debugger.stepOver");
|
|
1143
|
+
}
|
|
1144
|
+
async function stepOut(session) {
|
|
1145
|
+
await session.client.send("Debugger.stepOut");
|
|
1146
|
+
}
|
|
1147
|
+
async function releaseObject(session, objectId) {
|
|
1148
|
+
await session.client.send("Runtime.releaseObject", { objectId });
|
|
1149
|
+
}
|
|
1150
|
+
async function releaseObjectGroup(session, objectGroup) {
|
|
1151
|
+
await session.client.send("Runtime.releaseObjectGroup", { objectGroup });
|
|
1152
|
+
}
|
|
790
1153
|
|
|
791
1154
|
// src/inspector/session.ts
|
|
792
|
-
import { performance as
|
|
1155
|
+
import { performance as performance3 } from "perf_hooks";
|
|
793
1156
|
|
|
794
1157
|
// src/cdp/client.ts
|
|
795
1158
|
init_types();
|
|
@@ -892,54 +1255,70 @@ var CdpClient = class _CdpClient {
|
|
|
892
1255
|
if (this.closed) {
|
|
893
1256
|
throw this.closeReason ?? new CfInspectorError("INSPECTOR_CONNECTION_FAILED", "Connection closed");
|
|
894
1257
|
}
|
|
895
|
-
|
|
1258
|
+
if (options.signal?.aborted === true) {
|
|
1259
|
+
throw this.createWaitAbortError(method);
|
|
1260
|
+
}
|
|
1261
|
+
return await this.createEventWait(method, options);
|
|
1262
|
+
}
|
|
1263
|
+
createEventWait(method, options) {
|
|
1264
|
+
return new Promise((resolve, reject) => {
|
|
896
1265
|
let settled = false;
|
|
1266
|
+
let offEvent = () => void 0;
|
|
1267
|
+
let offClose = () => void 0;
|
|
897
1268
|
const cleanup = () => {
|
|
898
1269
|
clearTimeout(timer);
|
|
899
1270
|
offEvent();
|
|
900
1271
|
offClose();
|
|
1272
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
901
1273
|
};
|
|
902
|
-
const
|
|
1274
|
+
const resolveOnce = (value) => {
|
|
1275
|
+
if (settled) {
|
|
1276
|
+
return;
|
|
1277
|
+
}
|
|
903
1278
|
settled = true;
|
|
904
1279
|
cleanup();
|
|
905
1280
|
resolve(value);
|
|
906
1281
|
};
|
|
907
|
-
const
|
|
908
|
-
if (settled) {
|
|
909
|
-
return;
|
|
910
|
-
}
|
|
911
|
-
const params = raw;
|
|
912
|
-
if (options.predicate) {
|
|
913
|
-
let accepted;
|
|
914
|
-
try {
|
|
915
|
-
accepted = options.predicate(params);
|
|
916
|
-
} catch {
|
|
917
|
-
return;
|
|
918
|
-
}
|
|
919
|
-
if (!accepted) {
|
|
920
|
-
return;
|
|
921
|
-
}
|
|
922
|
-
}
|
|
923
|
-
finish(params);
|
|
924
|
-
});
|
|
925
|
-
const offClose = this.onClose((err) => {
|
|
1282
|
+
const rejectOnce = (error) => {
|
|
926
1283
|
if (settled) {
|
|
927
1284
|
return;
|
|
928
1285
|
}
|
|
929
1286
|
settled = true;
|
|
930
1287
|
cleanup();
|
|
931
|
-
reject(
|
|
932
|
-
}
|
|
1288
|
+
reject(error);
|
|
1289
|
+
};
|
|
1290
|
+
const onAbort = () => {
|
|
1291
|
+
rejectOnce(this.createWaitAbortError(method));
|
|
1292
|
+
};
|
|
933
1293
|
const timer = setTimeout(() => {
|
|
934
|
-
|
|
1294
|
+
rejectOnce(this.createWaitTimeoutError(method, options.timeoutMs));
|
|
1295
|
+
}, options.timeoutMs);
|
|
1296
|
+
offEvent = this.on(method, (raw) => {
|
|
1297
|
+
const params = raw;
|
|
1298
|
+
if (!this.eventMatches(params, options.predicate)) {
|
|
935
1299
|
return;
|
|
936
1300
|
}
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
1301
|
+
resolveOnce(params);
|
|
1302
|
+
});
|
|
1303
|
+
offClose = this.onClose((error) => {
|
|
1304
|
+
rejectOnce(error);
|
|
1305
|
+
});
|
|
1306
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
1307
|
+
if (options.signal?.aborted === true) {
|
|
1308
|
+
onAbort();
|
|
1309
|
+
}
|
|
941
1310
|
});
|
|
942
1311
|
}
|
|
1312
|
+
eventMatches(params, predicate) {
|
|
1313
|
+
if (predicate === void 0) {
|
|
1314
|
+
return true;
|
|
1315
|
+
}
|
|
1316
|
+
try {
|
|
1317
|
+
return predicate(params);
|
|
1318
|
+
} catch {
|
|
1319
|
+
return false;
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
943
1322
|
onClose(listener) {
|
|
944
1323
|
if (this.closed) {
|
|
945
1324
|
const reason = this.closeReason ?? new CfInspectorError("INSPECTOR_CONNECTION_FAILED", "Connection closed");
|
|
@@ -1006,6 +1385,9 @@ var CdpClient = class _CdpClient {
|
|
|
1006
1385
|
`Timed out waiting for ${method} after ${timeoutMs.toString()}ms`
|
|
1007
1386
|
);
|
|
1008
1387
|
}
|
|
1388
|
+
createWaitAbortError(method) {
|
|
1389
|
+
return new CfInspectorError("ABORTED", `Aborted while waiting for ${method}`);
|
|
1390
|
+
}
|
|
1009
1391
|
sendPayload(id, method, payload, timer, reject) {
|
|
1010
1392
|
try {
|
|
1011
1393
|
this.transport.send(payload);
|
|
@@ -1031,12 +1413,203 @@ var CdpClient = class _CdpClient {
|
|
|
1031
1413
|
this.emitter.removeAllListeners();
|
|
1032
1414
|
}
|
|
1033
1415
|
};
|
|
1416
|
+
var NodeWorkerTransport = class {
|
|
1417
|
+
constructor(parent, sessionId) {
|
|
1418
|
+
this.parent = parent;
|
|
1419
|
+
this.sessionId = sessionId;
|
|
1420
|
+
this.detachParentListeners = [
|
|
1421
|
+
parent.on("NodeWorker.receivedMessageFromWorker", (raw) => {
|
|
1422
|
+
this.forwardWorkerMessage(raw);
|
|
1423
|
+
}),
|
|
1424
|
+
parent.on("NodeWorker.detachedFromWorker", (raw) => {
|
|
1425
|
+
this.handleWorkerDetach(raw);
|
|
1426
|
+
}),
|
|
1427
|
+
parent.onClose((error) => {
|
|
1428
|
+
this.closeWithError(error);
|
|
1429
|
+
})
|
|
1430
|
+
];
|
|
1431
|
+
}
|
|
1432
|
+
parent;
|
|
1433
|
+
sessionId;
|
|
1434
|
+
emitter = new EventEmitter();
|
|
1435
|
+
detachParentListeners;
|
|
1436
|
+
readyState = 1;
|
|
1437
|
+
send(payload) {
|
|
1438
|
+
if (this.readyState !== 1) {
|
|
1439
|
+
throw new CfInspectorError("INSPECTOR_CONNECTION_FAILED", "Worker inspector session is closed");
|
|
1440
|
+
}
|
|
1441
|
+
void this.parent.send("NodeWorker.sendMessageToWorker", {
|
|
1442
|
+
sessionId: this.sessionId,
|
|
1443
|
+
message: payload
|
|
1444
|
+
}).catch((error) => {
|
|
1445
|
+
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
1446
|
+
this.closeWithError(normalized);
|
|
1447
|
+
});
|
|
1448
|
+
}
|
|
1449
|
+
close() {
|
|
1450
|
+
this.finishClose();
|
|
1451
|
+
}
|
|
1452
|
+
on(event, listener) {
|
|
1453
|
+
this.emitter.on(event, listener);
|
|
1454
|
+
}
|
|
1455
|
+
off(event, listener) {
|
|
1456
|
+
this.emitter.off(event, listener);
|
|
1457
|
+
}
|
|
1458
|
+
forwardWorkerMessage(raw) {
|
|
1459
|
+
const params = asNodeWorkerEventParams(raw);
|
|
1460
|
+
if (params.sessionId !== this.sessionId || typeof params.message !== "string") {
|
|
1461
|
+
return;
|
|
1462
|
+
}
|
|
1463
|
+
this.emitter.emit("message", params.message);
|
|
1464
|
+
}
|
|
1465
|
+
handleWorkerDetach(raw) {
|
|
1466
|
+
const params = asNodeWorkerEventParams(raw);
|
|
1467
|
+
if (params.sessionId === this.sessionId) {
|
|
1468
|
+
this.finishClose();
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
closeWithError(error) {
|
|
1472
|
+
if (this.readyState !== 1) {
|
|
1473
|
+
return;
|
|
1474
|
+
}
|
|
1475
|
+
this.emitter.emit("error", error);
|
|
1476
|
+
this.finishClose();
|
|
1477
|
+
}
|
|
1478
|
+
finishClose() {
|
|
1479
|
+
if (this.readyState !== 1) {
|
|
1480
|
+
return;
|
|
1481
|
+
}
|
|
1482
|
+
this.readyState = 3;
|
|
1483
|
+
for (const detach of this.detachParentListeners) {
|
|
1484
|
+
detach();
|
|
1485
|
+
}
|
|
1486
|
+
this.emitter.emit("close");
|
|
1487
|
+
this.emitter.removeAllListeners();
|
|
1488
|
+
}
|
|
1489
|
+
};
|
|
1490
|
+
function asNodeWorkerEventParams(raw) {
|
|
1491
|
+
if (!isUnknownRecord(raw)) {
|
|
1492
|
+
return {};
|
|
1493
|
+
}
|
|
1494
|
+
const sessionId = raw["sessionId"];
|
|
1495
|
+
const message = raw["message"];
|
|
1496
|
+
return {
|
|
1497
|
+
...typeof sessionId === "string" ? { sessionId } : {},
|
|
1498
|
+
...typeof message === "string" ? { message } : {}
|
|
1499
|
+
};
|
|
1500
|
+
}
|
|
1501
|
+
function isUnknownRecord(value) {
|
|
1502
|
+
return typeof value === "object" && value !== null;
|
|
1503
|
+
}
|
|
1504
|
+
async function createNodeWorkerClient(parent, sessionId, requestTimeoutMs = DEFAULT_REQUEST_TIMEOUT_MS) {
|
|
1505
|
+
const transport = new NodeWorkerTransport(parent, sessionId);
|
|
1506
|
+
return await CdpClient.connect({
|
|
1507
|
+
url: `node-worker://${sessionId}`,
|
|
1508
|
+
transportFactory: () => Promise.resolve(transport),
|
|
1509
|
+
requestTimeoutMs
|
|
1510
|
+
});
|
|
1511
|
+
}
|
|
1034
1512
|
|
|
1035
1513
|
// src/inspector/session.ts
|
|
1036
1514
|
init_types();
|
|
1037
1515
|
var DEFAULT_CONNECT_TIMEOUT_MS = 5e3;
|
|
1038
1516
|
var DEFAULT_HOST = "127.0.0.1";
|
|
1039
1517
|
var PAUSE_BUFFER_LIMIT = 32;
|
|
1518
|
+
var NodeWorkerDiscovery = class {
|
|
1519
|
+
constructor(client) {
|
|
1520
|
+
this.client = client;
|
|
1521
|
+
this.detachListeners = [
|
|
1522
|
+
client.on("NodeWorker.attachedToWorker", (raw) => {
|
|
1523
|
+
const worker = toInspectorWorkerTarget(raw);
|
|
1524
|
+
if (worker !== void 0) {
|
|
1525
|
+
this.workers.set(worker.sessionId, worker);
|
|
1526
|
+
}
|
|
1527
|
+
}),
|
|
1528
|
+
client.on("NodeWorker.detachedFromWorker", (raw) => {
|
|
1529
|
+
const sessionId = readField(raw, "sessionId");
|
|
1530
|
+
if (typeof sessionId === "string") {
|
|
1531
|
+
this.workers.delete(sessionId);
|
|
1532
|
+
}
|
|
1533
|
+
})
|
|
1534
|
+
];
|
|
1535
|
+
}
|
|
1536
|
+
client;
|
|
1537
|
+
workers = /* @__PURE__ */ new Map();
|
|
1538
|
+
detachListeners;
|
|
1539
|
+
supported = false;
|
|
1540
|
+
disposed = false;
|
|
1541
|
+
async enable() {
|
|
1542
|
+
try {
|
|
1543
|
+
await this.client.send("NodeWorker.enable", { waitForDebuggerOnStart: false });
|
|
1544
|
+
this.supported = true;
|
|
1545
|
+
} catch (error) {
|
|
1546
|
+
if (!isUnsupportedNodeWorkerDomain(error)) {
|
|
1547
|
+
throw error;
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
list() {
|
|
1552
|
+
return [...this.workers.values()].sort(compareWorkers);
|
|
1553
|
+
}
|
|
1554
|
+
async dispose() {
|
|
1555
|
+
if (this.disposed) {
|
|
1556
|
+
return;
|
|
1557
|
+
}
|
|
1558
|
+
this.disposed = true;
|
|
1559
|
+
if (this.supported && !this.client.isClosed) {
|
|
1560
|
+
try {
|
|
1561
|
+
await this.client.send("NodeWorker.disable");
|
|
1562
|
+
} catch {
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
for (const detach of this.detachListeners) {
|
|
1566
|
+
detach();
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
};
|
|
1570
|
+
function isUnsupportedNodeWorkerDomain(error) {
|
|
1571
|
+
if (!(error instanceof CfInspectorError) || error.code !== "CDP_REQUEST_FAILED") {
|
|
1572
|
+
return false;
|
|
1573
|
+
}
|
|
1574
|
+
return error.detail?.includes('"code":-32601') === true;
|
|
1575
|
+
}
|
|
1576
|
+
function compareWorkers(left, right) {
|
|
1577
|
+
const leftId = Number.parseInt(left.workerId, 10);
|
|
1578
|
+
const rightId = Number.parseInt(right.workerId, 10);
|
|
1579
|
+
if (!Number.isNaN(leftId) && !Number.isNaN(rightId) && leftId !== rightId) {
|
|
1580
|
+
return leftId - rightId;
|
|
1581
|
+
}
|
|
1582
|
+
return left.workerId.localeCompare(right.workerId);
|
|
1583
|
+
}
|
|
1584
|
+
function toInspectorWorkerTarget(raw) {
|
|
1585
|
+
const sessionId = readField(raw, "sessionId");
|
|
1586
|
+
const info = readField(raw, "workerInfo");
|
|
1587
|
+
if (typeof sessionId !== "string" || !isUnknownRecord2(info)) {
|
|
1588
|
+
return void 0;
|
|
1589
|
+
}
|
|
1590
|
+
const workerId = asString(info["workerId"]);
|
|
1591
|
+
if (workerId.length === 0) {
|
|
1592
|
+
return void 0;
|
|
1593
|
+
}
|
|
1594
|
+
return {
|
|
1595
|
+
sessionId,
|
|
1596
|
+
workerId,
|
|
1597
|
+
type: asString(info["type"]),
|
|
1598
|
+
title: asString(info["title"]),
|
|
1599
|
+
url: asString(info["url"])
|
|
1600
|
+
};
|
|
1601
|
+
}
|
|
1602
|
+
function readField(value, name) {
|
|
1603
|
+
return isUnknownRecord2(value) ? value[name] : void 0;
|
|
1604
|
+
}
|
|
1605
|
+
function isUnknownRecord2(value) {
|
|
1606
|
+
return typeof value === "object" && value !== null;
|
|
1607
|
+
}
|
|
1608
|
+
async function startNodeWorkerDiscovery(client) {
|
|
1609
|
+
const discovery = new NodeWorkerDiscovery(client);
|
|
1610
|
+
await discovery.enable();
|
|
1611
|
+
return discovery;
|
|
1612
|
+
}
|
|
1040
1613
|
async function connectInspector(options) {
|
|
1041
1614
|
const host = options.host ?? DEFAULT_HOST;
|
|
1042
1615
|
const connectTimeoutMs = options.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS;
|
|
@@ -1053,43 +1626,105 @@ async function connectInspector(options) {
|
|
|
1053
1626
|
url: target.webSocketDebuggerUrl,
|
|
1054
1627
|
connectTimeoutMs
|
|
1055
1628
|
});
|
|
1629
|
+
let workerDiscovery;
|
|
1056
1630
|
try {
|
|
1057
|
-
|
|
1631
|
+
workerDiscovery = await startNodeWorkerDiscovery(client);
|
|
1632
|
+
if (options.workerIndex === void 0) {
|
|
1633
|
+
const session = await initSession(client, target);
|
|
1634
|
+
return withWorkerMetadata(session, workerDiscovery, targetIndex, targets.length);
|
|
1635
|
+
}
|
|
1636
|
+
return await initWorkerSession(
|
|
1637
|
+
client,
|
|
1638
|
+
workerDiscovery,
|
|
1639
|
+
options.workerIndex,
|
|
1640
|
+
targetIndex,
|
|
1641
|
+
targets.length
|
|
1642
|
+
);
|
|
1058
1643
|
} catch (err) {
|
|
1644
|
+
await workerDiscovery?.dispose();
|
|
1059
1645
|
client.dispose();
|
|
1060
1646
|
throw err;
|
|
1061
1647
|
}
|
|
1062
1648
|
}
|
|
1649
|
+
async function initWorkerSession(parent, discovery, workerIndex, targetIndex, targetCount) {
|
|
1650
|
+
const workers = discovery.list();
|
|
1651
|
+
if (!discovery.supported) {
|
|
1652
|
+
throw new CfInspectorError(
|
|
1653
|
+
"INSPECTOR_DISCOVERY_FAILED",
|
|
1654
|
+
"This runtime does not expose the NodeWorker CDP domain; --worker cannot be used. Run list-targets for available raw targets."
|
|
1655
|
+
);
|
|
1656
|
+
}
|
|
1657
|
+
const worker = workers[workerIndex];
|
|
1658
|
+
if (worker === void 0) {
|
|
1659
|
+
throw new CfInspectorError(
|
|
1660
|
+
"INSPECTOR_DISCOVERY_FAILED",
|
|
1661
|
+
`No NodeWorker sub-session at index ${workerIndex.toString()} (available: ${workers.length.toString()}). Ensure the worker is alive, then rerun list-targets.`
|
|
1662
|
+
);
|
|
1663
|
+
}
|
|
1664
|
+
const client = await createNodeWorkerClient(parent, worker.sessionId);
|
|
1665
|
+
const session = await initSession(client, workerToInspectorTarget(worker));
|
|
1666
|
+
return withWorkerMetadata(session, discovery, targetIndex, targetCount, workerIndex, parent);
|
|
1667
|
+
}
|
|
1668
|
+
function withWorkerMetadata(session, discovery, targetIndex, targetCount, workerIndex, parent) {
|
|
1669
|
+
return {
|
|
1670
|
+
...session,
|
|
1671
|
+
targetIndex,
|
|
1672
|
+
targetCount,
|
|
1673
|
+
...workerIndex === void 0 ? {} : { workerIndex },
|
|
1674
|
+
workerTargets: discovery.list(),
|
|
1675
|
+
workerDiscoverySupported: discovery.supported,
|
|
1676
|
+
dispose: async () => {
|
|
1677
|
+
await session.dispose();
|
|
1678
|
+
await discovery.dispose();
|
|
1679
|
+
parent?.dispose();
|
|
1680
|
+
}
|
|
1681
|
+
};
|
|
1682
|
+
}
|
|
1683
|
+
function workerToInspectorTarget(worker) {
|
|
1684
|
+
return {
|
|
1685
|
+
description: "Node worker sub-session",
|
|
1686
|
+
id: worker.workerId,
|
|
1687
|
+
title: worker.title,
|
|
1688
|
+
type: worker.type,
|
|
1689
|
+
url: worker.url,
|
|
1690
|
+
webSocketDebuggerUrl: `node-worker://${worker.sessionId}`
|
|
1691
|
+
};
|
|
1692
|
+
}
|
|
1063
1693
|
async function initSession(client, target) {
|
|
1064
1694
|
const scripts = /* @__PURE__ */ new Map();
|
|
1065
|
-
client
|
|
1066
|
-
const params = raw;
|
|
1067
|
-
const scriptId = asString(params.scriptId);
|
|
1068
|
-
const url = asString(params.url);
|
|
1069
|
-
if (scriptId.length === 0) {
|
|
1070
|
-
return;
|
|
1071
|
-
}
|
|
1072
|
-
scripts.set(scriptId, { scriptId, url });
|
|
1073
|
-
});
|
|
1695
|
+
registerScriptTracking(client, scripts);
|
|
1074
1696
|
const pauseBuffer = [];
|
|
1075
1697
|
const pauseWaitGate = { active: false };
|
|
1076
1698
|
const debuggerState = {};
|
|
1699
|
+
registerPauseTracking(client, scripts, pauseBuffer, pauseWaitGate, debuggerState);
|
|
1700
|
+
await client.send("Runtime.enable");
|
|
1701
|
+
await client.send("Debugger.enable");
|
|
1702
|
+
return createSession(client, target, scripts, pauseBuffer, pauseWaitGate, debuggerState);
|
|
1703
|
+
}
|
|
1704
|
+
function registerScriptTracking(client, scripts) {
|
|
1705
|
+
client.on("Debugger.scriptParsed", (raw) => {
|
|
1706
|
+
const script = toScriptInfo(raw);
|
|
1707
|
+
if (script !== void 0) {
|
|
1708
|
+
scripts.set(script.scriptId, script);
|
|
1709
|
+
}
|
|
1710
|
+
});
|
|
1711
|
+
}
|
|
1712
|
+
function registerPauseTracking(client, scripts, pauseBuffer, pauseWaitGate, debuggerState) {
|
|
1077
1713
|
client.on("Debugger.paused", (raw) => {
|
|
1078
1714
|
if (pauseWaitGate.active) {
|
|
1079
1715
|
return;
|
|
1080
1716
|
}
|
|
1081
|
-
const
|
|
1082
|
-
const event = toPauseEvent(params, performance2.now(), scripts);
|
|
1717
|
+
const event = toPauseEvent(raw, performance3.now(), scripts);
|
|
1083
1718
|
if (pauseBuffer.length >= PAUSE_BUFFER_LIMIT) {
|
|
1084
1719
|
pauseBuffer.shift();
|
|
1085
1720
|
}
|
|
1086
1721
|
pauseBuffer.push(event);
|
|
1087
1722
|
});
|
|
1088
1723
|
client.on("Debugger.resumed", () => {
|
|
1089
|
-
debuggerState.lastResumedAtMs =
|
|
1724
|
+
debuggerState.lastResumedAtMs = performance3.now();
|
|
1090
1725
|
});
|
|
1091
|
-
|
|
1092
|
-
|
|
1726
|
+
}
|
|
1727
|
+
function createSession(client, target, scripts, pauseBuffer, pauseWaitGate, debuggerState) {
|
|
1093
1728
|
return {
|
|
1094
1729
|
client,
|
|
1095
1730
|
target,
|
|
@@ -1107,9 +1742,61 @@ async function initSession(client, target) {
|
|
|
1107
1742
|
};
|
|
1108
1743
|
}
|
|
1109
1744
|
|
|
1745
|
+
// src/cli/captureParser.ts
|
|
1746
|
+
function isQuoteChar(value) {
|
|
1747
|
+
return value === "'" || value === '"' || value === "`";
|
|
1748
|
+
}
|
|
1749
|
+
function consumeQuotedChar(state, char) {
|
|
1750
|
+
if (state.quote === void 0) {
|
|
1751
|
+
return false;
|
|
1752
|
+
}
|
|
1753
|
+
if (state.escaped) {
|
|
1754
|
+
state.escaped = false;
|
|
1755
|
+
return true;
|
|
1756
|
+
}
|
|
1757
|
+
if (char === "\\") {
|
|
1758
|
+
state.escaped = true;
|
|
1759
|
+
return true;
|
|
1760
|
+
}
|
|
1761
|
+
if (char === state.quote) {
|
|
1762
|
+
state.quote = void 0;
|
|
1763
|
+
}
|
|
1764
|
+
return true;
|
|
1765
|
+
}
|
|
1766
|
+
function stripQuotedText(expression) {
|
|
1767
|
+
const state = { quote: void 0, escaped: false };
|
|
1768
|
+
let stripped = "";
|
|
1769
|
+
for (const char of expression) {
|
|
1770
|
+
if (consumeQuotedChar(state, char)) {
|
|
1771
|
+
stripped += " ";
|
|
1772
|
+
continue;
|
|
1773
|
+
}
|
|
1774
|
+
if (isQuoteChar(char)) {
|
|
1775
|
+
state.quote = char;
|
|
1776
|
+
stripped += " ";
|
|
1777
|
+
continue;
|
|
1778
|
+
}
|
|
1779
|
+
stripped += char;
|
|
1780
|
+
}
|
|
1781
|
+
return stripped;
|
|
1782
|
+
}
|
|
1783
|
+
function looksLikeMutation(expression) {
|
|
1784
|
+
const stripped = stripQuotedText(expression);
|
|
1785
|
+
const hasUpdate = /(?:\+\+|--)/u.test(stripped);
|
|
1786
|
+
const hasAssignment = /(?:\*\*=|&&=|\|\|=|\?\?=|[+\-*/%&|^]=|(?:^|[^=!<>])=(?!=|>))/u.test(stripped);
|
|
1787
|
+
const hasDelete = /\bdelete\b/u.test(stripped);
|
|
1788
|
+
const hasMutatingMethod = /\.\s*(?:push|pop|shift|unshift|splice|sort|reverse|fill|copyWithin|set|add|delete|clear)\s*\(/u.test(stripped);
|
|
1789
|
+
const hasObjectMutation = /\bObject\s*\.\s*(?:assign|defineProperty|defineProperties)\s*\(/u.test(stripped);
|
|
1790
|
+
return hasUpdate || hasAssignment || hasDelete || hasMutatingMethod || hasObjectMutation;
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
// src/snapshot/evaluation.ts
|
|
1794
|
+
init_types();
|
|
1795
|
+
|
|
1110
1796
|
// src/snapshot/values.ts
|
|
1111
1797
|
init_types();
|
|
1112
|
-
var DEFAULT_MAX_VALUE_LENGTH =
|
|
1798
|
+
var DEFAULT_MAX_VALUE_LENGTH = 131072;
|
|
1799
|
+
var DEFAULT_STREAM_MAX_VALUE_LENGTH = 4096;
|
|
1113
1800
|
function isPrimitive(value) {
|
|
1114
1801
|
const t = typeof value;
|
|
1115
1802
|
return t === "string" || t === "number" || t === "boolean" || t === "bigint" || t === "symbol";
|
|
@@ -1137,9 +1824,16 @@ function resolveMaxValueLength(value) {
|
|
|
1137
1824
|
}
|
|
1138
1825
|
function limitValueLength(raw, maxValueLength = DEFAULT_MAX_VALUE_LENGTH) {
|
|
1139
1826
|
if (raw.length <= maxValueLength) {
|
|
1140
|
-
return raw;
|
|
1827
|
+
return { text: raw, truncated: false };
|
|
1141
1828
|
}
|
|
1142
|
-
return
|
|
1829
|
+
return {
|
|
1830
|
+
text: raw.slice(0, maxValueLength),
|
|
1831
|
+
truncated: true,
|
|
1832
|
+
originalLength: raw.length
|
|
1833
|
+
};
|
|
1834
|
+
}
|
|
1835
|
+
function textTruncationFields(limited) {
|
|
1836
|
+
return limited.truncated ? { truncated: true, originalLength: limited.originalLength } : {};
|
|
1143
1837
|
}
|
|
1144
1838
|
function parseQuotedString(value) {
|
|
1145
1839
|
try {
|
|
@@ -1224,7 +1918,12 @@ function toStructuredValue(variable) {
|
|
|
1224
1918
|
// src/snapshot/evaluation.ts
|
|
1225
1919
|
function evalResultToCaptured(expression, result, maxValueLength = DEFAULT_MAX_VALUE_LENGTH) {
|
|
1226
1920
|
if (result.exceptionDetails !== void 0) {
|
|
1227
|
-
|
|
1921
|
+
const limited = readEvalError(result, maxValueLength);
|
|
1922
|
+
return {
|
|
1923
|
+
expression,
|
|
1924
|
+
error: limited.text,
|
|
1925
|
+
...textTruncationFields(limited)
|
|
1926
|
+
};
|
|
1228
1927
|
}
|
|
1229
1928
|
const inner = result.result;
|
|
1230
1929
|
if (!inner) {
|
|
@@ -1232,8 +1931,12 @@ function evalResultToCaptured(expression, result, maxValueLength = DEFAULT_MAX_V
|
|
|
1232
1931
|
}
|
|
1233
1932
|
const type = typeof inner.type === "string" ? inner.type : void 0;
|
|
1234
1933
|
const buildCaptured = (rendered) => {
|
|
1235
|
-
const
|
|
1236
|
-
const base = {
|
|
1934
|
+
const limited = limitValueLength(rendered, maxValueLength);
|
|
1935
|
+
const base = {
|
|
1936
|
+
expression,
|
|
1937
|
+
value: limited.text,
|
|
1938
|
+
...textTruncationFields(limited)
|
|
1939
|
+
};
|
|
1237
1940
|
return type === void 0 ? base : { ...base, type };
|
|
1238
1941
|
};
|
|
1239
1942
|
if (type === "string" && typeof inner.value === "string") {
|
|
@@ -1250,6 +1953,18 @@ function evalResultToCaptured(expression, result, maxValueLength = DEFAULT_MAX_V
|
|
|
1250
1953
|
}
|
|
1251
1954
|
return buildCaptured("undefined");
|
|
1252
1955
|
}
|
|
1956
|
+
function sideEffectRefusalToCaptured(expression) {
|
|
1957
|
+
const error = new CfInspectorError(
|
|
1958
|
+
"MUTATION_NOT_ALLOWED",
|
|
1959
|
+
`V8 blocked the capture expression "${expression}" because it may have side effects. Pass --allow-mutation to run it explicitly.`
|
|
1960
|
+
);
|
|
1961
|
+
return {
|
|
1962
|
+
expression,
|
|
1963
|
+
error: `${error.code}: ${error.message}`,
|
|
1964
|
+
mutationRisk: true,
|
|
1965
|
+
blocked: true
|
|
1966
|
+
};
|
|
1967
|
+
}
|
|
1253
1968
|
function readEvalError(result, maxValueLength) {
|
|
1254
1969
|
const text = typeof result.exceptionDetails?.exception?.description === "string" ? result.exceptionDetails.exception.description : typeof result.exceptionDetails?.text === "string" ? result.exceptionDetails.text : "evaluation failed";
|
|
1255
1970
|
return limitValueLength(text, maxValueLength);
|
|
@@ -1307,56 +2022,88 @@ async function captureProperties(session, objectId, limit, depth, maxValueLength
|
|
|
1307
2022
|
return await captureProperty(session, prop, depth, maxValueLength);
|
|
1308
2023
|
})
|
|
1309
2024
|
);
|
|
1310
|
-
|
|
2025
|
+
const omittedCount = Math.max(properties.length - limited.length, 0);
|
|
2026
|
+
return omittedCount === 0 ? { variables } : { variables, omittedCount };
|
|
1311
2027
|
}
|
|
1312
2028
|
async function captureProperty(session, prop, depth, maxValueLength) {
|
|
1313
2029
|
const name = typeof prop.name === "string" ? prop.name : "?";
|
|
1314
2030
|
const described = describeProperty(prop);
|
|
1315
|
-
const
|
|
1316
|
-
|
|
1317
|
-
|
|
2031
|
+
const capturedChildren = await capturePropertyChildren(
|
|
2032
|
+
session,
|
|
2033
|
+
described,
|
|
2034
|
+
depth,
|
|
2035
|
+
maxValueLength
|
|
2036
|
+
);
|
|
2037
|
+
const limited = limitValueLength(described.value, maxValueLength);
|
|
2038
|
+
const base = {
|
|
2039
|
+
name,
|
|
2040
|
+
value: limited.text,
|
|
2041
|
+
...textTruncationFields(limited)
|
|
2042
|
+
};
|
|
1318
2043
|
const withType = described.type === void 0 ? base : { ...base, type: described.type };
|
|
1319
|
-
|
|
2044
|
+
const children = capturedChildren?.variables;
|
|
2045
|
+
const withChildren = children === void 0 || children.length === 0 ? withType : { ...withType, children };
|
|
2046
|
+
const omittedCount = capturedChildren?.omittedCount ?? 0;
|
|
2047
|
+
return omittedCount === 0 ? withChildren : { ...withChildren, truncated: true, omittedCount };
|
|
1320
2048
|
}
|
|
1321
2049
|
async function capturePropertyChildren(session, described, depth, maxValueLength) {
|
|
1322
|
-
if (
|
|
2050
|
+
if (described.objectId === void 0 || !isExpandable(described.type)) {
|
|
1323
2051
|
return void 0;
|
|
1324
2052
|
}
|
|
2053
|
+
if (depth <= 0) {
|
|
2054
|
+
return await countDepthOmissions(session, described.objectId);
|
|
2055
|
+
}
|
|
1325
2056
|
try {
|
|
1326
|
-
|
|
2057
|
+
return await captureProperties(
|
|
1327
2058
|
session,
|
|
1328
2059
|
described.objectId,
|
|
1329
2060
|
MAX_CHILD_VARIABLES,
|
|
1330
2061
|
depth - 1,
|
|
1331
2062
|
maxValueLength
|
|
1332
2063
|
);
|
|
1333
|
-
return nested.length > 0 ? nested : void 0;
|
|
1334
2064
|
} catch {
|
|
1335
2065
|
return void 0;
|
|
1336
2066
|
}
|
|
1337
2067
|
}
|
|
2068
|
+
async function countDepthOmissions(session, objectId) {
|
|
2069
|
+
try {
|
|
2070
|
+
const properties = await getProperties(session, objectId);
|
|
2071
|
+
return properties.length === 0 ? void 0 : { variables: [], omittedCount: properties.length };
|
|
2072
|
+
} catch {
|
|
2073
|
+
return void 0;
|
|
2074
|
+
}
|
|
2075
|
+
}
|
|
2076
|
+
function countPropertyOmissions(captured) {
|
|
2077
|
+
return (captured.omittedCount ?? 0) + captured.variables.reduce((total, variable) => {
|
|
2078
|
+
const childOmissions = variable.children === void 0 ? 0 : countPropertyOmissions({ variables: variable.children });
|
|
2079
|
+
return total + (variable.omittedCount ?? 0) + childOmissions;
|
|
2080
|
+
}, 0);
|
|
2081
|
+
}
|
|
1338
2082
|
|
|
1339
2083
|
// src/snapshot/exception.ts
|
|
1340
2084
|
function asString2(value) {
|
|
1341
2085
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
1342
2086
|
}
|
|
1343
|
-
async function materializeObject(session, objectId
|
|
2087
|
+
async function materializeObject(session, objectId) {
|
|
1344
2088
|
try {
|
|
1345
|
-
const
|
|
2089
|
+
const captured = await captureProperties(
|
|
1346
2090
|
session,
|
|
1347
2091
|
objectId,
|
|
1348
2092
|
MAX_SCOPE_VARIABLES,
|
|
1349
2093
|
MAX_VARIABLE_DEPTH,
|
|
1350
|
-
|
|
2094
|
+
Number.MAX_SAFE_INTEGER
|
|
1351
2095
|
);
|
|
1352
|
-
if (
|
|
2096
|
+
if (captured.variables.length === 0) {
|
|
1353
2097
|
return void 0;
|
|
1354
2098
|
}
|
|
1355
2099
|
const structured = {};
|
|
1356
|
-
for (const variable of
|
|
2100
|
+
for (const variable of captured.variables) {
|
|
1357
2101
|
structured[variable.name] = toStructuredValue(variable);
|
|
1358
2102
|
}
|
|
1359
|
-
return
|
|
2103
|
+
return {
|
|
2104
|
+
value: JSON.stringify(structured),
|
|
2105
|
+
omittedCount: countPropertyOmissions(captured)
|
|
2106
|
+
};
|
|
1360
2107
|
} catch {
|
|
1361
2108
|
return void 0;
|
|
1362
2109
|
}
|
|
@@ -1409,18 +2156,44 @@ async function captureException(session, pause, maxValueLength) {
|
|
|
1409
2156
|
return { error: "exception data has no objectId or value" };
|
|
1410
2157
|
}
|
|
1411
2158
|
const message = await readPropertyDescription(session, objectId, "message");
|
|
1412
|
-
const rendered = await materializeObject(session, objectId
|
|
2159
|
+
const rendered = await materializeObject(session, objectId);
|
|
1413
2160
|
if (rendered !== void 0) {
|
|
1414
|
-
|
|
1415
|
-
|
|
2161
|
+
return buildResult(
|
|
2162
|
+
type,
|
|
2163
|
+
message ?? description,
|
|
2164
|
+
rendered.value,
|
|
2165
|
+
maxValueLength,
|
|
2166
|
+
rendered.omittedCount
|
|
2167
|
+
);
|
|
1416
2168
|
}
|
|
1417
2169
|
return buildResult(type, description, description ?? "[exception]", maxValueLength);
|
|
1418
2170
|
}
|
|
1419
|
-
function buildResult(type, description, value, maxValueLength) {
|
|
1420
|
-
const
|
|
1421
|
-
const
|
|
2171
|
+
function buildResult(type, description, value, maxValueLength, omittedCount = 0) {
|
|
2172
|
+
const limitedValue = limitValueLength(value, maxValueLength);
|
|
2173
|
+
const limitedDescription = description === void 0 ? void 0 : limitValueLength(description, maxValueLength);
|
|
2174
|
+
const base = {
|
|
2175
|
+
value: limitedValue.text,
|
|
2176
|
+
...exceptionTruncationFields(limitedValue, limitedDescription)
|
|
2177
|
+
};
|
|
1422
2178
|
const withType = type === void 0 ? base : { ...base, type };
|
|
1423
|
-
|
|
2179
|
+
const withDescription = limitedDescription === void 0 ? withType : { ...withType, description: limitedDescription.text };
|
|
2180
|
+
return omittedCount === 0 ? withDescription : { ...withDescription, truncated: true, omittedCount };
|
|
2181
|
+
}
|
|
2182
|
+
function exceptionTruncationFields(value, description) {
|
|
2183
|
+
const valueLength = value.truncated ? value.originalLength : void 0;
|
|
2184
|
+
const descriptionLength = description?.truncated === true ? description.originalLength : void 0;
|
|
2185
|
+
const lengths = [valueLength, descriptionLength].filter(
|
|
2186
|
+
(length) => length !== void 0
|
|
2187
|
+
);
|
|
2188
|
+
if (lengths.length === 0) {
|
|
2189
|
+
return {};
|
|
2190
|
+
}
|
|
2191
|
+
return {
|
|
2192
|
+
truncated: true,
|
|
2193
|
+
originalLength: Math.max(...lengths),
|
|
2194
|
+
...valueLength === void 0 ? {} : { valueOriginalLength: valueLength },
|
|
2195
|
+
...descriptionLength === void 0 ? {} : { descriptionOriginalLength: descriptionLength }
|
|
2196
|
+
};
|
|
1424
2197
|
}
|
|
1425
2198
|
|
|
1426
2199
|
// src/snapshot/objects.ts
|
|
@@ -1435,20 +2208,23 @@ function objectIdFromEvalResult(result) {
|
|
|
1435
2208
|
}
|
|
1436
2209
|
return objectId;
|
|
1437
2210
|
}
|
|
1438
|
-
async function renderObjectCapture(session, objectId
|
|
2211
|
+
async function renderObjectCapture(session, objectId) {
|
|
1439
2212
|
try {
|
|
1440
|
-
const
|
|
2213
|
+
const captured = await captureProperties(
|
|
1441
2214
|
session,
|
|
1442
2215
|
objectId,
|
|
1443
2216
|
MAX_SCOPE_VARIABLES,
|
|
1444
2217
|
MAX_VARIABLE_DEPTH,
|
|
1445
|
-
|
|
2218
|
+
Number.MAX_SAFE_INTEGER
|
|
1446
2219
|
);
|
|
1447
2220
|
const structured = {};
|
|
1448
|
-
for (const variable of
|
|
2221
|
+
for (const variable of captured.variables) {
|
|
1449
2222
|
structured[variable.name] = toStructuredValue(variable);
|
|
1450
2223
|
}
|
|
1451
|
-
return
|
|
2224
|
+
return {
|
|
2225
|
+
value: JSON.stringify(structured),
|
|
2226
|
+
omittedCount: countPropertyOmissions(captured)
|
|
2227
|
+
};
|
|
1452
2228
|
} catch {
|
|
1453
2229
|
return void 0;
|
|
1454
2230
|
}
|
|
@@ -1470,16 +2246,22 @@ async function withSerializedObjectCapture(session, expression, evalResult, capt
|
|
|
1470
2246
|
if (objectId === void 0) {
|
|
1471
2247
|
return captured;
|
|
1472
2248
|
}
|
|
1473
|
-
const rendered = await renderObjectCapture(session, objectId
|
|
2249
|
+
const rendered = await renderObjectCapture(session, objectId);
|
|
1474
2250
|
if (rendered === void 0) {
|
|
1475
2251
|
return captured;
|
|
1476
2252
|
}
|
|
1477
|
-
const normalized = normalizeRenderedObjectCapture(rendered, captured.value);
|
|
2253
|
+
const normalized = normalizeRenderedObjectCapture(rendered.value, captured.value);
|
|
1478
2254
|
if (normalized === void 0) {
|
|
1479
2255
|
return captured;
|
|
1480
2256
|
}
|
|
1481
|
-
const
|
|
1482
|
-
|
|
2257
|
+
const limited = limitValueLength(normalized, maxValueLength);
|
|
2258
|
+
const base = {
|
|
2259
|
+
expression,
|
|
2260
|
+
value: limited.text,
|
|
2261
|
+
...textTruncationFields(limited),
|
|
2262
|
+
...captured.type === void 0 ? {} : { type: captured.type }
|
|
2263
|
+
};
|
|
2264
|
+
return rendered.omittedCount === 0 ? base : { ...base, truncated: true, omittedCount: rendered.omittedCount };
|
|
1483
2265
|
}
|
|
1484
2266
|
|
|
1485
2267
|
// src/snapshot/scopes.ts
|
|
@@ -1494,35 +2276,39 @@ var PRIORITY_BY_TYPE = {
|
|
|
1494
2276
|
module: 6,
|
|
1495
2277
|
script: 7
|
|
1496
2278
|
};
|
|
1497
|
-
function
|
|
2279
|
+
function rankedScopes(scopeChain) {
|
|
1498
2280
|
const eligible = scopeChain.filter((scope) => scope.objectId !== void 0 && scope.type !== "global");
|
|
1499
|
-
return [...eligible].sort((a, b) => priorityOf(a.type) - priorityOf(b.type))
|
|
2281
|
+
return [...eligible].sort((a, b) => priorityOf(a.type) - priorityOf(b.type));
|
|
1500
2282
|
}
|
|
1501
2283
|
function priorityOf(type) {
|
|
1502
2284
|
return PRIORITY_BY_TYPE[type] ?? Number.MAX_SAFE_INTEGER;
|
|
1503
2285
|
}
|
|
1504
2286
|
async function captureScopes(session, frame, maxValueLength) {
|
|
1505
|
-
const
|
|
1506
|
-
|
|
2287
|
+
const ranked = rankedScopes(frame.scopeChain);
|
|
2288
|
+
const scopes = ranked.slice(0, MAX_SCOPES);
|
|
2289
|
+
const capturedScopes = await Promise.all(
|
|
1507
2290
|
scopes.map(async (scope) => {
|
|
1508
2291
|
const objectId = scope.objectId;
|
|
1509
2292
|
if (objectId === void 0) {
|
|
1510
2293
|
return { type: scope.type, variables: [] };
|
|
1511
2294
|
}
|
|
1512
2295
|
try {
|
|
1513
|
-
const
|
|
2296
|
+
const captured = await captureProperties(
|
|
1514
2297
|
session,
|
|
1515
2298
|
objectId,
|
|
1516
2299
|
MAX_SCOPE_VARIABLES,
|
|
1517
2300
|
MAX_VARIABLE_DEPTH,
|
|
1518
2301
|
maxValueLength
|
|
1519
2302
|
);
|
|
1520
|
-
|
|
2303
|
+
const base = { type: scope.type, variables: captured.variables };
|
|
2304
|
+
return captured.omittedCount === void 0 ? base : { ...base, truncated: true, omittedCount: captured.omittedCount };
|
|
1521
2305
|
} catch {
|
|
1522
2306
|
return { type: scope.type, variables: [] };
|
|
1523
2307
|
}
|
|
1524
2308
|
})
|
|
1525
2309
|
);
|
|
2310
|
+
const omittedCount = Math.max(ranked.length - capturedScopes.length, 0);
|
|
2311
|
+
return omittedCount === 0 ? { scopes: capturedScopes } : { scopes: capturedScopes, omittedCount };
|
|
1526
2312
|
}
|
|
1527
2313
|
|
|
1528
2314
|
// src/snapshot/stack.ts
|
|
@@ -1542,23 +2328,48 @@ function buildBaseFrame(frame) {
|
|
|
1542
2328
|
};
|
|
1543
2329
|
return frame.url === void 0 ? base : { ...base, url: frame.url };
|
|
1544
2330
|
}
|
|
1545
|
-
async function captureFrameExpression(session, callFrameId, expression, maxValueLength) {
|
|
2331
|
+
async function captureFrameExpression(session, callFrameId, expression, maxValueLength, throwOnSideEffect) {
|
|
2332
|
+
const mutationRisk = throwOnSideEffect === false && looksLikeMutation(expression);
|
|
1546
2333
|
try {
|
|
1547
|
-
const result = await evaluateOnFrame(session, callFrameId, expression
|
|
2334
|
+
const result = await evaluateOnFrame(session, callFrameId, expression, {
|
|
2335
|
+
...throwOnSideEffect === void 0 ? {} : { throwOnSideEffect }
|
|
2336
|
+
});
|
|
2337
|
+
if (isSideEffectRefusal(result)) {
|
|
2338
|
+
return sideEffectRefusalToCaptured(expression);
|
|
2339
|
+
}
|
|
1548
2340
|
const captured = evalResultToCaptured(expression, result, maxValueLength);
|
|
1549
|
-
|
|
2341
|
+
const serialized = await withSerializedObjectCapture(
|
|
2342
|
+
session,
|
|
2343
|
+
expression,
|
|
2344
|
+
result,
|
|
2345
|
+
captured,
|
|
2346
|
+
maxValueLength
|
|
2347
|
+
);
|
|
2348
|
+
return mutationRisk ? { ...serialized, mutationRisk: true } : serialized;
|
|
1550
2349
|
} catch (err) {
|
|
1551
2350
|
const message = err instanceof Error ? err.message : String(err);
|
|
1552
|
-
|
|
2351
|
+
const limited = limitValueLength(message, maxValueLength);
|
|
2352
|
+
const captured = {
|
|
2353
|
+
expression,
|
|
2354
|
+
error: limited.text,
|
|
2355
|
+
...textTruncationFields(limited)
|
|
2356
|
+
};
|
|
2357
|
+
return mutationRisk ? { ...captured, mutationRisk: true } : captured;
|
|
1553
2358
|
}
|
|
1554
2359
|
}
|
|
1555
|
-
async function captureFrameExpressions(session, frame, expressions, maxValueLength) {
|
|
2360
|
+
async function captureFrameExpressions(session, frame, expressions, maxValueLength, throwOnSideEffect) {
|
|
1556
2361
|
if (expressions.length === 0) {
|
|
1557
2362
|
return [];
|
|
1558
2363
|
}
|
|
1559
2364
|
return await Promise.all(
|
|
1560
2365
|
expressions.map(
|
|
1561
|
-
(expression) => captureFrameExpression(
|
|
2366
|
+
(expression) => captureFrameExpression(
|
|
2367
|
+
session,
|
|
2368
|
+
frame.callFrameId,
|
|
2369
|
+
expression,
|
|
2370
|
+
maxValueLength,
|
|
2371
|
+
throwOnSideEffect
|
|
2372
|
+
)
|
|
1562
2373
|
)
|
|
1563
2374
|
);
|
|
1564
2375
|
}
|
|
@@ -1578,7 +2389,8 @@ async function walkStack(session, callFrames, options) {
|
|
|
1578
2389
|
session,
|
|
1579
2390
|
frame,
|
|
1580
2391
|
options.stackCaptures,
|
|
1581
|
-
options.maxValueLength
|
|
2392
|
+
options.maxValueLength,
|
|
2393
|
+
options.throwOnSideEffect
|
|
1582
2394
|
);
|
|
1583
2395
|
return { ...base, captures };
|
|
1584
2396
|
})
|
|
@@ -1600,14 +2412,25 @@ async function captureSnapshot(session, pause, options = {}) {
|
|
|
1600
2412
|
column: top.columnNumber + 1
|
|
1601
2413
|
};
|
|
1602
2414
|
if (options.includeScopes === true) {
|
|
1603
|
-
const
|
|
1604
|
-
topFrame = {
|
|
2415
|
+
const capturedScopes = await captureScopes(session, top, maxValueLength);
|
|
2416
|
+
topFrame = {
|
|
2417
|
+
...topFrame,
|
|
2418
|
+
scopes: capturedScopes.scopes,
|
|
2419
|
+
...capturedScopes.omittedCount === void 0 ? {} : { truncated: true, omittedCount: capturedScopes.omittedCount }
|
|
2420
|
+
};
|
|
1605
2421
|
}
|
|
1606
|
-
captures = await captureExpressions(
|
|
2422
|
+
captures = await captureExpressions(
|
|
2423
|
+
session,
|
|
2424
|
+
top.callFrameId,
|
|
2425
|
+
options.captures,
|
|
2426
|
+
maxValueLength,
|
|
2427
|
+
options.throwOnSideEffect
|
|
2428
|
+
);
|
|
1607
2429
|
stack = await walkStack(session, pause.callFrames, {
|
|
1608
2430
|
stackDepth: options.stackDepth ?? DEFAULT_STACK_DEPTH,
|
|
1609
2431
|
stackCaptures: options.stackCaptures ?? [],
|
|
1610
|
-
maxValueLength
|
|
2432
|
+
maxValueLength,
|
|
2433
|
+
...options.throwOnSideEffect === void 0 ? {} : { throwOnSideEffect: options.throwOnSideEffect }
|
|
1611
2434
|
});
|
|
1612
2435
|
}
|
|
1613
2436
|
const exception = await captureException(session, pause, maxValueLength);
|
|
@@ -1630,24 +2453,49 @@ function buildResult2(input) {
|
|
|
1630
2453
|
const withStack = input.stack.length > 0 ? { ...withFrame, stack: input.stack } : withFrame;
|
|
1631
2454
|
return input.exception === void 0 ? withStack : { ...withStack, exception: input.exception };
|
|
1632
2455
|
}
|
|
1633
|
-
async function captureExpressions(session, callFrameId, captures, maxValueLength) {
|
|
2456
|
+
async function captureExpressions(session, callFrameId, captures, maxValueLength, throwOnSideEffect) {
|
|
1634
2457
|
if (captures === void 0 || captures.length === 0) {
|
|
1635
2458
|
return [];
|
|
1636
2459
|
}
|
|
1637
2460
|
return await Promise.all(
|
|
1638
2461
|
captures.map(async (expression) => {
|
|
1639
|
-
return await captureExpression(
|
|
2462
|
+
return await captureExpression(
|
|
2463
|
+
session,
|
|
2464
|
+
callFrameId,
|
|
2465
|
+
expression,
|
|
2466
|
+
maxValueLength,
|
|
2467
|
+
throwOnSideEffect
|
|
2468
|
+
);
|
|
1640
2469
|
})
|
|
1641
2470
|
);
|
|
1642
2471
|
}
|
|
1643
|
-
async function captureExpression(session, callFrameId, expression, maxValueLength) {
|
|
2472
|
+
async function captureExpression(session, callFrameId, expression, maxValueLength, throwOnSideEffect) {
|
|
2473
|
+
const mutationRisk = throwOnSideEffect === false && looksLikeMutation(expression);
|
|
1644
2474
|
try {
|
|
1645
|
-
const result = await evaluateOnFrame(session, callFrameId, expression
|
|
2475
|
+
const result = await evaluateOnFrame(session, callFrameId, expression, {
|
|
2476
|
+
...throwOnSideEffect === void 0 ? {} : { throwOnSideEffect }
|
|
2477
|
+
});
|
|
2478
|
+
if (isSideEffectRefusal(result)) {
|
|
2479
|
+
return sideEffectRefusalToCaptured(expression);
|
|
2480
|
+
}
|
|
1646
2481
|
const captured = evalResultToCaptured(expression, result, maxValueLength);
|
|
1647
|
-
|
|
2482
|
+
const serialized = await withSerializedObjectCapture(
|
|
2483
|
+
session,
|
|
2484
|
+
expression,
|
|
2485
|
+
result,
|
|
2486
|
+
captured,
|
|
2487
|
+
maxValueLength
|
|
2488
|
+
);
|
|
2489
|
+
return mutationRisk ? { ...serialized, mutationRisk: true } : serialized;
|
|
1648
2490
|
} catch (err) {
|
|
1649
2491
|
const message = err instanceof Error ? err.message : String(err);
|
|
1650
|
-
|
|
2492
|
+
const limited = limitValueLength(message, maxValueLength);
|
|
2493
|
+
const captured = {
|
|
2494
|
+
expression,
|
|
2495
|
+
error: limited.text,
|
|
2496
|
+
...textTruncationFields(limited)
|
|
2497
|
+
};
|
|
2498
|
+
return mutationRisk ? { ...captured, mutationRisk: true } : captured;
|
|
1651
2499
|
}
|
|
1652
2500
|
}
|
|
1653
2501
|
|
|
@@ -1735,7 +2583,7 @@ function readArg(arg, index) {
|
|
|
1735
2583
|
}
|
|
1736
2584
|
return index === 0 ? void 0 : "";
|
|
1737
2585
|
}
|
|
1738
|
-
function parseLogEvent(rawArgs, sentinel, location, timestamp) {
|
|
2586
|
+
function parseLogEvent(rawArgs, sentinel, location, timestamp, maxValueLength = DEFAULT_STREAM_MAX_VALUE_LENGTH) {
|
|
1739
2587
|
if (!Array.isArray(rawArgs) || rawArgs.length < 2) {
|
|
1740
2588
|
return void 0;
|
|
1741
2589
|
}
|
|
@@ -1747,21 +2595,37 @@ function parseLogEvent(rawArgs, sentinel, location, timestamp) {
|
|
|
1747
2595
|
const ts = new Date(typeof timestamp === "number" ? timestamp : Date.now()).toISOString();
|
|
1748
2596
|
const at = `${location.file}:${location.line.toString()}`;
|
|
1749
2597
|
if (payload.startsWith("!err:")) {
|
|
1750
|
-
|
|
2598
|
+
const limited = limitValueLength(payload.slice("!err:".length), maxValueLength);
|
|
2599
|
+
return {
|
|
2600
|
+
ts,
|
|
2601
|
+
at,
|
|
2602
|
+
error: limited.text,
|
|
2603
|
+
...textTruncationFields(limited)
|
|
2604
|
+
};
|
|
1751
2605
|
}
|
|
1752
|
-
return parsePayload(ts, at, payload);
|
|
2606
|
+
return parsePayload(ts, at, payload, maxValueLength);
|
|
1753
2607
|
}
|
|
1754
|
-
function parsePayload(ts, at, payload) {
|
|
2608
|
+
function parsePayload(ts, at, payload, maxValueLength) {
|
|
1755
2609
|
try {
|
|
1756
2610
|
const parsed = JSON.parse(payload);
|
|
1757
2611
|
if (typeof parsed === "string") {
|
|
1758
|
-
return
|
|
2612
|
+
return buildValueEvent(ts, at, parsed, maxValueLength);
|
|
1759
2613
|
}
|
|
1760
|
-
return
|
|
2614
|
+
return buildValueEvent(ts, at, JSON.stringify(parsed), maxValueLength);
|
|
1761
2615
|
} catch {
|
|
1762
|
-
return
|
|
2616
|
+
return buildValueEvent(ts, at, payload, maxValueLength, true);
|
|
1763
2617
|
}
|
|
1764
2618
|
}
|
|
2619
|
+
function buildValueEvent(ts, at, value, maxValueLength, includeRaw = false) {
|
|
2620
|
+
const limited = limitValueLength(value, maxValueLength);
|
|
2621
|
+
return {
|
|
2622
|
+
ts,
|
|
2623
|
+
at,
|
|
2624
|
+
value: limited.text,
|
|
2625
|
+
...includeRaw ? { raw: limited.text } : {},
|
|
2626
|
+
...textTruncationFields(limited)
|
|
2627
|
+
};
|
|
2628
|
+
}
|
|
1765
2629
|
|
|
1766
2630
|
// src/logpoint/stream.ts
|
|
1767
2631
|
function validateMaxEvents(maxEvents) {
|
|
@@ -1791,6 +2655,9 @@ function validateHitCount2(hitCount) {
|
|
|
1791
2655
|
async function streamLogpoint(session, options) {
|
|
1792
2656
|
const maxEvents = validateMaxEvents(options.maxEvents);
|
|
1793
2657
|
const hitCount = validateHitCount2(options.hitCount);
|
|
2658
|
+
const maxValueLength = resolveMaxValueLength(
|
|
2659
|
+
options.maxValueLength ?? DEFAULT_STREAM_MAX_VALUE_LENGTH
|
|
2660
|
+
);
|
|
1794
2661
|
const sentinel = generateSentinel();
|
|
1795
2662
|
const condition = buildLogpointCondition(sentinel, options.expression, {
|
|
1796
2663
|
...options.condition === void 0 ? {} : { predicate: options.condition },
|
|
@@ -1803,7 +2670,7 @@ async function streamLogpoint(session, options) {
|
|
|
1803
2670
|
if (maxEventsReached) {
|
|
1804
2671
|
return;
|
|
1805
2672
|
}
|
|
1806
|
-
const event = toLogpointEvent(raw, sentinel, options.location);
|
|
2673
|
+
const event = toLogpointEvent(raw, sentinel, options.location, maxValueLength);
|
|
1807
2674
|
if (event === void 0) {
|
|
1808
2675
|
return;
|
|
1809
2676
|
}
|
|
@@ -1843,13 +2710,13 @@ async function streamLogpoint(session, options) {
|
|
|
1843
2710
|
await removeBreakpointBestEffort(session, handle.breakpointId);
|
|
1844
2711
|
}
|
|
1845
2712
|
}
|
|
1846
|
-
function toLogpointEvent(raw, sentinel, location) {
|
|
2713
|
+
function toLogpointEvent(raw, sentinel, location, maxValueLength) {
|
|
1847
2714
|
const params = raw;
|
|
1848
2715
|
if (asString3(params.type) !== "log") {
|
|
1849
2716
|
return void 0;
|
|
1850
2717
|
}
|
|
1851
2718
|
const ts = typeof params.timestamp === "number" ? params.timestamp : void 0;
|
|
1852
|
-
return parseLogEvent(params.args, sentinel, location, ts);
|
|
2719
|
+
return parseLogEvent(params.args, sentinel, location, ts, maxValueLength);
|
|
1853
2720
|
}
|
|
1854
2721
|
async function removeBreakpointBestEffort(session, breakpointId) {
|
|
1855
2722
|
try {
|
|
@@ -1896,66 +2763,70 @@ async function waitForStop(session, options, registerMaxEventsSignal) {
|
|
|
1896
2763
|
|
|
1897
2764
|
// src/cf/tunnel.ts
|
|
1898
2765
|
import { startDebugger } from "@saptools/cf-debugger";
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
region: target.region,
|
|
2766
|
+
function targetOptions(target) {
|
|
2767
|
+
return {
|
|
1902
2768
|
...target.apiEndpoint === void 0 ? {} : { apiEndpoint: target.apiEndpoint },
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
2769
|
+
...target.process === void 0 ? {} : { process: target.process },
|
|
2770
|
+
...target.instance === void 0 ? {} : { instance: target.instance },
|
|
2771
|
+
...target.nodePid === void 0 ? {} : { nodePid: target.nodePid }
|
|
2772
|
+
};
|
|
2773
|
+
}
|
|
2774
|
+
function lifecycleOptions(target) {
|
|
2775
|
+
return {
|
|
2776
|
+
...target.allowSshEnableRestart === void 0 ? {} : { allowSshEnableRestart: target.allowSshEnableRestart },
|
|
1906
2777
|
...target.tunnelReadyTimeoutMs === void 0 ? {} : { tunnelReadyTimeoutMs: target.tunnelReadyTimeoutMs },
|
|
1907
2778
|
...target.preferredPort === void 0 ? {} : { preferredPort: target.preferredPort },
|
|
1908
2779
|
...target.verbose === void 0 ? {} : { verbose: target.verbose },
|
|
1909
2780
|
...target.signal === void 0 ? {} : { signal: target.signal },
|
|
1910
2781
|
...target.onStatus === void 0 ? {} : { onStatus: target.onStatus }
|
|
1911
2782
|
};
|
|
1912
|
-
try {
|
|
1913
|
-
const handle = await startDebugger(opts);
|
|
1914
|
-
return {
|
|
1915
|
-
localPort: handle.session.localPort,
|
|
1916
|
-
handle,
|
|
1917
|
-
dispose: async () => {
|
|
1918
|
-
await handle.dispose();
|
|
1919
|
-
}
|
|
1920
|
-
};
|
|
1921
|
-
} catch (err) {
|
|
1922
|
-
return reuseExistingTunnelOrThrow(err, target.onStatus);
|
|
1923
|
-
}
|
|
1924
2783
|
}
|
|
1925
|
-
function
|
|
1926
|
-
if (!isSessionAlreadyRunningError(err)) {
|
|
1927
|
-
throw err;
|
|
1928
|
-
}
|
|
1929
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
1930
|
-
const port = extractExistingTunnelPort(message);
|
|
1931
|
-
if (port === void 0) {
|
|
1932
|
-
throw err;
|
|
1933
|
-
}
|
|
1934
|
-
const warning = `Reusing existing tunnel on port ${port.toString()}`;
|
|
1935
|
-
onStatus?.("ready", warning);
|
|
2784
|
+
function toStartDebuggerOptions(target) {
|
|
1936
2785
|
return {
|
|
1937
|
-
|
|
1938
|
-
|
|
2786
|
+
region: target.region,
|
|
2787
|
+
org: target.org,
|
|
2788
|
+
space: target.space,
|
|
2789
|
+
app: target.app,
|
|
2790
|
+
...targetOptions(target),
|
|
2791
|
+
...lifecycleOptions(target)
|
|
1939
2792
|
};
|
|
1940
2793
|
}
|
|
1941
|
-
function
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
2794
|
+
async function openOwnedCfTunnel(target) {
|
|
2795
|
+
const opts = toStartDebuggerOptions(target);
|
|
2796
|
+
const handle = await startDebugger(opts);
|
|
2797
|
+
return {
|
|
2798
|
+
localPort: handle.session.localPort,
|
|
2799
|
+
handle,
|
|
2800
|
+
dispose: async () => {
|
|
2801
|
+
await handle.dispose();
|
|
2802
|
+
}
|
|
2803
|
+
};
|
|
1947
2804
|
}
|
|
1948
|
-
function
|
|
1949
|
-
|
|
1950
|
-
|
|
2805
|
+
function isExistingSessionError(error) {
|
|
2806
|
+
return error instanceof Error && "code" in error && error.code === "SESSION_ALREADY_RUNNING";
|
|
2807
|
+
}
|
|
2808
|
+
function existingTunnelPort(error) {
|
|
2809
|
+
if (!isExistingSessionError(error)) {
|
|
1951
2810
|
return void 0;
|
|
1952
2811
|
}
|
|
1953
|
-
const rawPort =
|
|
2812
|
+
const rawPort = /\bon port (\d+)\b/iu.exec(error.message)?.[1];
|
|
1954
2813
|
if (rawPort === void 0) {
|
|
1955
2814
|
return void 0;
|
|
1956
2815
|
}
|
|
1957
2816
|
const port = Number.parseInt(rawPort, 10);
|
|
1958
|
-
return Number.
|
|
2817
|
+
return Number.isInteger(port) && port >= 1 && port <= 65535 ? port : void 0;
|
|
2818
|
+
}
|
|
2819
|
+
async function openCfTunnel(target) {
|
|
2820
|
+
try {
|
|
2821
|
+
return await openOwnedCfTunnel(target);
|
|
2822
|
+
} catch (error) {
|
|
2823
|
+
const localPort = existingTunnelPort(error);
|
|
2824
|
+
if (localPort === void 0) {
|
|
2825
|
+
throw error;
|
|
2826
|
+
}
|
|
2827
|
+
target.onStatus?.("ready", `Reusing existing tunnel on port ${localPort.toString()}`);
|
|
2828
|
+
return { localPort, dispose: () => Promise.resolve() };
|
|
2829
|
+
}
|
|
1959
2830
|
}
|
|
1960
2831
|
export {
|
|
1961
2832
|
CfInspectorError,
|
|
@@ -1969,16 +2840,25 @@ export {
|
|
|
1969
2840
|
evaluateGlobal,
|
|
1970
2841
|
evaluateOnFrame,
|
|
1971
2842
|
fetchInspectorVersion,
|
|
2843
|
+
getPossibleBreakpoints,
|
|
1972
2844
|
getProperties,
|
|
2845
|
+
getScriptSource,
|
|
1973
2846
|
listScripts,
|
|
1974
2847
|
openCfTunnel,
|
|
2848
|
+
openOwnedCfTunnel,
|
|
1975
2849
|
parseBreakpointSpec,
|
|
1976
2850
|
parseRemoteRoot,
|
|
2851
|
+
releaseObject,
|
|
2852
|
+
releaseObjectGroup,
|
|
1977
2853
|
removeBreakpoint,
|
|
1978
2854
|
resume,
|
|
1979
2855
|
runSetupEvals,
|
|
1980
2856
|
setBreakpoint,
|
|
2857
|
+
setBreakpointAtLocation,
|
|
1981
2858
|
setPauseOnExceptions,
|
|
2859
|
+
stepInto,
|
|
2860
|
+
stepOut,
|
|
2861
|
+
stepOver,
|
|
1982
2862
|
streamLogpoint,
|
|
1983
2863
|
validateExpression,
|
|
1984
2864
|
waitForPause,
|