@saptools/cf-inspector 0.5.0 → 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 +51 -0
- package/dist/cli.js +380 -153
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +102 -7
- package/dist/index.js +495 -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;
|
|
@@ -767,7 +1050,8 @@ async function evaluateOnFrame(session, callFrameId, expression, options = {}) {
|
|
|
767
1050
|
returnByValue: false,
|
|
768
1051
|
generatePreview: true,
|
|
769
1052
|
silent: true,
|
|
770
|
-
...options.throwOnSideEffect === void 0 ? {} : { throwOnSideEffect: options.throwOnSideEffect }
|
|
1053
|
+
...options.throwOnSideEffect === void 0 ? {} : { throwOnSideEffect: options.throwOnSideEffect },
|
|
1054
|
+
...options.objectGroup === void 0 ? {} : { objectGroup: options.objectGroup }
|
|
771
1055
|
});
|
|
772
1056
|
}
|
|
773
1057
|
function isSideEffectRefusal(result) {
|
|
@@ -833,6 +1117,39 @@ async function getProperties(session, objectId) {
|
|
|
833
1117
|
}
|
|
834
1118
|
return result.result;
|
|
835
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
|
+
}
|
|
836
1153
|
|
|
837
1154
|
// src/inspector/session.ts
|
|
838
1155
|
import { performance as performance3 } from "perf_hooks";
|
|
@@ -938,54 +1255,70 @@ var CdpClient = class _CdpClient {
|
|
|
938
1255
|
if (this.closed) {
|
|
939
1256
|
throw this.closeReason ?? new CfInspectorError("INSPECTOR_CONNECTION_FAILED", "Connection closed");
|
|
940
1257
|
}
|
|
941
|
-
|
|
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) => {
|
|
942
1265
|
let settled = false;
|
|
1266
|
+
let offEvent = () => void 0;
|
|
1267
|
+
let offClose = () => void 0;
|
|
943
1268
|
const cleanup = () => {
|
|
944
1269
|
clearTimeout(timer);
|
|
945
1270
|
offEvent();
|
|
946
1271
|
offClose();
|
|
1272
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
947
1273
|
};
|
|
948
|
-
const
|
|
1274
|
+
const resolveOnce = (value) => {
|
|
1275
|
+
if (settled) {
|
|
1276
|
+
return;
|
|
1277
|
+
}
|
|
949
1278
|
settled = true;
|
|
950
1279
|
cleanup();
|
|
951
1280
|
resolve(value);
|
|
952
1281
|
};
|
|
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) => {
|
|
1282
|
+
const rejectOnce = (error) => {
|
|
972
1283
|
if (settled) {
|
|
973
1284
|
return;
|
|
974
1285
|
}
|
|
975
1286
|
settled = true;
|
|
976
1287
|
cleanup();
|
|
977
|
-
reject(
|
|
978
|
-
}
|
|
1288
|
+
reject(error);
|
|
1289
|
+
};
|
|
1290
|
+
const onAbort = () => {
|
|
1291
|
+
rejectOnce(this.createWaitAbortError(method));
|
|
1292
|
+
};
|
|
979
1293
|
const timer = setTimeout(() => {
|
|
980
|
-
|
|
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)) {
|
|
981
1299
|
return;
|
|
982
1300
|
}
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
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
|
+
}
|
|
987
1310
|
});
|
|
988
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
|
+
}
|
|
989
1322
|
onClose(listener) {
|
|
990
1323
|
if (this.closed) {
|
|
991
1324
|
const reason = this.closeReason ?? new CfInspectorError("INSPECTOR_CONNECTION_FAILED", "Connection closed");
|
|
@@ -1052,6 +1385,9 @@ var CdpClient = class _CdpClient {
|
|
|
1052
1385
|
`Timed out waiting for ${method} after ${timeoutMs.toString()}ms`
|
|
1053
1386
|
);
|
|
1054
1387
|
}
|
|
1388
|
+
createWaitAbortError(method) {
|
|
1389
|
+
return new CfInspectorError("ABORTED", `Aborted while waiting for ${method}`);
|
|
1390
|
+
}
|
|
1055
1391
|
sendPayload(id, method, payload, timer, reject) {
|
|
1056
1392
|
try {
|
|
1057
1393
|
this.transport.send(payload);
|
|
@@ -1356,24 +1692,29 @@ function workerToInspectorTarget(worker) {
|
|
|
1356
1692
|
}
|
|
1357
1693
|
async function initSession(client, target) {
|
|
1358
1694
|
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
|
-
});
|
|
1695
|
+
registerScriptTracking(client, scripts);
|
|
1368
1696
|
const pauseBuffer = [];
|
|
1369
1697
|
const pauseWaitGate = { active: false };
|
|
1370
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) {
|
|
1371
1713
|
client.on("Debugger.paused", (raw) => {
|
|
1372
1714
|
if (pauseWaitGate.active) {
|
|
1373
1715
|
return;
|
|
1374
1716
|
}
|
|
1375
|
-
const
|
|
1376
|
-
const event = toPauseEvent(params, performance3.now(), scripts);
|
|
1717
|
+
const event = toPauseEvent(raw, performance3.now(), scripts);
|
|
1377
1718
|
if (pauseBuffer.length >= PAUSE_BUFFER_LIMIT) {
|
|
1378
1719
|
pauseBuffer.shift();
|
|
1379
1720
|
}
|
|
@@ -1382,8 +1723,8 @@ async function initSession(client, target) {
|
|
|
1382
1723
|
client.on("Debugger.resumed", () => {
|
|
1383
1724
|
debuggerState.lastResumedAtMs = performance3.now();
|
|
1384
1725
|
});
|
|
1385
|
-
|
|
1386
|
-
|
|
1726
|
+
}
|
|
1727
|
+
function createSession(client, target, scripts, pauseBuffer, pauseWaitGate, debuggerState) {
|
|
1387
1728
|
return {
|
|
1388
1729
|
client,
|
|
1389
1730
|
target,
|
|
@@ -2422,66 +2763,70 @@ async function waitForStop(session, options, registerMaxEventsSignal) {
|
|
|
2422
2763
|
|
|
2423
2764
|
// src/cf/tunnel.ts
|
|
2424
2765
|
import { startDebugger } from "@saptools/cf-debugger";
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
region: target.region,
|
|
2766
|
+
function targetOptions(target) {
|
|
2767
|
+
return {
|
|
2428
2768
|
...target.apiEndpoint === void 0 ? {} : { apiEndpoint: target.apiEndpoint },
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
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 },
|
|
2432
2777
|
...target.tunnelReadyTimeoutMs === void 0 ? {} : { tunnelReadyTimeoutMs: target.tunnelReadyTimeoutMs },
|
|
2433
2778
|
...target.preferredPort === void 0 ? {} : { preferredPort: target.preferredPort },
|
|
2434
2779
|
...target.verbose === void 0 ? {} : { verbose: target.verbose },
|
|
2435
2780
|
...target.signal === void 0 ? {} : { signal: target.signal },
|
|
2436
2781
|
...target.onStatus === void 0 ? {} : { onStatus: target.onStatus }
|
|
2437
2782
|
};
|
|
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
2783
|
}
|
|
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);
|
|
2784
|
+
function toStartDebuggerOptions(target) {
|
|
2462
2785
|
return {
|
|
2463
|
-
|
|
2464
|
-
|
|
2786
|
+
region: target.region,
|
|
2787
|
+
org: target.org,
|
|
2788
|
+
space: target.space,
|
|
2789
|
+
app: target.app,
|
|
2790
|
+
...targetOptions(target),
|
|
2791
|
+
...lifecycleOptions(target)
|
|
2465
2792
|
};
|
|
2466
2793
|
}
|
|
2467
|
-
function
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
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
|
+
};
|
|
2473
2804
|
}
|
|
2474
|
-
function
|
|
2475
|
-
|
|
2476
|
-
|
|
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)) {
|
|
2477
2810
|
return void 0;
|
|
2478
2811
|
}
|
|
2479
|
-
const rawPort =
|
|
2812
|
+
const rawPort = /\bon port (\d+)\b/iu.exec(error.message)?.[1];
|
|
2480
2813
|
if (rawPort === void 0) {
|
|
2481
2814
|
return void 0;
|
|
2482
2815
|
}
|
|
2483
2816
|
const port = Number.parseInt(rawPort, 10);
|
|
2484
|
-
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
|
+
}
|
|
2485
2830
|
}
|
|
2486
2831
|
export {
|
|
2487
2832
|
CfInspectorError,
|
|
@@ -2495,16 +2840,25 @@ export {
|
|
|
2495
2840
|
evaluateGlobal,
|
|
2496
2841
|
evaluateOnFrame,
|
|
2497
2842
|
fetchInspectorVersion,
|
|
2843
|
+
getPossibleBreakpoints,
|
|
2498
2844
|
getProperties,
|
|
2845
|
+
getScriptSource,
|
|
2499
2846
|
listScripts,
|
|
2500
2847
|
openCfTunnel,
|
|
2848
|
+
openOwnedCfTunnel,
|
|
2501
2849
|
parseBreakpointSpec,
|
|
2502
2850
|
parseRemoteRoot,
|
|
2851
|
+
releaseObject,
|
|
2852
|
+
releaseObjectGroup,
|
|
2503
2853
|
removeBreakpoint,
|
|
2504
2854
|
resume,
|
|
2505
2855
|
runSetupEvals,
|
|
2506
2856
|
setBreakpoint,
|
|
2857
|
+
setBreakpointAtLocation,
|
|
2507
2858
|
setPauseOnExceptions,
|
|
2859
|
+
stepInto,
|
|
2860
|
+
stepOut,
|
|
2861
|
+
stepOver,
|
|
2508
2862
|
streamLogpoint,
|
|
2509
2863
|
validateExpression,
|
|
2510
2864
|
waitForPause,
|