@saptools/cf-inspector 0.5.0 → 0.6.1
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 +51 -0
- package/dist/cli.js +380 -153
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +103 -7
- package/dist/index.js +499 -141
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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
|
-
|
|
352
|
+
const location = toScriptLocation(entry);
|
|
353
|
+
if (location === void 0 || !isRecord(entry)) {
|
|
307
354
|
return [];
|
|
308
355
|
}
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
if (scriptId.length === 0) {
|
|
312
|
-
return [];
|
|
313
|
-
}
|
|
314
|
-
const url = typeof candidate.url === "string" ? candidate.url : void 0;
|
|
315
|
-
const lineNumber = asNumber(candidate.lineNumber);
|
|
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
|
-
|
|
365
|
+
const location = toScriptLocation(entry);
|
|
366
|
+
if (location === void 0 || !isRecord(entry)) {
|
|
326
367
|
return [];
|
|
327
368
|
}
|
|
328
|
-
const
|
|
329
|
-
|
|
330
|
-
if (type.length === 0) {
|
|
331
|
-
return [];
|
|
332
|
-
}
|
|
333
|
-
const objectId = typeof candidate.object?.objectId === "string" ? candidate.object.objectId : void 0;
|
|
334
|
-
const name = typeof candidate.name === "string" ? candidate.name : void 0;
|
|
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,6 +664,83 @@ 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();
|
|
@@ -658,6 +929,11 @@ function pauseMatches(pause, breakpointIds, pauseReasons) {
|
|
|
658
929
|
function remainingUntil(deadlineMs) {
|
|
659
930
|
return Math.max(0, deadlineMs - performance2.now());
|
|
660
931
|
}
|
|
932
|
+
function throwIfAborted(signal) {
|
|
933
|
+
if (signal?.aborted === true) {
|
|
934
|
+
throw new CfInspectorError("ABORTED", "Aborted while waiting for Debugger.paused");
|
|
935
|
+
}
|
|
936
|
+
}
|
|
661
937
|
function hasResumedSincePause(session, pause) {
|
|
662
938
|
const pauseAt = pause.receivedAtMs;
|
|
663
939
|
const resumedAt = session.debuggerState.lastResumedAtMs;
|
|
@@ -676,20 +952,23 @@ function throwUnrelatedPauseTimeout(pause, timeoutMs) {
|
|
|
676
952
|
pauseDetail(pause)
|
|
677
953
|
);
|
|
678
954
|
}
|
|
679
|
-
async function waitForUnmatchedPauseToResume(session, pause, deadlineMs,
|
|
955
|
+
async function waitForUnmatchedPauseToResume(session, pause, deadlineMs, options) {
|
|
680
956
|
if (hasResumedSincePause(session, pause)) {
|
|
681
957
|
return;
|
|
682
958
|
}
|
|
683
959
|
const remainingMs = remainingUntil(deadlineMs);
|
|
684
960
|
if (remainingMs <= 0) {
|
|
685
|
-
throwUnrelatedPauseTimeout(pause, timeoutMs);
|
|
961
|
+
throwUnrelatedPauseTimeout(pause, options.timeoutMs);
|
|
686
962
|
}
|
|
687
963
|
try {
|
|
688
|
-
await session.client.waitFor("Debugger.resumed", {
|
|
964
|
+
await session.client.waitFor("Debugger.resumed", {
|
|
965
|
+
timeoutMs: remainingMs,
|
|
966
|
+
...options.signal === void 0 ? {} : { signal: options.signal }
|
|
967
|
+
});
|
|
689
968
|
session.debuggerState.lastResumedAtMs = performance2.now();
|
|
690
969
|
} catch (err) {
|
|
691
970
|
if (err instanceof CfInspectorError && err.code === "BREAKPOINT_NOT_HIT") {
|
|
692
|
-
throwUnrelatedPauseTimeout(pause, timeoutMs);
|
|
971
|
+
throwUnrelatedPauseTimeout(pause, options.timeoutMs);
|
|
693
972
|
}
|
|
694
973
|
throw err;
|
|
695
974
|
}
|
|
@@ -706,13 +985,16 @@ async function handleUnmatchedPause(session, pause, options, deadlineMs) {
|
|
|
706
985
|
return;
|
|
707
986
|
}
|
|
708
987
|
options.onUnmatchedPause?.(pause);
|
|
709
|
-
await waitForUnmatchedPauseToResume(session, pause, deadlineMs, options
|
|
988
|
+
await waitForUnmatchedPauseToResume(session, pause, deadlineMs, options);
|
|
710
989
|
}
|
|
711
990
|
async function waitForPause(session, options) {
|
|
991
|
+
throwIfAborted(options.signal);
|
|
712
992
|
const deadlineMs = performance2.now() + options.timeoutMs;
|
|
713
993
|
const buffer = session.pauseBuffer;
|
|
714
994
|
while (buffer.length > 0 || remainingUntil(deadlineMs) > 0) {
|
|
995
|
+
throwIfAborted(options.signal);
|
|
715
996
|
while (buffer.length > 0) {
|
|
997
|
+
throwIfAborted(options.signal);
|
|
716
998
|
const buffered = buffer.shift();
|
|
717
999
|
if (buffered === void 0) {
|
|
718
1000
|
continue;
|
|
@@ -741,6 +1023,7 @@ async function waitForLivePause(session, options, deadlineMs) {
|
|
|
741
1023
|
try {
|
|
742
1024
|
params = await session.client.waitFor("Debugger.paused", {
|
|
743
1025
|
timeoutMs: remainingMs,
|
|
1026
|
+
...options.signal === void 0 ? {} : { signal: options.signal },
|
|
744
1027
|
predicate: () => {
|
|
745
1028
|
receivedAtMs = performance2.now();
|
|
746
1029
|
return true;
|
|
@@ -760,6 +1043,9 @@ async function resume(session) {
|
|
|
760
1043
|
async function setPauseOnExceptions(session, state) {
|
|
761
1044
|
await session.client.send("Debugger.setPauseOnExceptions", { state });
|
|
762
1045
|
}
|
|
1046
|
+
async function setAsyncCallStackDepth(session, maxDepth) {
|
|
1047
|
+
await session.client.send("Debugger.setAsyncCallStackDepth", { maxDepth });
|
|
1048
|
+
}
|
|
763
1049
|
async function evaluateOnFrame(session, callFrameId, expression, options = {}) {
|
|
764
1050
|
return await session.client.send("Debugger.evaluateOnCallFrame", {
|
|
765
1051
|
callFrameId,
|
|
@@ -767,7 +1053,8 @@ async function evaluateOnFrame(session, callFrameId, expression, options = {}) {
|
|
|
767
1053
|
returnByValue: false,
|
|
768
1054
|
generatePreview: true,
|
|
769
1055
|
silent: true,
|
|
770
|
-
...options.throwOnSideEffect === void 0 ? {} : { throwOnSideEffect: options.throwOnSideEffect }
|
|
1056
|
+
...options.throwOnSideEffect === void 0 ? {} : { throwOnSideEffect: options.throwOnSideEffect },
|
|
1057
|
+
...options.objectGroup === void 0 ? {} : { objectGroup: options.objectGroup }
|
|
771
1058
|
});
|
|
772
1059
|
}
|
|
773
1060
|
function isSideEffectRefusal(result) {
|
|
@@ -833,6 +1120,39 @@ async function getProperties(session, objectId) {
|
|
|
833
1120
|
}
|
|
834
1121
|
return result.result;
|
|
835
1122
|
}
|
|
1123
|
+
async function getScriptSource(session, scriptId) {
|
|
1124
|
+
if (scriptId.trim().length === 0) {
|
|
1125
|
+
throw new CfInspectorError("INVALID_ARGUMENT", "scriptId must not be empty");
|
|
1126
|
+
}
|
|
1127
|
+
const result = await session.client.send(
|
|
1128
|
+
"Debugger.getScriptSource",
|
|
1129
|
+
{ scriptId }
|
|
1130
|
+
);
|
|
1131
|
+
if (typeof result.scriptSource !== "string") {
|
|
1132
|
+
throw new CfInspectorError(
|
|
1133
|
+
"CDP_REQUEST_FAILED",
|
|
1134
|
+
"Debugger.getScriptSource did not return scriptSource"
|
|
1135
|
+
);
|
|
1136
|
+
}
|
|
1137
|
+
return result.scriptSource;
|
|
1138
|
+
}
|
|
1139
|
+
async function stepInto(session, options = {}) {
|
|
1140
|
+
await session.client.send("Debugger.stepInto", {
|
|
1141
|
+
...options.breakOnAsyncCall === void 0 ? {} : { breakOnAsyncCall: options.breakOnAsyncCall }
|
|
1142
|
+
});
|
|
1143
|
+
}
|
|
1144
|
+
async function stepOver(session) {
|
|
1145
|
+
await session.client.send("Debugger.stepOver");
|
|
1146
|
+
}
|
|
1147
|
+
async function stepOut(session) {
|
|
1148
|
+
await session.client.send("Debugger.stepOut");
|
|
1149
|
+
}
|
|
1150
|
+
async function releaseObject(session, objectId) {
|
|
1151
|
+
await session.client.send("Runtime.releaseObject", { objectId });
|
|
1152
|
+
}
|
|
1153
|
+
async function releaseObjectGroup(session, objectGroup) {
|
|
1154
|
+
await session.client.send("Runtime.releaseObjectGroup", { objectGroup });
|
|
1155
|
+
}
|
|
836
1156
|
|
|
837
1157
|
// src/inspector/session.ts
|
|
838
1158
|
import { performance as performance3 } from "perf_hooks";
|
|
@@ -938,54 +1258,70 @@ var CdpClient = class _CdpClient {
|
|
|
938
1258
|
if (this.closed) {
|
|
939
1259
|
throw this.closeReason ?? new CfInspectorError("INSPECTOR_CONNECTION_FAILED", "Connection closed");
|
|
940
1260
|
}
|
|
941
|
-
|
|
1261
|
+
if (options.signal?.aborted === true) {
|
|
1262
|
+
throw this.createWaitAbortError(method);
|
|
1263
|
+
}
|
|
1264
|
+
return await this.createEventWait(method, options);
|
|
1265
|
+
}
|
|
1266
|
+
createEventWait(method, options) {
|
|
1267
|
+
return new Promise((resolve, reject) => {
|
|
942
1268
|
let settled = false;
|
|
1269
|
+
let offEvent = () => void 0;
|
|
1270
|
+
let offClose = () => void 0;
|
|
943
1271
|
const cleanup = () => {
|
|
944
1272
|
clearTimeout(timer);
|
|
945
1273
|
offEvent();
|
|
946
1274
|
offClose();
|
|
1275
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
947
1276
|
};
|
|
948
|
-
const
|
|
1277
|
+
const resolveOnce = (value) => {
|
|
1278
|
+
if (settled) {
|
|
1279
|
+
return;
|
|
1280
|
+
}
|
|
949
1281
|
settled = true;
|
|
950
1282
|
cleanup();
|
|
951
1283
|
resolve(value);
|
|
952
1284
|
};
|
|
953
|
-
const
|
|
954
|
-
if (settled) {
|
|
955
|
-
return;
|
|
956
|
-
}
|
|
957
|
-
const params = raw;
|
|
958
|
-
if (options.predicate) {
|
|
959
|
-
let accepted;
|
|
960
|
-
try {
|
|
961
|
-
accepted = options.predicate(params);
|
|
962
|
-
} catch {
|
|
963
|
-
return;
|
|
964
|
-
}
|
|
965
|
-
if (!accepted) {
|
|
966
|
-
return;
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
|
-
finish(params);
|
|
970
|
-
});
|
|
971
|
-
const offClose = this.onClose((err) => {
|
|
1285
|
+
const rejectOnce = (error) => {
|
|
972
1286
|
if (settled) {
|
|
973
1287
|
return;
|
|
974
1288
|
}
|
|
975
1289
|
settled = true;
|
|
976
1290
|
cleanup();
|
|
977
|
-
reject(
|
|
978
|
-
}
|
|
1291
|
+
reject(error);
|
|
1292
|
+
};
|
|
1293
|
+
const onAbort = () => {
|
|
1294
|
+
rejectOnce(this.createWaitAbortError(method));
|
|
1295
|
+
};
|
|
979
1296
|
const timer = setTimeout(() => {
|
|
980
|
-
|
|
1297
|
+
rejectOnce(this.createWaitTimeoutError(method, options.timeoutMs));
|
|
1298
|
+
}, options.timeoutMs);
|
|
1299
|
+
offEvent = this.on(method, (raw) => {
|
|
1300
|
+
const params = raw;
|
|
1301
|
+
if (!this.eventMatches(params, options.predicate)) {
|
|
981
1302
|
return;
|
|
982
1303
|
}
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
1304
|
+
resolveOnce(params);
|
|
1305
|
+
});
|
|
1306
|
+
offClose = this.onClose((error) => {
|
|
1307
|
+
rejectOnce(error);
|
|
1308
|
+
});
|
|
1309
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
1310
|
+
if (options.signal?.aborted === true) {
|
|
1311
|
+
onAbort();
|
|
1312
|
+
}
|
|
987
1313
|
});
|
|
988
1314
|
}
|
|
1315
|
+
eventMatches(params, predicate) {
|
|
1316
|
+
if (predicate === void 0) {
|
|
1317
|
+
return true;
|
|
1318
|
+
}
|
|
1319
|
+
try {
|
|
1320
|
+
return predicate(params);
|
|
1321
|
+
} catch {
|
|
1322
|
+
return false;
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
989
1325
|
onClose(listener) {
|
|
990
1326
|
if (this.closed) {
|
|
991
1327
|
const reason = this.closeReason ?? new CfInspectorError("INSPECTOR_CONNECTION_FAILED", "Connection closed");
|
|
@@ -1052,6 +1388,9 @@ var CdpClient = class _CdpClient {
|
|
|
1052
1388
|
`Timed out waiting for ${method} after ${timeoutMs.toString()}ms`
|
|
1053
1389
|
);
|
|
1054
1390
|
}
|
|
1391
|
+
createWaitAbortError(method) {
|
|
1392
|
+
return new CfInspectorError("ABORTED", `Aborted while waiting for ${method}`);
|
|
1393
|
+
}
|
|
1055
1394
|
sendPayload(id, method, payload, timer, reject) {
|
|
1056
1395
|
try {
|
|
1057
1396
|
this.transport.send(payload);
|
|
@@ -1356,24 +1695,29 @@ function workerToInspectorTarget(worker) {
|
|
|
1356
1695
|
}
|
|
1357
1696
|
async function initSession(client, target) {
|
|
1358
1697
|
const scripts = /* @__PURE__ */ new Map();
|
|
1359
|
-
client
|
|
1360
|
-
const params = raw;
|
|
1361
|
-
const scriptId = asString(params.scriptId);
|
|
1362
|
-
const url = asString(params.url);
|
|
1363
|
-
if (scriptId.length === 0) {
|
|
1364
|
-
return;
|
|
1365
|
-
}
|
|
1366
|
-
scripts.set(scriptId, { scriptId, url });
|
|
1367
|
-
});
|
|
1698
|
+
registerScriptTracking(client, scripts);
|
|
1368
1699
|
const pauseBuffer = [];
|
|
1369
1700
|
const pauseWaitGate = { active: false };
|
|
1370
1701
|
const debuggerState = {};
|
|
1702
|
+
registerPauseTracking(client, scripts, pauseBuffer, pauseWaitGate, debuggerState);
|
|
1703
|
+
await client.send("Runtime.enable");
|
|
1704
|
+
await client.send("Debugger.enable");
|
|
1705
|
+
return createSession(client, target, scripts, pauseBuffer, pauseWaitGate, debuggerState);
|
|
1706
|
+
}
|
|
1707
|
+
function registerScriptTracking(client, scripts) {
|
|
1708
|
+
client.on("Debugger.scriptParsed", (raw) => {
|
|
1709
|
+
const script = toScriptInfo(raw);
|
|
1710
|
+
if (script !== void 0) {
|
|
1711
|
+
scripts.set(script.scriptId, script);
|
|
1712
|
+
}
|
|
1713
|
+
});
|
|
1714
|
+
}
|
|
1715
|
+
function registerPauseTracking(client, scripts, pauseBuffer, pauseWaitGate, debuggerState) {
|
|
1371
1716
|
client.on("Debugger.paused", (raw) => {
|
|
1372
1717
|
if (pauseWaitGate.active) {
|
|
1373
1718
|
return;
|
|
1374
1719
|
}
|
|
1375
|
-
const
|
|
1376
|
-
const event = toPauseEvent(params, performance3.now(), scripts);
|
|
1720
|
+
const event = toPauseEvent(raw, performance3.now(), scripts);
|
|
1377
1721
|
if (pauseBuffer.length >= PAUSE_BUFFER_LIMIT) {
|
|
1378
1722
|
pauseBuffer.shift();
|
|
1379
1723
|
}
|
|
@@ -1382,8 +1726,8 @@ async function initSession(client, target) {
|
|
|
1382
1726
|
client.on("Debugger.resumed", () => {
|
|
1383
1727
|
debuggerState.lastResumedAtMs = performance3.now();
|
|
1384
1728
|
});
|
|
1385
|
-
|
|
1386
|
-
|
|
1729
|
+
}
|
|
1730
|
+
function createSession(client, target, scripts, pauseBuffer, pauseWaitGate, debuggerState) {
|
|
1387
1731
|
return {
|
|
1388
1732
|
client,
|
|
1389
1733
|
target,
|
|
@@ -2422,66 +2766,70 @@ async function waitForStop(session, options, registerMaxEventsSignal) {
|
|
|
2422
2766
|
|
|
2423
2767
|
// src/cf/tunnel.ts
|
|
2424
2768
|
import { startDebugger } from "@saptools/cf-debugger";
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
region: target.region,
|
|
2769
|
+
function targetOptions(target) {
|
|
2770
|
+
return {
|
|
2428
2771
|
...target.apiEndpoint === void 0 ? {} : { apiEndpoint: target.apiEndpoint },
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2772
|
+
...target.process === void 0 ? {} : { process: target.process },
|
|
2773
|
+
...target.instance === void 0 ? {} : { instance: target.instance },
|
|
2774
|
+
...target.nodePid === void 0 ? {} : { nodePid: target.nodePid }
|
|
2775
|
+
};
|
|
2776
|
+
}
|
|
2777
|
+
function lifecycleOptions(target) {
|
|
2778
|
+
return {
|
|
2779
|
+
...target.allowSshEnableRestart === void 0 ? {} : { allowSshEnableRestart: target.allowSshEnableRestart },
|
|
2432
2780
|
...target.tunnelReadyTimeoutMs === void 0 ? {} : { tunnelReadyTimeoutMs: target.tunnelReadyTimeoutMs },
|
|
2433
2781
|
...target.preferredPort === void 0 ? {} : { preferredPort: target.preferredPort },
|
|
2434
2782
|
...target.verbose === void 0 ? {} : { verbose: target.verbose },
|
|
2435
2783
|
...target.signal === void 0 ? {} : { signal: target.signal },
|
|
2436
2784
|
...target.onStatus === void 0 ? {} : { onStatus: target.onStatus }
|
|
2437
2785
|
};
|
|
2438
|
-
try {
|
|
2439
|
-
const handle = await startDebugger(opts);
|
|
2440
|
-
return {
|
|
2441
|
-
localPort: handle.session.localPort,
|
|
2442
|
-
handle,
|
|
2443
|
-
dispose: async () => {
|
|
2444
|
-
await handle.dispose();
|
|
2445
|
-
}
|
|
2446
|
-
};
|
|
2447
|
-
} catch (err) {
|
|
2448
|
-
return reuseExistingTunnelOrThrow(err, target.onStatus);
|
|
2449
|
-
}
|
|
2450
2786
|
}
|
|
2451
|
-
function
|
|
2452
|
-
if (!isSessionAlreadyRunningError(err)) {
|
|
2453
|
-
throw err;
|
|
2454
|
-
}
|
|
2455
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
2456
|
-
const port = extractExistingTunnelPort(message);
|
|
2457
|
-
if (port === void 0) {
|
|
2458
|
-
throw err;
|
|
2459
|
-
}
|
|
2460
|
-
const warning = `Reusing existing tunnel on port ${port.toString()}`;
|
|
2461
|
-
onStatus?.("ready", warning);
|
|
2787
|
+
function toStartDebuggerOptions(target) {
|
|
2462
2788
|
return {
|
|
2463
|
-
|
|
2464
|
-
|
|
2789
|
+
region: target.region,
|
|
2790
|
+
org: target.org,
|
|
2791
|
+
space: target.space,
|
|
2792
|
+
app: target.app,
|
|
2793
|
+
...targetOptions(target),
|
|
2794
|
+
...lifecycleOptions(target)
|
|
2465
2795
|
};
|
|
2466
2796
|
}
|
|
2467
|
-
function
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2797
|
+
async function openOwnedCfTunnel(target) {
|
|
2798
|
+
const opts = toStartDebuggerOptions(target);
|
|
2799
|
+
const handle = await startDebugger(opts);
|
|
2800
|
+
return {
|
|
2801
|
+
localPort: handle.session.localPort,
|
|
2802
|
+
handle,
|
|
2803
|
+
dispose: async () => {
|
|
2804
|
+
await handle.dispose();
|
|
2805
|
+
}
|
|
2806
|
+
};
|
|
2473
2807
|
}
|
|
2474
|
-
function
|
|
2475
|
-
|
|
2476
|
-
|
|
2808
|
+
function isExistingSessionError(error) {
|
|
2809
|
+
return error instanceof Error && "code" in error && error.code === "SESSION_ALREADY_RUNNING";
|
|
2810
|
+
}
|
|
2811
|
+
function existingTunnelPort(error) {
|
|
2812
|
+
if (!isExistingSessionError(error)) {
|
|
2477
2813
|
return void 0;
|
|
2478
2814
|
}
|
|
2479
|
-
const rawPort =
|
|
2815
|
+
const rawPort = /\bon port (\d+)\b/iu.exec(error.message)?.[1];
|
|
2480
2816
|
if (rawPort === void 0) {
|
|
2481
2817
|
return void 0;
|
|
2482
2818
|
}
|
|
2483
2819
|
const port = Number.parseInt(rawPort, 10);
|
|
2484
|
-
return Number.
|
|
2820
|
+
return Number.isInteger(port) && port >= 1 && port <= 65535 ? port : void 0;
|
|
2821
|
+
}
|
|
2822
|
+
async function openCfTunnel(target) {
|
|
2823
|
+
try {
|
|
2824
|
+
return await openOwnedCfTunnel(target);
|
|
2825
|
+
} catch (error) {
|
|
2826
|
+
const localPort = existingTunnelPort(error);
|
|
2827
|
+
if (localPort === void 0) {
|
|
2828
|
+
throw error;
|
|
2829
|
+
}
|
|
2830
|
+
target.onStatus?.("ready", `Reusing existing tunnel on port ${localPort.toString()}`);
|
|
2831
|
+
return { localPort, dispose: () => Promise.resolve() };
|
|
2832
|
+
}
|
|
2485
2833
|
}
|
|
2486
2834
|
export {
|
|
2487
2835
|
CfInspectorError,
|
|
@@ -2495,16 +2843,26 @@ export {
|
|
|
2495
2843
|
evaluateGlobal,
|
|
2496
2844
|
evaluateOnFrame,
|
|
2497
2845
|
fetchInspectorVersion,
|
|
2846
|
+
getPossibleBreakpoints,
|
|
2498
2847
|
getProperties,
|
|
2848
|
+
getScriptSource,
|
|
2499
2849
|
listScripts,
|
|
2500
2850
|
openCfTunnel,
|
|
2851
|
+
openOwnedCfTunnel,
|
|
2501
2852
|
parseBreakpointSpec,
|
|
2502
2853
|
parseRemoteRoot,
|
|
2854
|
+
releaseObject,
|
|
2855
|
+
releaseObjectGroup,
|
|
2503
2856
|
removeBreakpoint,
|
|
2504
2857
|
resume,
|
|
2505
2858
|
runSetupEvals,
|
|
2859
|
+
setAsyncCallStackDepth,
|
|
2506
2860
|
setBreakpoint,
|
|
2861
|
+
setBreakpointAtLocation,
|
|
2507
2862
|
setPauseOnExceptions,
|
|
2863
|
+
stepInto,
|
|
2864
|
+
stepOut,
|
|
2865
|
+
stepOver,
|
|
2508
2866
|
streamLogpoint,
|
|
2509
2867
|
validateExpression,
|
|
2510
2868
|
waitForPause,
|