@saptools/cf-inspector 0.7.0 → 0.8.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 +63 -1
- package/dist/cli.js +599 -142
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +29 -7
- package/dist/index.js +60 -3
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -152,16 +152,16 @@ var init_wsTransport = __esm({
|
|
|
152
152
|
});
|
|
153
153
|
|
|
154
154
|
// src/cli.ts
|
|
155
|
-
import
|
|
155
|
+
import process13 from "process";
|
|
156
156
|
|
|
157
157
|
// src/cli/program.ts
|
|
158
158
|
import { readFileSync } from "fs";
|
|
159
|
-
import { dirname, join } from "path";
|
|
159
|
+
import { dirname, join as join2 } from "path";
|
|
160
160
|
import { fileURLToPath } from "url";
|
|
161
161
|
import { Command } from "commander";
|
|
162
162
|
|
|
163
163
|
// src/cli/commands/attach.ts
|
|
164
|
-
import
|
|
164
|
+
import process4 from "process";
|
|
165
165
|
|
|
166
166
|
// src/inspector/discovery.ts
|
|
167
167
|
init_types();
|
|
@@ -386,13 +386,22 @@ function startInspectorKeepalive(host, port, options = {}) {
|
|
|
386
386
|
}
|
|
387
387
|
|
|
388
388
|
// src/cli/output.ts
|
|
389
|
-
import
|
|
389
|
+
import process2 from "process";
|
|
390
390
|
function writeProgress(message) {
|
|
391
|
-
|
|
391
|
+
process2.stderr.write(`[cf-inspector] ${message}
|
|
392
|
+
`);
|
|
393
|
+
}
|
|
394
|
+
function writeArmedEvent(event) {
|
|
395
|
+
const payload = {
|
|
396
|
+
event: "breakpoint-armed",
|
|
397
|
+
schemaVersion: 1,
|
|
398
|
+
...event
|
|
399
|
+
};
|
|
400
|
+
process2.stderr.write(`${JSON.stringify(payload)}
|
|
392
401
|
`);
|
|
393
402
|
}
|
|
394
403
|
function writeJson(value) {
|
|
395
|
-
|
|
404
|
+
process2.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
396
405
|
`);
|
|
397
406
|
}
|
|
398
407
|
function writeHumanSnapshot(snapshot) {
|
|
@@ -423,7 +432,7 @@ function writeHumanSnapshot(snapshot) {
|
|
|
423
432
|
appendStackFrameLine(lines, frame);
|
|
424
433
|
}
|
|
425
434
|
}
|
|
426
|
-
|
|
435
|
+
process2.stdout.write(`${lines.join("\n")}
|
|
427
436
|
`);
|
|
428
437
|
}
|
|
429
438
|
function appendFrameLines(lines, frame) {
|
|
@@ -466,36 +475,36 @@ function appendExceptionLines(lines, exception) {
|
|
|
466
475
|
}
|
|
467
476
|
function writeLogEvent(event, json) {
|
|
468
477
|
if (json) {
|
|
469
|
-
|
|
478
|
+
process2.stdout.write(`${JSON.stringify(event)}
|
|
470
479
|
`);
|
|
471
480
|
return;
|
|
472
481
|
}
|
|
473
482
|
const isolateSuffix = event.isolate === void 0 ? "" : ` (${formatIsolate(event.isolate)})`;
|
|
474
483
|
if (event.error !== void 0) {
|
|
475
|
-
|
|
484
|
+
process2.stdout.write(`[${event.ts}] ${event.at}${isolateSuffix} !err ${renderTruncated(event.error, event)}
|
|
476
485
|
`);
|
|
477
486
|
return;
|
|
478
487
|
}
|
|
479
|
-
|
|
488
|
+
process2.stdout.write(`[${event.ts}] ${event.at}${isolateSuffix} ${renderTruncated(event.value ?? "", event)}
|
|
480
489
|
`);
|
|
481
490
|
}
|
|
482
491
|
function writeWatchEvent(event, json) {
|
|
483
492
|
if (json) {
|
|
484
|
-
|
|
493
|
+
process2.stdout.write(`${JSON.stringify(event)}
|
|
485
494
|
`);
|
|
486
495
|
return;
|
|
487
496
|
}
|
|
488
|
-
|
|
497
|
+
process2.stdout.write(
|
|
489
498
|
`[${event.ts}] hit#${event.hit.toString()} ${event.at} (${formatIsolate(event.isolate)})
|
|
490
499
|
`
|
|
491
500
|
);
|
|
492
501
|
if (event.exception !== void 0) {
|
|
493
|
-
|
|
502
|
+
process2.stdout.write(` exception: ${renderExceptionDetail(event.exception)}
|
|
494
503
|
`);
|
|
495
504
|
}
|
|
496
505
|
for (const capture of event.captures) {
|
|
497
506
|
const detail = capture.error ?? capture.value ?? "undefined";
|
|
498
|
-
|
|
507
|
+
process2.stdout.write(` ${capture.expression} = ${renderTruncated(detail, capture)}
|
|
499
508
|
`);
|
|
500
509
|
}
|
|
501
510
|
}
|
|
@@ -1776,9 +1785,247 @@ var DEFAULT_BREAKPOINT_TIMEOUT_SEC = 30;
|
|
|
1776
1785
|
var DEFAULT_CF_TIMEOUT_SEC = 180;
|
|
1777
1786
|
var DEFAULT_EXCEPTION_TIMEOUT_SEC = 30;
|
|
1778
1787
|
|
|
1788
|
+
// src/cli/sessionLock.ts
|
|
1789
|
+
init_types();
|
|
1790
|
+
import { execFileSync } from "child_process";
|
|
1791
|
+
import { createHash, randomUUID } from "crypto";
|
|
1792
|
+
import { constants } from "fs";
|
|
1793
|
+
import { mkdir, open, readFile, readdir, stat, unlink, writeFile } from "fs/promises";
|
|
1794
|
+
import { homedir } from "os";
|
|
1795
|
+
import { join } from "path";
|
|
1796
|
+
var ELECTION_WINDOW_MS = 25;
|
|
1797
|
+
var LOCK_FILE_SUFFIX = ".lock";
|
|
1798
|
+
async function acquireDebugSessionLock(target, options = {}) {
|
|
1799
|
+
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
1800
|
+
const pid = options.pid ?? process.pid;
|
|
1801
|
+
const getProcessStart = options.getProcessStart ?? processStart;
|
|
1802
|
+
const ownerProcessStart = getProcessStart(pid);
|
|
1803
|
+
const token = options.token?.() ?? randomUUID();
|
|
1804
|
+
const targetIdentity = debugTargetIdentity(target);
|
|
1805
|
+
const key = createHash("sha256").update(targetIdentity).digest("hex");
|
|
1806
|
+
const lockRoot = options.stateRoot ?? defaultStateRoot();
|
|
1807
|
+
const lockDirectory = join(lockRoot, "cf-inspector", "locks");
|
|
1808
|
+
const ownPath = join(lockDirectory, `${key}.${pid.toString()}.${token}${LOCK_FILE_SUFFIX}`);
|
|
1809
|
+
const metadata = {
|
|
1810
|
+
pid,
|
|
1811
|
+
...ownerProcessStart === void 0 ? {} : { processStart: ownerProcessStart },
|
|
1812
|
+
state: "pending",
|
|
1813
|
+
startedAt: now().toISOString(),
|
|
1814
|
+
token,
|
|
1815
|
+
target: targetIdentity
|
|
1816
|
+
};
|
|
1817
|
+
await mkdir(lockDirectory, { recursive: true, mode: 448 });
|
|
1818
|
+
const handle = await open(ownPath, constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY, 384);
|
|
1819
|
+
try {
|
|
1820
|
+
await handle.writeFile(`${JSON.stringify(metadata)}
|
|
1821
|
+
`, "utf8");
|
|
1822
|
+
} finally {
|
|
1823
|
+
await handle.close();
|
|
1824
|
+
}
|
|
1825
|
+
try {
|
|
1826
|
+
await new Promise((resolve) => {
|
|
1827
|
+
setTimeout(resolve, ELECTION_WINDOW_MS);
|
|
1828
|
+
});
|
|
1829
|
+
const contenders = await findLiveContenders(
|
|
1830
|
+
lockDirectory,
|
|
1831
|
+
key,
|
|
1832
|
+
ownPath,
|
|
1833
|
+
options.isProcessAlive ?? processIsAlive,
|
|
1834
|
+
getProcessStart
|
|
1835
|
+
);
|
|
1836
|
+
const owner = contenders.find((candidate) => candidate.state === "owned") ?? contenders.filter((candidate) => candidate.state === "pending" && candidate.token < token).sort((left, right) => left.token.localeCompare(right.token))[0];
|
|
1837
|
+
if (owner !== void 0) {
|
|
1838
|
+
throw alreadyDebuggedError(owner);
|
|
1839
|
+
}
|
|
1840
|
+
await writeLockMetadata(ownPath, { ...metadata, state: "owned" });
|
|
1841
|
+
} catch (error) {
|
|
1842
|
+
await unlink(ownPath).catch(() => {
|
|
1843
|
+
});
|
|
1844
|
+
throw error;
|
|
1845
|
+
}
|
|
1846
|
+
let released = false;
|
|
1847
|
+
return {
|
|
1848
|
+
path: ownPath,
|
|
1849
|
+
release: async () => {
|
|
1850
|
+
if (released) {
|
|
1851
|
+
return;
|
|
1852
|
+
}
|
|
1853
|
+
released = true;
|
|
1854
|
+
const current = await readLockMetadata(ownPath);
|
|
1855
|
+
if (current?.token !== token || current.pid !== pid) {
|
|
1856
|
+
return;
|
|
1857
|
+
}
|
|
1858
|
+
await unlink(ownPath).catch((error) => {
|
|
1859
|
+
if (!isNodeError(error, "ENOENT")) {
|
|
1860
|
+
throw error;
|
|
1861
|
+
}
|
|
1862
|
+
});
|
|
1863
|
+
}
|
|
1864
|
+
};
|
|
1865
|
+
}
|
|
1866
|
+
function debugTargetIdentity(target) {
|
|
1867
|
+
const targetIndex = target.targetIndex ?? 0;
|
|
1868
|
+
if (target.kind === "port") {
|
|
1869
|
+
return JSON.stringify({
|
|
1870
|
+
kind: "port",
|
|
1871
|
+
host: normalizeHost(target.host),
|
|
1872
|
+
port: target.port,
|
|
1873
|
+
targetIndex
|
|
1874
|
+
});
|
|
1875
|
+
}
|
|
1876
|
+
return JSON.stringify({
|
|
1877
|
+
kind: "cf",
|
|
1878
|
+
region: target.region,
|
|
1879
|
+
org: target.org,
|
|
1880
|
+
space: target.space,
|
|
1881
|
+
app: target.app,
|
|
1882
|
+
targetIndex
|
|
1883
|
+
});
|
|
1884
|
+
}
|
|
1885
|
+
function defaultStateRoot() {
|
|
1886
|
+
const configured = process.env["CF_INSPECTOR_STATE_DIR"]?.trim();
|
|
1887
|
+
return configured === void 0 || configured.length === 0 ? join(homedir(), ".saptools") : configured;
|
|
1888
|
+
}
|
|
1889
|
+
async function findLiveContenders(lockDirectory, key, ownPath, isProcessAlive, getProcessStart) {
|
|
1890
|
+
const prefix = `${key}.`;
|
|
1891
|
+
const names = await readdir(lockDirectory);
|
|
1892
|
+
const contenders = [];
|
|
1893
|
+
for (const name of names) {
|
|
1894
|
+
if (!name.startsWith(prefix) || !name.endsWith(LOCK_FILE_SUFFIX)) {
|
|
1895
|
+
continue;
|
|
1896
|
+
}
|
|
1897
|
+
const path = join(lockDirectory, name);
|
|
1898
|
+
if (path === ownPath) {
|
|
1899
|
+
continue;
|
|
1900
|
+
}
|
|
1901
|
+
const info = await stat(path).catch(() => {
|
|
1902
|
+
});
|
|
1903
|
+
const metadata = await readLockMetadata(path) ?? (info === void 0 ? void 0 : metadataFromFilename(name, key, info.mtimeMs));
|
|
1904
|
+
if (metadata !== void 0) {
|
|
1905
|
+
if (ownerIsAlive(metadata, isProcessAlive, getProcessStart)) {
|
|
1906
|
+
contenders.push(metadata);
|
|
1907
|
+
} else {
|
|
1908
|
+
await unlink(path).catch(() => {
|
|
1909
|
+
});
|
|
1910
|
+
}
|
|
1911
|
+
continue;
|
|
1912
|
+
}
|
|
1913
|
+
if (info !== void 0) {
|
|
1914
|
+
contenders.push({
|
|
1915
|
+
pid: 0,
|
|
1916
|
+
state: "owned",
|
|
1917
|
+
startedAt: new Date(info.mtimeMs).toISOString(),
|
|
1918
|
+
token: "unknown",
|
|
1919
|
+
target: "unknown"
|
|
1920
|
+
});
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1923
|
+
return contenders;
|
|
1924
|
+
}
|
|
1925
|
+
async function readLockMetadata(path) {
|
|
1926
|
+
try {
|
|
1927
|
+
const parsed = JSON.parse(await readFile(path, "utf8"));
|
|
1928
|
+
if (!isRecord2(parsed)) {
|
|
1929
|
+
return void 0;
|
|
1930
|
+
}
|
|
1931
|
+
const pid = parsed["pid"];
|
|
1932
|
+
const processStart2 = parsed["processStart"];
|
|
1933
|
+
const state = parsed["state"];
|
|
1934
|
+
const startedAt = parsed["startedAt"];
|
|
1935
|
+
const token = parsed["token"];
|
|
1936
|
+
const target = parsed["target"];
|
|
1937
|
+
if (typeof pid !== "number" || !Number.isSafeInteger(pid) || pid <= 0 || processStart2 !== void 0 && typeof processStart2 !== "string" || state !== "pending" && state !== "owned" || typeof startedAt !== "string" || Number.isNaN(Date.parse(startedAt)) || typeof token !== "string" || token.length === 0 || typeof target !== "string" || target.length === 0) {
|
|
1938
|
+
return void 0;
|
|
1939
|
+
}
|
|
1940
|
+
return {
|
|
1941
|
+
pid,
|
|
1942
|
+
...typeof processStart2 === "string" ? { processStart: processStart2 } : {},
|
|
1943
|
+
state,
|
|
1944
|
+
startedAt,
|
|
1945
|
+
token,
|
|
1946
|
+
target
|
|
1947
|
+
};
|
|
1948
|
+
} catch {
|
|
1949
|
+
return void 0;
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
async function writeLockMetadata(path, metadata) {
|
|
1953
|
+
await writeFile(path, `${JSON.stringify(metadata)}
|
|
1954
|
+
`, { encoding: "utf8", mode: 384 });
|
|
1955
|
+
}
|
|
1956
|
+
function metadataFromFilename(name, key, mtimeMs) {
|
|
1957
|
+
const match = new RegExp(`^${key}\\.(\\d+)\\.(.+)\\${LOCK_FILE_SUFFIX}$`, "u").exec(name);
|
|
1958
|
+
const rawPid = match?.[1];
|
|
1959
|
+
const token = match?.[2];
|
|
1960
|
+
if (rawPid === void 0 || token === void 0 || token.length === 0) {
|
|
1961
|
+
return void 0;
|
|
1962
|
+
}
|
|
1963
|
+
const pid = Number.parseInt(rawPid, 10);
|
|
1964
|
+
if (!Number.isSafeInteger(pid) || pid <= 0) {
|
|
1965
|
+
return void 0;
|
|
1966
|
+
}
|
|
1967
|
+
return {
|
|
1968
|
+
pid,
|
|
1969
|
+
state: "owned",
|
|
1970
|
+
startedAt: new Date(mtimeMs).toISOString(),
|
|
1971
|
+
token,
|
|
1972
|
+
target: "unknown"
|
|
1973
|
+
};
|
|
1974
|
+
}
|
|
1975
|
+
function ownerIsAlive(metadata, isProcessAlive, getProcessStart) {
|
|
1976
|
+
if (!isProcessAlive(metadata.pid)) {
|
|
1977
|
+
return false;
|
|
1978
|
+
}
|
|
1979
|
+
const currentStart = getProcessStart(metadata.pid);
|
|
1980
|
+
return metadata.processStart === void 0 || currentStart === void 0 || metadata.processStart === currentStart;
|
|
1981
|
+
}
|
|
1982
|
+
function processIsAlive(pid) {
|
|
1983
|
+
try {
|
|
1984
|
+
process.kill(pid, 0);
|
|
1985
|
+
const status = processStatus(pid);
|
|
1986
|
+
return !status?.startsWith("Z");
|
|
1987
|
+
} catch (error) {
|
|
1988
|
+
return isNodeError(error, "EPERM");
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
function processStatus(pid) {
|
|
1992
|
+
return runPs(pid, "stat=");
|
|
1993
|
+
}
|
|
1994
|
+
function processStart(pid) {
|
|
1995
|
+
return runPs(pid, "lstart=");
|
|
1996
|
+
}
|
|
1997
|
+
function runPs(pid, field) {
|
|
1998
|
+
try {
|
|
1999
|
+
const value = execFileSync("ps", ["-o", field, "-p", pid.toString()], {
|
|
2000
|
+
encoding: "utf8",
|
|
2001
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
2002
|
+
}).trim();
|
|
2003
|
+
return value.length === 0 ? void 0 : value;
|
|
2004
|
+
} catch {
|
|
2005
|
+
return void 0;
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
function alreadyDebuggedError(owner) {
|
|
2009
|
+
const ownerLabel = owner.pid > 0 ? `PID ${owner.pid.toString()}` : "an unknown process";
|
|
2010
|
+
return new CfInspectorError(
|
|
2011
|
+
"TARGET_ALREADY_DEBUGGED",
|
|
2012
|
+
`Another cf-inspector session (${ownerLabel}, started ${owner.startedAt}) is already actively debugging this target. Concurrent debugging sessions on the same isolate(s) can corrupt each other and disrupt real application traffic, so this attempt was refused rather than queued. Wait for the other session to finish, or confirm that it is gone before retrying; locks from dead processes are reclaimed automatically.`
|
|
2013
|
+
);
|
|
2014
|
+
}
|
|
2015
|
+
function normalizeHost(host) {
|
|
2016
|
+
const normalized = host.trim().toLowerCase();
|
|
2017
|
+
return normalized === "localhost" || normalized === "::1" ? "127.0.0.1" : normalized;
|
|
2018
|
+
}
|
|
2019
|
+
function isRecord2(value) {
|
|
2020
|
+
return typeof value === "object" && value !== null;
|
|
2021
|
+
}
|
|
2022
|
+
function isNodeError(error, code) {
|
|
2023
|
+
return error instanceof Error && "code" in error && error.code === code;
|
|
2024
|
+
}
|
|
2025
|
+
|
|
1779
2026
|
// src/cli/warnings.ts
|
|
1780
2027
|
init_types();
|
|
1781
|
-
import
|
|
2028
|
+
import process3 from "process";
|
|
1782
2029
|
|
|
1783
2030
|
// src/cli/captureParser.ts
|
|
1784
2031
|
function parseCaptureList(raw) {
|
|
@@ -1893,7 +2140,7 @@ function warnOnCaptureMutationRisk(expressions, allowMutation) {
|
|
|
1893
2140
|
return;
|
|
1894
2141
|
}
|
|
1895
2142
|
const suffix = allowMutation ? "will run without the V8 side-effect guard because --allow-mutation was passed." : "will be checked by the V8 side-effect guard and blocked unless V8 proves them safe; pass --allow-mutation to run them unrestricted.";
|
|
1896
|
-
|
|
2143
|
+
process3.stderr.write(
|
|
1897
2144
|
`[cf-inspector] warning: ${riskyCount.toString()} capture ${riskyCount === 1 ? "expression looks" : "expressions look"} mutation-capable and ${suffix}
|
|
1898
2145
|
`
|
|
1899
2146
|
);
|
|
@@ -1908,7 +2155,7 @@ function enforceNativeConditionMutationPolicy(expression, allowMutation, context
|
|
|
1908
2155
|
`${context} looks mutation-capable. Native breakpoint conditions cannot be protected by V8's side-effect guard; pass --allow-mutation to arm it explicitly.`
|
|
1909
2156
|
);
|
|
1910
2157
|
}
|
|
1911
|
-
|
|
2158
|
+
process3.stderr.write(
|
|
1912
2159
|
`[cf-inspector] warning: ${context} looks mutation-capable and will run as a native breakpoint condition; native conditions cannot be side-effect-gated.
|
|
1913
2160
|
`
|
|
1914
2161
|
);
|
|
@@ -1917,7 +2164,7 @@ function warnOnMutationRisk(expression, context) {
|
|
|
1917
2164
|
if (!looksLikeMutation(expression)) {
|
|
1918
2165
|
return;
|
|
1919
2166
|
}
|
|
1920
|
-
|
|
2167
|
+
process3.stderr.write(
|
|
1921
2168
|
`[cf-inspector] warning: ${context} looks mutation-capable and will execute against the live inspectee without a side-effect guard.
|
|
1922
2169
|
`
|
|
1923
2170
|
);
|
|
@@ -1926,7 +2173,7 @@ function warnOnUnboundBreakpoints(handles) {
|
|
|
1926
2173
|
for (const handle of handles) {
|
|
1927
2174
|
if (handle.resolvedLocations.length === 0) {
|
|
1928
2175
|
const tsHint = handle.file.endsWith(".ts") ? " Hint: Source TS breakpoints may not bind. Try inspecting loaded scripts with list-scripts and target the compiled .js file instead." : "";
|
|
1929
|
-
|
|
2176
|
+
process3.stderr.write(
|
|
1930
2177
|
`[cf-inspector] warning: breakpoint ${handle.file}:${handle.line.toString()} did not bind to any loaded script. Check the path or pass --remote-root. Use 'list-scripts' to inspect what V8 currently has loaded.${tsHint}
|
|
1931
2178
|
`
|
|
1932
2179
|
);
|
|
@@ -1937,14 +2184,14 @@ function warnOnImplicitInspectorSelection(session, targetWasExplicit, workerWasE
|
|
|
1937
2184
|
const targetCount = session.targetCount ?? 1;
|
|
1938
2185
|
const targetIndex = session.targetIndex ?? 0;
|
|
1939
2186
|
if (!targetWasExplicit && targetCount > 1) {
|
|
1940
|
-
|
|
2187
|
+
process3.stderr.write(
|
|
1941
2188
|
`[cf-inspector] notice: attached to inspector target ${targetIndex.toString()} of ${targetCount.toString()}; pass --target <index> to pick another.
|
|
1942
2189
|
`
|
|
1943
2190
|
);
|
|
1944
2191
|
}
|
|
1945
2192
|
const workerCount = session.workerTargets?.length ?? 0;
|
|
1946
2193
|
if (!workerWasExplicit && workerCount > 0) {
|
|
1947
|
-
|
|
2194
|
+
process3.stderr.write(
|
|
1948
2195
|
`[cf-inspector] notice: attached to the main isolate; ${workerCount.toString()} Node ${workerCount === 1 ? "worker is" : "workers are"} available. This command is single-isolate by nature; use --worker-id <id> to inspect one worker explicitly.
|
|
1949
2196
|
`
|
|
1950
2197
|
);
|
|
@@ -1957,7 +2204,7 @@ function warnOnBoundBreakpointWithoutHit(handles) {
|
|
|
1957
2204
|
if (boundCount === 0) {
|
|
1958
2205
|
return;
|
|
1959
2206
|
}
|
|
1960
|
-
|
|
2207
|
+
process3.stderr.write(
|
|
1961
2208
|
`[cf-inspector] warning: ${boundCount.toString()} breakpoint ${boundCount === 1 ? "location bound" : "locations bound"}, but no hit was observed. No selected isolate executed the location before the command stopped. Check conditions, hit counts, request traffic, and use check-breakpoint to verify the exact line.
|
|
1962
2209
|
`
|
|
1963
2210
|
);
|
|
@@ -1967,7 +2214,7 @@ function roundDurationMs(durationMs) {
|
|
|
1967
2214
|
}
|
|
1968
2215
|
function warnOnUnmatchedPause(pause) {
|
|
1969
2216
|
const reason = pause.reason.length > 0 ? pause.reason : "unknown";
|
|
1970
|
-
|
|
2217
|
+
process3.stderr.write(
|
|
1971
2218
|
`[cf-inspector] warning: target is paused by another debugger event (${reason} at ${formatPauseLocation(pause)}); waiting for it to resume...
|
|
1972
2219
|
`
|
|
1973
2220
|
);
|
|
@@ -2142,65 +2389,75 @@ function parseWorkerId(value) {
|
|
|
2142
2389
|
return trimmed;
|
|
2143
2390
|
}
|
|
2144
2391
|
async function withSession(target, fn, reportProgress, signal) {
|
|
2145
|
-
const
|
|
2146
|
-
let session;
|
|
2392
|
+
const lock = await acquireDebugSessionLock(target);
|
|
2147
2393
|
try {
|
|
2148
|
-
reportProgress
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
...target.workerId === void 0 ? {} : { workerId: target.workerId }
|
|
2156
|
-
});
|
|
2157
|
-
warnOnImplicitInspectorSelection(
|
|
2158
|
-
session,
|
|
2159
|
-
target.targetIndex !== void 0,
|
|
2160
|
-
target.workerIndex !== void 0 || target.workerId !== void 0
|
|
2161
|
-
);
|
|
2162
|
-
reportProgress?.("Inspector session is ready.");
|
|
2163
|
-
return await fn(session, tunnel.port);
|
|
2164
|
-
} finally {
|
|
2165
|
-
if (session) {
|
|
2166
|
-
reportProgress?.("Closing the inspector session...");
|
|
2167
|
-
await session.dispose();
|
|
2168
|
-
reportProgress?.("Inspector session closed.");
|
|
2169
|
-
}
|
|
2170
|
-
await tunnel.dispose();
|
|
2171
|
-
}
|
|
2172
|
-
}
|
|
2173
|
-
async function withSessions(target, fn, reportProgress, signal) {
|
|
2174
|
-
const tunnel = await openTarget(target, reportProgress, signal);
|
|
2175
|
-
let group;
|
|
2176
|
-
try {
|
|
2177
|
-
reportProgress?.(
|
|
2178
|
-
`Connecting to the Node.js inspector at ${tunnel.host}:${tunnel.port.toString()}...`
|
|
2179
|
-
);
|
|
2180
|
-
const autoAttach = target.targetIndex === void 0 && target.workerIndex === void 0 && target.workerId === void 0 && target.mainOnly !== true;
|
|
2181
|
-
if (autoAttach) {
|
|
2182
|
-
group = await connectInspectorGroup({ port: tunnel.port, host: tunnel.host });
|
|
2183
|
-
} else {
|
|
2184
|
-
const session = await connectInspector({
|
|
2394
|
+
const tunnel = await openTarget(target, reportProgress, signal);
|
|
2395
|
+
let session;
|
|
2396
|
+
try {
|
|
2397
|
+
reportProgress?.(
|
|
2398
|
+
`Connecting to the Node.js inspector at ${tunnel.host}:${tunnel.port.toString()}...`
|
|
2399
|
+
);
|
|
2400
|
+
session = await connectInspector({
|
|
2185
2401
|
port: tunnel.port,
|
|
2186
2402
|
host: tunnel.host,
|
|
2187
|
-
...selectionOptions(target.targetIndex, target.workerIndex,
|
|
2403
|
+
...selectionOptions(target.targetIndex, target.workerIndex),
|
|
2404
|
+
...target.workerId === void 0 ? {} : { workerId: target.workerId }
|
|
2188
2405
|
});
|
|
2189
|
-
|
|
2406
|
+
warnOnImplicitInspectorSelection(
|
|
2407
|
+
session,
|
|
2408
|
+
target.targetIndex !== void 0,
|
|
2409
|
+
target.workerIndex !== void 0 || target.workerId !== void 0
|
|
2410
|
+
);
|
|
2411
|
+
reportProgress?.("Inspector session is ready.");
|
|
2412
|
+
return await fn(session, tunnel.port);
|
|
2413
|
+
} finally {
|
|
2414
|
+
if (session) {
|
|
2415
|
+
reportProgress?.("Closing the inspector session...");
|
|
2416
|
+
await session.dispose();
|
|
2417
|
+
reportProgress?.("Inspector session closed.");
|
|
2418
|
+
}
|
|
2419
|
+
await tunnel.dispose();
|
|
2190
2420
|
}
|
|
2191
|
-
reportProgress?.("Inspector session is ready.");
|
|
2192
|
-
return await fn(group, tunnel.port);
|
|
2193
2421
|
} finally {
|
|
2422
|
+
await lock.release();
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2425
|
+
async function withSessions(target, fn, reportProgress, signal) {
|
|
2426
|
+
const lock = await acquireDebugSessionLock(target);
|
|
2427
|
+
try {
|
|
2428
|
+
const tunnel = await openTarget(target, reportProgress, signal);
|
|
2429
|
+
let group;
|
|
2194
2430
|
try {
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2431
|
+
reportProgress?.(
|
|
2432
|
+
`Connecting to the Node.js inspector at ${tunnel.host}:${tunnel.port.toString()}...`
|
|
2433
|
+
);
|
|
2434
|
+
const autoAttach = target.targetIndex === void 0 && target.workerIndex === void 0 && target.workerId === void 0 && target.mainOnly !== true;
|
|
2435
|
+
if (autoAttach) {
|
|
2436
|
+
group = await connectInspectorGroup({ port: tunnel.port, host: tunnel.host });
|
|
2437
|
+
} else {
|
|
2438
|
+
const session = await connectInspector({
|
|
2439
|
+
port: tunnel.port,
|
|
2440
|
+
host: tunnel.host,
|
|
2441
|
+
...selectionOptions(target.targetIndex, target.workerIndex, target.workerId)
|
|
2442
|
+
});
|
|
2443
|
+
group = singleSessionGroup(session);
|
|
2200
2444
|
}
|
|
2445
|
+
reportProgress?.("Inspector session is ready.");
|
|
2446
|
+
return await fn(group, tunnel.port);
|
|
2201
2447
|
} finally {
|
|
2202
|
-
|
|
2448
|
+
try {
|
|
2449
|
+
if (group !== void 0) {
|
|
2450
|
+
const sessionCount = group.list().length;
|
|
2451
|
+
reportProgress?.(sessionCount === 1 ? "Closing the inspector session..." : `Closing ${sessionCount.toString()} inspector sessions...`);
|
|
2452
|
+
await group.dispose();
|
|
2453
|
+
reportProgress?.(sessionCount === 1 ? "Inspector session closed." : "Inspector sessions closed.");
|
|
2454
|
+
}
|
|
2455
|
+
} finally {
|
|
2456
|
+
await tunnel.dispose();
|
|
2457
|
+
}
|
|
2203
2458
|
}
|
|
2459
|
+
} finally {
|
|
2460
|
+
await lock.release();
|
|
2204
2461
|
}
|
|
2205
2462
|
}
|
|
2206
2463
|
function singleSessionGroup(session) {
|
|
@@ -2262,7 +2519,7 @@ async function handleAttach(opts) {
|
|
|
2262
2519
|
writeJson({ host: tunnel.host, port: tunnel.port, ...version });
|
|
2263
2520
|
return;
|
|
2264
2521
|
}
|
|
2265
|
-
|
|
2522
|
+
process4.stdout.write(
|
|
2266
2523
|
`Connected to ${tunnel.host}:${tunnel.port.toString()}
|
|
2267
2524
|
Browser: ${version.browser}
|
|
2268
2525
|
Protocol: ${version.protocolVersion}
|
|
@@ -2274,7 +2531,7 @@ async function handleAttach(opts) {
|
|
|
2274
2531
|
}
|
|
2275
2532
|
|
|
2276
2533
|
// src/cli/commands/checkBreakpoint.ts
|
|
2277
|
-
import
|
|
2534
|
+
import process5 from "process";
|
|
2278
2535
|
|
|
2279
2536
|
// src/pathMapper.ts
|
|
2280
2537
|
init_types();
|
|
@@ -2561,25 +2818,25 @@ async function checkSession(session, matcher, requestedLine) {
|
|
|
2561
2818
|
}
|
|
2562
2819
|
function writeHumanCheck(result) {
|
|
2563
2820
|
if (result.status === "script-not-loaded") {
|
|
2564
|
-
|
|
2821
|
+
process5.stdout.write(
|
|
2565
2822
|
`${result.file}:${result.line.toString()} does not match any loaded script. Run list-scripts and check --remote-root/path mapping, or trigger lazy module loading first.
|
|
2566
2823
|
`
|
|
2567
2824
|
);
|
|
2568
2825
|
return;
|
|
2569
2826
|
}
|
|
2570
2827
|
if (result.status === "unbreakable") {
|
|
2571
|
-
|
|
2828
|
+
process5.stdout.write(
|
|
2572
2829
|
`${result.file}:${result.line.toString()} matches a loaded script, but this exact line has no breakable location. Try a neighboring executable line.
|
|
2573
2830
|
`
|
|
2574
2831
|
);
|
|
2575
2832
|
return;
|
|
2576
2833
|
}
|
|
2577
|
-
|
|
2834
|
+
process5.stdout.write(`${result.file}:${result.line.toString()} is breakable:
|
|
2578
2835
|
`);
|
|
2579
2836
|
for (const script of result.scripts) {
|
|
2580
2837
|
for (const location of script.locations) {
|
|
2581
2838
|
const isolate = script.isolate.kind === "main" ? "main" : `worker ${script.isolate.workerId}`;
|
|
2582
|
-
|
|
2839
|
+
process5.stdout.write(
|
|
2583
2840
|
` ${isolate} ${script.url} line ${(location.lineNumber + 1).toString()}:${((location.columnNumber ?? 0) + 1).toString()}
|
|
2584
2841
|
`
|
|
2585
2842
|
);
|
|
@@ -2588,7 +2845,7 @@ function writeHumanCheck(result) {
|
|
|
2588
2845
|
}
|
|
2589
2846
|
|
|
2590
2847
|
// src/cli/commands/eval.ts
|
|
2591
|
-
import
|
|
2848
|
+
import process6 from "process";
|
|
2592
2849
|
|
|
2593
2850
|
// src/inspector/runtime.ts
|
|
2594
2851
|
init_types();
|
|
@@ -2685,7 +2942,7 @@ async function handleEval(opts) {
|
|
|
2685
2942
|
if (opts.json) {
|
|
2686
2943
|
writeJson(result);
|
|
2687
2944
|
if (result.exceptionDetails !== void 0) {
|
|
2688
|
-
|
|
2945
|
+
process6.exitCode = 1;
|
|
2689
2946
|
}
|
|
2690
2947
|
return;
|
|
2691
2948
|
}
|
|
@@ -2694,33 +2951,33 @@ async function handleEval(opts) {
|
|
|
2694
2951
|
function writeHumanEvalResult(result) {
|
|
2695
2952
|
if (result.exceptionDetails !== void 0) {
|
|
2696
2953
|
const detail = typeof result.exceptionDetails.exception?.description === "string" ? result.exceptionDetails.exception.description : typeof result.exceptionDetails.text === "string" ? result.exceptionDetails.text : "evaluation failed";
|
|
2697
|
-
|
|
2954
|
+
process6.stderr.write(`${detail}
|
|
2698
2955
|
`);
|
|
2699
|
-
|
|
2956
|
+
process6.exitCode = 1;
|
|
2700
2957
|
return;
|
|
2701
2958
|
}
|
|
2702
2959
|
const inner = result.result;
|
|
2703
2960
|
if (inner === void 0) {
|
|
2704
|
-
|
|
2961
|
+
process6.stdout.write("\n");
|
|
2705
2962
|
return;
|
|
2706
2963
|
}
|
|
2707
2964
|
if (typeof inner.value === "string") {
|
|
2708
|
-
|
|
2965
|
+
process6.stdout.write(`${inner.value}
|
|
2709
2966
|
`);
|
|
2710
2967
|
return;
|
|
2711
2968
|
}
|
|
2712
2969
|
if (typeof inner.description === "string") {
|
|
2713
|
-
|
|
2970
|
+
process6.stdout.write(`${inner.description}
|
|
2714
2971
|
`);
|
|
2715
2972
|
return;
|
|
2716
2973
|
}
|
|
2717
|
-
|
|
2974
|
+
process6.stdout.write(`${JSON.stringify(inner.value)}
|
|
2718
2975
|
`);
|
|
2719
2976
|
}
|
|
2720
2977
|
|
|
2721
2978
|
// src/cli/commands/exception.ts
|
|
2722
2979
|
import { performance as performance5 } from "perf_hooks";
|
|
2723
|
-
import
|
|
2980
|
+
import process8 from "process";
|
|
2724
2981
|
|
|
2725
2982
|
// src/inspector/pause.ts
|
|
2726
2983
|
init_types();
|
|
@@ -2855,6 +3112,8 @@ var BreakpointFanout = class {
|
|
|
2855
3112
|
detachError;
|
|
2856
3113
|
activeRace;
|
|
2857
3114
|
pauseReasons = [];
|
|
3115
|
+
pendingSetupError;
|
|
3116
|
+
preserveReadinessErrors = false;
|
|
2858
3117
|
constructor(group, setupSession, pauseReasons = []) {
|
|
2859
3118
|
this.pauseReasons = pauseReasons;
|
|
2860
3119
|
this.detach = group.onSession((session) => {
|
|
@@ -2880,13 +3139,51 @@ var BreakpointFanout = class {
|
|
|
2880
3139
|
this.activeRace?.remove(session);
|
|
2881
3140
|
});
|
|
2882
3141
|
this.detachError = group.onError((error) => {
|
|
3142
|
+
if (this.setupErrors.length === 0 && this.pendingSetupError === void 0) {
|
|
3143
|
+
this.pendingSetupError = error;
|
|
3144
|
+
}
|
|
2883
3145
|
for (const reject of this.setupErrors) {
|
|
2884
3146
|
reject(error);
|
|
2885
3147
|
}
|
|
2886
3148
|
});
|
|
2887
3149
|
}
|
|
2888
|
-
async ready() {
|
|
2889
|
-
|
|
3150
|
+
async ready(options = {}) {
|
|
3151
|
+
if (options.includeNewSessions !== true) {
|
|
3152
|
+
const records = [...this.records.values()];
|
|
3153
|
+
await Promise.all(records.map((record) => record.setup));
|
|
3154
|
+
options.onReady?.(this.outcomesFor(records));
|
|
3155
|
+
return;
|
|
3156
|
+
}
|
|
3157
|
+
this.preserveReadinessErrors = true;
|
|
3158
|
+
const pendingError = this.takePendingSetupError();
|
|
3159
|
+
if (pendingError !== void 0) {
|
|
3160
|
+
throw pendingError;
|
|
3161
|
+
}
|
|
3162
|
+
let rejectGroupError = () => void 0;
|
|
3163
|
+
const groupError = new Promise((_resolve, reject) => {
|
|
3164
|
+
rejectGroupError = reject;
|
|
3165
|
+
});
|
|
3166
|
+
this.setupErrors.push(rejectGroupError);
|
|
3167
|
+
try {
|
|
3168
|
+
let stableRecords;
|
|
3169
|
+
while (stableRecords === void 0) {
|
|
3170
|
+
const records = [...this.records.values()];
|
|
3171
|
+
await Promise.race([
|
|
3172
|
+
Promise.all(records.map((record) => record.setup)),
|
|
3173
|
+
groupError
|
|
3174
|
+
]);
|
|
3175
|
+
const stable = records.length === this.records.size && records.every((record) => this.records.get(record.session) === record);
|
|
3176
|
+
if (stable) {
|
|
3177
|
+
stableRecords = records;
|
|
3178
|
+
}
|
|
3179
|
+
}
|
|
3180
|
+
options.onReady?.(this.outcomesFor(stableRecords));
|
|
3181
|
+
} finally {
|
|
3182
|
+
const index = this.setupErrors.indexOf(rejectGroupError);
|
|
3183
|
+
if (index >= 0) {
|
|
3184
|
+
this.setupErrors.splice(index, 1);
|
|
3185
|
+
}
|
|
3186
|
+
}
|
|
2890
3187
|
}
|
|
2891
3188
|
trackHandle(session, handle) {
|
|
2892
3189
|
const record = this.records.get(session);
|
|
@@ -2895,11 +3192,19 @@ var BreakpointFanout = class {
|
|
|
2895
3192
|
}
|
|
2896
3193
|
}
|
|
2897
3194
|
availableOutcomes() {
|
|
2898
|
-
return [...this.records.values()]
|
|
3195
|
+
return this.outcomesFor([...this.records.values()]);
|
|
3196
|
+
}
|
|
3197
|
+
outcomesFor(records) {
|
|
3198
|
+
return records.map((record) => ({
|
|
2899
3199
|
session: record.session,
|
|
2900
3200
|
setup: { handles: record.handles }
|
|
2901
3201
|
}));
|
|
2902
3202
|
}
|
|
3203
|
+
takePendingSetupError() {
|
|
3204
|
+
const error = this.pendingSetupError;
|
|
3205
|
+
this.pendingSetupError = void 0;
|
|
3206
|
+
return error;
|
|
3207
|
+
}
|
|
2903
3208
|
async waitForFirst(timeoutMs, options = {}, signal) {
|
|
2904
3209
|
if (this.activeRace !== void 0) {
|
|
2905
3210
|
throw new CfInspectorError("INVALID_ARGUMENT", "A fan-out pause race is already active");
|
|
@@ -2908,6 +3213,12 @@ var BreakpointFanout = class {
|
|
|
2908
3213
|
this.pauseReasons = options.pauseReasons ?? [];
|
|
2909
3214
|
this.activeRace = race;
|
|
2910
3215
|
this.setupErrors.push(race.reject);
|
|
3216
|
+
if (this.preserveReadinessErrors) {
|
|
3217
|
+
const pendingError = this.takePendingSetupError();
|
|
3218
|
+
if (pendingError !== void 0) {
|
|
3219
|
+
race.reject(pendingError);
|
|
3220
|
+
}
|
|
3221
|
+
}
|
|
2911
3222
|
for (const record of this.records.values()) {
|
|
2912
3223
|
race.add(record);
|
|
2913
3224
|
}
|
|
@@ -3814,19 +4125,19 @@ async function captureExpression(session, callFrameId, expression, maxValueLengt
|
|
|
3814
4125
|
init_types();
|
|
3815
4126
|
|
|
3816
4127
|
// src/cli/signals.ts
|
|
3817
|
-
import
|
|
4128
|
+
import process7 from "process";
|
|
3818
4129
|
async function withTerminationSignal(fn) {
|
|
3819
4130
|
const abort = new AbortController();
|
|
3820
4131
|
const onSignal = () => {
|
|
3821
4132
|
abort.abort();
|
|
3822
4133
|
};
|
|
3823
|
-
|
|
3824
|
-
|
|
4134
|
+
process7.once("SIGINT", onSignal);
|
|
4135
|
+
process7.once("SIGTERM", onSignal);
|
|
3825
4136
|
try {
|
|
3826
4137
|
return await fn(abort.signal);
|
|
3827
4138
|
} finally {
|
|
3828
|
-
|
|
3829
|
-
|
|
4139
|
+
process7.off("SIGINT", onSignal);
|
|
4140
|
+
process7.off("SIGTERM", onSignal);
|
|
3830
4141
|
}
|
|
3831
4142
|
}
|
|
3832
4143
|
|
|
@@ -3878,7 +4189,20 @@ async function runExceptionCommand(command, opts, signal) {
|
|
|
3878
4189
|
let winner;
|
|
3879
4190
|
let preserveWinner = false;
|
|
3880
4191
|
try {
|
|
3881
|
-
await fanout.ready(
|
|
4192
|
+
await fanout.ready(opts.readyEvent === true ? {
|
|
4193
|
+
includeNewSessions: true,
|
|
4194
|
+
onReady: (outcomes) => {
|
|
4195
|
+
if (signal?.aborted === true) {
|
|
4196
|
+
return;
|
|
4197
|
+
}
|
|
4198
|
+
writeArmedEvent({
|
|
4199
|
+
command: "exception",
|
|
4200
|
+
sessions: outcomes.length,
|
|
4201
|
+
resolvedLocations: null,
|
|
4202
|
+
timeoutMs: command.timeoutMs
|
|
4203
|
+
});
|
|
4204
|
+
}
|
|
4205
|
+
} : {});
|
|
3882
4206
|
const hit = await fanout.waitForFirst(command.timeoutMs, {
|
|
3883
4207
|
pauseReasons: ["exception", "promiseRejection"],
|
|
3884
4208
|
unmatchedPausePolicy: "wait-for-resume"
|
|
@@ -3913,7 +4237,7 @@ async function resumeAfterException(session, snapshot, pausedStartedAt) {
|
|
|
3913
4237
|
await resume(session);
|
|
3914
4238
|
return withPausedDuration(snapshot, roundDurationMs(performance5.now() - pausedStartedAt));
|
|
3915
4239
|
} catch {
|
|
3916
|
-
|
|
4240
|
+
process8.stderr.write(
|
|
3917
4241
|
"[cf-inspector] warning: Debugger.resume failed after exception capture; pausedDurationMs is unknown.\n"
|
|
3918
4242
|
);
|
|
3919
4243
|
return withPausedDuration(snapshot, null);
|
|
@@ -3927,20 +4251,48 @@ async function disablePauseOnExceptionsBestEffort(session) {
|
|
|
3927
4251
|
}
|
|
3928
4252
|
|
|
3929
4253
|
// src/cli/commands/listScripts.ts
|
|
3930
|
-
import
|
|
4254
|
+
import process9 from "process";
|
|
3931
4255
|
async function handleListScripts(opts) {
|
|
3932
4256
|
const target = await resolveTargetWithCurrentCfTarget(opts);
|
|
3933
4257
|
const filter = compileScriptUrlFilter(opts.filter);
|
|
3934
|
-
const scripts = (await
|
|
4258
|
+
const scripts = (await withSessions(target, (group) => {
|
|
4259
|
+
const sessions = group.list();
|
|
4260
|
+
warnOnListScriptsSelection(target, {
|
|
4261
|
+
targetCount: group.targetCount,
|
|
4262
|
+
targetIndex: group.targetIndex,
|
|
4263
|
+
...sessions[0]?.workerTargets === void 0 ? {} : { workerTargets: sessions[0].workerTargets }
|
|
4264
|
+
});
|
|
4265
|
+
return Promise.resolve(collectListedScripts(sessions));
|
|
4266
|
+
})).filter((script) => filter === void 0 || filter(script.url));
|
|
3935
4267
|
if (opts.json) {
|
|
3936
4268
|
writeJson(scripts);
|
|
3937
4269
|
return;
|
|
3938
4270
|
}
|
|
3939
4271
|
for (const script of scripts) {
|
|
3940
|
-
|
|
3941
|
-
|
|
4272
|
+
process9.stdout.write(
|
|
4273
|
+
`${script.scriptId} ${script.url} ${formatIsolate2(script.isolate)}
|
|
4274
|
+
`
|
|
4275
|
+
);
|
|
3942
4276
|
}
|
|
3943
4277
|
}
|
|
4278
|
+
function warnOnListScriptsSelection(target, selection) {
|
|
4279
|
+
const autoAttach = target.targetIndex === void 0 && target.workerIndex === void 0 && target.workerId === void 0 && target.mainOnly !== true;
|
|
4280
|
+
const isolateWasExplicit = autoAttach || target.workerIndex !== void 0 || target.workerId !== void 0 || target.mainOnly === true;
|
|
4281
|
+
warnOnImplicitInspectorSelection(
|
|
4282
|
+
selection,
|
|
4283
|
+
target.targetIndex !== void 0,
|
|
4284
|
+
isolateWasExplicit
|
|
4285
|
+
);
|
|
4286
|
+
}
|
|
4287
|
+
function collectListedScripts(sessions) {
|
|
4288
|
+
return sessions.flatMap((session) => listScripts(session).map((script) => ({
|
|
4289
|
+
...script,
|
|
4290
|
+
isolate: session.isolate ?? { kind: "main" }
|
|
4291
|
+
})));
|
|
4292
|
+
}
|
|
4293
|
+
function formatIsolate2(isolate) {
|
|
4294
|
+
return isolate.kind === "worker" ? `worker:${isolate.workerId}` : "main";
|
|
4295
|
+
}
|
|
3944
4296
|
async function handleListTargets(opts) {
|
|
3945
4297
|
const target = await resolveTargetWithCurrentCfTarget(opts);
|
|
3946
4298
|
const tunnel = await openTarget(target);
|
|
@@ -3968,7 +4320,7 @@ async function buildListedTargets(targets) {
|
|
|
3968
4320
|
return buildListedTarget(target, index, workerResult.supported, workerResult.workers);
|
|
3969
4321
|
} catch (error) {
|
|
3970
4322
|
const message = error instanceof Error ? error.message : String(error);
|
|
3971
|
-
|
|
4323
|
+
process9.stderr.write(
|
|
3972
4324
|
`[cf-inspector] warning: worker discovery failed for raw target ${index.toString()}: ${message}
|
|
3973
4325
|
`
|
|
3974
4326
|
);
|
|
@@ -3995,7 +4347,7 @@ function looksLikeWorkerTarget(target) {
|
|
|
3995
4347
|
return `${target.type} ${target.title} ${target.url}`.toLowerCase().includes("worker");
|
|
3996
4348
|
}
|
|
3997
4349
|
function writeTargetCountSummary(targetCount, workerCount) {
|
|
3998
|
-
|
|
4350
|
+
process9.stderr.write(
|
|
3999
4351
|
`[cf-inspector] ${targetCount.toString()} raw inspector ${targetCount === 1 ? "target" : "targets"}; ${workerCount.toString()} ${workerCount === 1 ? "worker" : "workers"}.
|
|
4000
4352
|
`
|
|
4001
4353
|
);
|
|
@@ -4006,7 +4358,7 @@ function warnOnMissingWorkers(targetCount, workerCount, targets) {
|
|
|
4006
4358
|
}
|
|
4007
4359
|
const supported = targets[0]?.workerDiscoverySupported === true;
|
|
4008
4360
|
const supportHint = supported ? "NodeWorker discovery is available, but no live worker attached." : "This runtime did not expose NodeWorker discovery.";
|
|
4009
|
-
|
|
4361
|
+
process9.stderr.write(
|
|
4010
4362
|
`[cf-inspector] warning: only the main inspector target is reachable. ${supportHint} If worker code is expected, ensure the worker is alive and rerun list-targets. A worker on a separate inspector port is not carried by a single Cloud Foundry tunnel.
|
|
4011
4363
|
`
|
|
4012
4364
|
);
|
|
@@ -4014,12 +4366,12 @@ function warnOnMissingWorkers(targetCount, workerCount, targets) {
|
|
|
4014
4366
|
function writeHumanTargets(targets) {
|
|
4015
4367
|
for (const target of targets) {
|
|
4016
4368
|
const workerLabel = target.likelyWorker ? " likely-worker" : "";
|
|
4017
|
-
|
|
4369
|
+
process9.stdout.write(
|
|
4018
4370
|
`${target.index.toString()} target ${target.type} ${target.title} ${target.url}${workerLabel}
|
|
4019
4371
|
`
|
|
4020
4372
|
);
|
|
4021
4373
|
for (const worker of target.workers) {
|
|
4022
|
-
|
|
4374
|
+
process9.stdout.write(
|
|
4023
4375
|
` ${worker.index.toString()} worker ${worker.type} ${worker.title} ${worker.url}
|
|
4024
4376
|
`
|
|
4025
4377
|
);
|
|
@@ -4096,7 +4448,7 @@ function matchesFilterTokens(value, tokens) {
|
|
|
4096
4448
|
}
|
|
4097
4449
|
|
|
4098
4450
|
// src/cli/commands/log.ts
|
|
4099
|
-
import
|
|
4451
|
+
import process10 from "process";
|
|
4100
4452
|
|
|
4101
4453
|
// src/logpoint/stream.ts
|
|
4102
4454
|
init_types();
|
|
@@ -4273,6 +4625,9 @@ async function streamLogpoint(session, options) {
|
|
|
4273
4625
|
if (event === void 0) {
|
|
4274
4626
|
return;
|
|
4275
4627
|
}
|
|
4628
|
+
if (options.eventGate?.() === false) {
|
|
4629
|
+
return;
|
|
4630
|
+
}
|
|
4276
4631
|
emitted += 1;
|
|
4277
4632
|
try {
|
|
4278
4633
|
options.onEvent(event);
|
|
@@ -4391,6 +4746,7 @@ async function handleLog(opts) {
|
|
|
4391
4746
|
...condition === void 0 ? {} : { condition },
|
|
4392
4747
|
maxValueLength,
|
|
4393
4748
|
json: opts.json,
|
|
4749
|
+
emitReadyEvent: opts.readyEvent === true,
|
|
4394
4750
|
signal
|
|
4395
4751
|
});
|
|
4396
4752
|
writeLogSummary(result.stoppedReason, result.emitted, opts.json);
|
|
@@ -4402,9 +4758,13 @@ async function runLogGroup(group, options) {
|
|
|
4402
4758
|
const tasks = /* @__PURE__ */ new Set();
|
|
4403
4759
|
const removedSessions = /* @__PURE__ */ new Set();
|
|
4404
4760
|
const results = [];
|
|
4761
|
+
const pendingArming = /* @__PURE__ */ new Set();
|
|
4762
|
+
const resolvedLocations = /* @__PURE__ */ new Map();
|
|
4405
4763
|
let fatalError;
|
|
4406
4764
|
let emitted = 0;
|
|
4407
4765
|
let reason = "signal";
|
|
4766
|
+
let sessionRegistrationComplete = false;
|
|
4767
|
+
let readyEventEmitted = !options.emitReadyEvent;
|
|
4408
4768
|
let resolveStop;
|
|
4409
4769
|
const stopped = new Promise((resolve) => {
|
|
4410
4770
|
resolveStop = resolve;
|
|
@@ -4427,10 +4787,35 @@ async function runLogGroup(group, options) {
|
|
|
4427
4787
|
const timer = options.durationMs === void 0 ? void 0 : setTimeout(() => {
|
|
4428
4788
|
finish("duration");
|
|
4429
4789
|
}, options.durationMs);
|
|
4790
|
+
const detachError = options.emitReadyEvent ? group.onError((error) => {
|
|
4791
|
+
if (controller.signal.aborted) {
|
|
4792
|
+
return;
|
|
4793
|
+
}
|
|
4794
|
+
fatalError = error;
|
|
4795
|
+
finish("transport-closed");
|
|
4796
|
+
}) : () => void 0;
|
|
4797
|
+
const emitReadyEventIfArmed = () => {
|
|
4798
|
+
if (readyEventEmitted || !sessionRegistrationComplete || pendingArming.size > 0 || resolvedLocations.size === 0 || controller.signal.aborted) {
|
|
4799
|
+
return;
|
|
4800
|
+
}
|
|
4801
|
+
writeArmedEvent({
|
|
4802
|
+
command: "log",
|
|
4803
|
+
sessions: resolvedLocations.size,
|
|
4804
|
+
resolvedLocations: [...resolvedLocations.values()].reduce(
|
|
4805
|
+
(total, count) => total + count,
|
|
4806
|
+
0
|
|
4807
|
+
),
|
|
4808
|
+
timeoutMs: null
|
|
4809
|
+
});
|
|
4810
|
+
readyEventEmitted = true;
|
|
4811
|
+
};
|
|
4430
4812
|
const startSession = (session) => {
|
|
4431
4813
|
if (controller.signal.aborted) {
|
|
4432
4814
|
return;
|
|
4433
4815
|
}
|
|
4816
|
+
if (!readyEventEmitted) {
|
|
4817
|
+
pendingArming.add(session);
|
|
4818
|
+
}
|
|
4434
4819
|
const task = (async () => {
|
|
4435
4820
|
await validateExpression(session, options.expression);
|
|
4436
4821
|
if (options.condition !== void 0) {
|
|
@@ -4444,6 +4829,7 @@ async function runLogGroup(group, options) {
|
|
|
4444
4829
|
...options.condition === void 0 ? {} : { condition: options.condition },
|
|
4445
4830
|
maxValueLength: options.maxValueLength,
|
|
4446
4831
|
signal: controller.signal,
|
|
4832
|
+
...options.emitReadyEvent ? { eventGate: () => readyEventEmitted } : {},
|
|
4447
4833
|
onEvent: (event) => {
|
|
4448
4834
|
if (controller.signal.aborted) {
|
|
4449
4835
|
return;
|
|
@@ -4456,6 +4842,11 @@ async function runLogGroup(group, options) {
|
|
|
4456
4842
|
},
|
|
4457
4843
|
onBreakpointSet: (handle) => {
|
|
4458
4844
|
warnOnUnboundBreakpoints([handle]);
|
|
4845
|
+
if (!readyEventEmitted) {
|
|
4846
|
+
resolvedLocations.set(session, handle.resolvedLocations.length);
|
|
4847
|
+
pendingArming.delete(session);
|
|
4848
|
+
emitReadyEventIfArmed();
|
|
4849
|
+
}
|
|
4459
4850
|
}
|
|
4460
4851
|
});
|
|
4461
4852
|
})();
|
|
@@ -4468,6 +4859,9 @@ async function runLogGroup(group, options) {
|
|
|
4468
4859
|
}
|
|
4469
4860
|
},
|
|
4470
4861
|
(error) => {
|
|
4862
|
+
if (options.emitReadyEvent && (removedSessions.has(session) || fatalError !== void 0)) {
|
|
4863
|
+
return;
|
|
4864
|
+
}
|
|
4471
4865
|
fatalError = error;
|
|
4472
4866
|
finish("transport-closed");
|
|
4473
4867
|
}
|
|
@@ -4476,8 +4870,27 @@ async function runLogGroup(group, options) {
|
|
|
4476
4870
|
});
|
|
4477
4871
|
};
|
|
4478
4872
|
const detach = group.onSession(startSession);
|
|
4873
|
+
sessionRegistrationComplete = true;
|
|
4874
|
+
emitReadyEventIfArmed();
|
|
4479
4875
|
const detachRemoved = group.onSessionRemoved((session) => {
|
|
4480
4876
|
removedSessions.add(session);
|
|
4877
|
+
if (!readyEventEmitted) {
|
|
4878
|
+
if (controller.signal.aborted) {
|
|
4879
|
+
pendingArming.delete(session);
|
|
4880
|
+
resolvedLocations.delete(session);
|
|
4881
|
+
return;
|
|
4882
|
+
}
|
|
4883
|
+
if (pendingArming.has(session)) {
|
|
4884
|
+
fatalError = new CfInspectorError(
|
|
4885
|
+
"INSPECTOR_CONNECTION_FAILED",
|
|
4886
|
+
"A worker detached before logpoint arming completed; no readiness event was emitted."
|
|
4887
|
+
);
|
|
4888
|
+
finish("transport-closed");
|
|
4889
|
+
return;
|
|
4890
|
+
}
|
|
4891
|
+
resolvedLocations.delete(session);
|
|
4892
|
+
emitReadyEventIfArmed();
|
|
4893
|
+
}
|
|
4481
4894
|
});
|
|
4482
4895
|
try {
|
|
4483
4896
|
await stopped;
|
|
@@ -4485,6 +4898,7 @@ async function runLogGroup(group, options) {
|
|
|
4485
4898
|
} finally {
|
|
4486
4899
|
detach();
|
|
4487
4900
|
detachRemoved();
|
|
4901
|
+
detachError();
|
|
4488
4902
|
if (timer !== void 0) {
|
|
4489
4903
|
clearTimeout(timer);
|
|
4490
4904
|
}
|
|
@@ -4503,11 +4917,11 @@ function isZeroHitStop(reason) {
|
|
|
4503
4917
|
}
|
|
4504
4918
|
function writeLogSummary(stoppedReason, emitted, json) {
|
|
4505
4919
|
if (json) {
|
|
4506
|
-
|
|
4920
|
+
process10.stderr.write(`${JSON.stringify({ stopped: stoppedReason, emitted })}
|
|
4507
4921
|
`);
|
|
4508
4922
|
return;
|
|
4509
4923
|
}
|
|
4510
|
-
|
|
4924
|
+
process10.stderr.write(
|
|
4511
4925
|
`Stopped (${stoppedReason}); emitted ${emitted.toString()} log ${emitted === 1 ? "entry" : "entries"}.
|
|
4512
4926
|
`
|
|
4513
4927
|
);
|
|
@@ -4515,7 +4929,7 @@ function writeLogSummary(stoppedReason, emitted, json) {
|
|
|
4515
4929
|
|
|
4516
4930
|
// src/cli/commands/snapshot.ts
|
|
4517
4931
|
import { performance as performance6 } from "perf_hooks";
|
|
4518
|
-
import
|
|
4932
|
+
import process11 from "process";
|
|
4519
4933
|
init_types();
|
|
4520
4934
|
async function handleSnapshot(opts) {
|
|
4521
4935
|
const target = await resolveTargetWithCurrentCfTarget(opts, { useTimeoutForTunnel: false });
|
|
@@ -4591,18 +5005,38 @@ async function runSnapshotCommand(command, opts, reportProgress, signal) {
|
|
|
4591
5005
|
let winner;
|
|
4592
5006
|
let preserveWinner = false;
|
|
4593
5007
|
try {
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
|
|
5008
|
+
const reportArmedSetup = (outcomes) => {
|
|
5009
|
+
if (opts.readyEvent === true && signal?.aborted === true) {
|
|
5010
|
+
return;
|
|
5011
|
+
}
|
|
5012
|
+
if (command.setupEvals.length > 0) {
|
|
5013
|
+
reportProgress?.("Setup evaluation complete.");
|
|
5014
|
+
}
|
|
5015
|
+
if (command.condition !== void 0) {
|
|
5016
|
+
reportProgress?.("Breakpoint condition is valid.");
|
|
5017
|
+
}
|
|
5018
|
+
const setup = reportBreakpointOutcomes(outcomes, reportProgress);
|
|
5019
|
+
reportProgress?.(
|
|
5020
|
+
`Waiting up to ${(command.timeoutMs / 1e3).toString()}s for a breakpoint hit...`
|
|
5021
|
+
);
|
|
5022
|
+
if (opts.readyEvent === true && signal?.aborted !== true) {
|
|
5023
|
+
writeArmedEvent({
|
|
5024
|
+
command: "snapshot",
|
|
5025
|
+
sessions: setup.sessions,
|
|
5026
|
+
resolvedLocations: setup.resolvedLocations,
|
|
5027
|
+
timeoutMs: command.timeoutMs
|
|
5028
|
+
});
|
|
5029
|
+
}
|
|
5030
|
+
};
|
|
5031
|
+
if (opts.readyEvent === true) {
|
|
5032
|
+
await fanout.ready({
|
|
5033
|
+
includeNewSessions: true,
|
|
5034
|
+
onReady: reportArmedSetup
|
|
5035
|
+
});
|
|
5036
|
+
} else {
|
|
5037
|
+
await fanout.ready();
|
|
5038
|
+
reportArmedSetup(fanout.availableOutcomes());
|
|
4600
5039
|
}
|
|
4601
|
-
const outcomes = fanout.availableOutcomes();
|
|
4602
|
-
reportBreakpointOutcomes(outcomes, reportProgress);
|
|
4603
|
-
reportProgress?.(
|
|
4604
|
-
`Waiting up to ${(command.timeoutMs / 1e3).toString()}s for a breakpoint hit...`
|
|
4605
|
-
);
|
|
4606
5040
|
const hit = await fanout.waitForFirst(command.timeoutMs, {
|
|
4607
5041
|
unmatchedPausePolicy: opts.failOnUnmatchedPause === true ? "fail" : "wait-for-resume",
|
|
4608
5042
|
...opts.failOnUnmatchedPause === true ? {} : { onUnmatchedPause: warnOnUnmatchedPause }
|
|
@@ -4650,11 +5084,12 @@ function reportBreakpointOutcomes(outcomes, reportProgress) {
|
|
|
4650
5084
|
reportProgress?.(
|
|
4651
5085
|
`Breakpoint setup complete: ${locations.toString()} resolved ${locations === 1 ? "location" : "locations"}.`
|
|
4652
5086
|
);
|
|
4653
|
-
return;
|
|
5087
|
+
return { sessions: outcomes.length, resolvedLocations: locations };
|
|
4654
5088
|
}
|
|
4655
5089
|
reportProgress?.(
|
|
4656
5090
|
`Breakpoint setup complete: sessions=${outcomes.length.toString()} boundSessions=${boundSessions.toString()} resolvedLocations=${locations.toString()}.`
|
|
4657
5091
|
);
|
|
5092
|
+
return { sessions: outcomes.length, resolvedLocations: locations };
|
|
4658
5093
|
}
|
|
4659
5094
|
async function captureSnapshotResult(session, pause, command, opts, reportProgress) {
|
|
4660
5095
|
const pausedStartedAt = pause.receivedAtMs ?? performance6.now();
|
|
@@ -4694,7 +5129,7 @@ async function resumeAfterSnapshot(session, snapshot, pausedStartedAt, reportPro
|
|
|
4694
5129
|
reportProgress?.("Target resumed.");
|
|
4695
5130
|
return withPausedDuration(snapshot, roundDurationMs(performance6.now() - pausedStartedAt));
|
|
4696
5131
|
} catch {
|
|
4697
|
-
|
|
5132
|
+
process11.stderr.write(
|
|
4698
5133
|
"[cf-inspector] warning: Debugger.resume failed after snapshot; pausedDurationMs is unknown.\n"
|
|
4699
5134
|
);
|
|
4700
5135
|
return withPausedDuration(snapshot, null);
|
|
@@ -4707,7 +5142,7 @@ function parseSetupEvals(raw) {
|
|
|
4707
5142
|
|
|
4708
5143
|
// src/cli/commands/watch.ts
|
|
4709
5144
|
import { performance as performance7 } from "perf_hooks";
|
|
4710
|
-
import
|
|
5145
|
+
import process12 from "process";
|
|
4711
5146
|
init_types();
|
|
4712
5147
|
async function handleWatch(opts) {
|
|
4713
5148
|
const target = await resolveTargetWithCurrentCfTarget(opts, { useTimeoutForTunnel: false });
|
|
@@ -4775,7 +5210,26 @@ async function runWatchGroup(group, command, opts, signal) {
|
|
|
4775
5210
|
let stoppedReason = "signal";
|
|
4776
5211
|
const deadline = computeDeadline(command.durationMs);
|
|
4777
5212
|
try {
|
|
4778
|
-
await fanout.ready(
|
|
5213
|
+
await fanout.ready(opts.readyEvent === true ? {
|
|
5214
|
+
includeNewSessions: true,
|
|
5215
|
+
onReady: (outcomes) => {
|
|
5216
|
+
if (signal.aborted || remainingForLoop(deadline, command.perHitTimeoutMs) <= 0) {
|
|
5217
|
+
return;
|
|
5218
|
+
}
|
|
5219
|
+
writeArmedEvent({
|
|
5220
|
+
command: "watch",
|
|
5221
|
+
sessions: outcomes.length,
|
|
5222
|
+
resolvedLocations: outcomes.reduce(
|
|
5223
|
+
(total, outcome) => total + outcome.setup.handles.reduce(
|
|
5224
|
+
(sessionTotal, handle) => sessionTotal + handle.resolvedLocations.length,
|
|
5225
|
+
0
|
|
5226
|
+
),
|
|
5227
|
+
0
|
|
5228
|
+
),
|
|
5229
|
+
timeoutMs: command.perHitTimeoutMs
|
|
5230
|
+
});
|
|
5231
|
+
}
|
|
5232
|
+
} : {});
|
|
4779
5233
|
while (!signal.aborted) {
|
|
4780
5234
|
const remainingMs = remainingForLoop(deadline, command.perHitTimeoutMs);
|
|
4781
5235
|
if (remainingMs <= 0) {
|
|
@@ -4806,7 +5260,7 @@ async function runWatchGroup(group, command, opts, signal) {
|
|
|
4806
5260
|
await resume(hit.session);
|
|
4807
5261
|
hit.session.debuggerState.paused = false;
|
|
4808
5262
|
} catch {
|
|
4809
|
-
|
|
5263
|
+
process12.stderr.write("[cf-inspector] warning: Debugger.resume failed during watch.\n");
|
|
4810
5264
|
stoppedReason = "transport-closed";
|
|
4811
5265
|
break;
|
|
4812
5266
|
}
|
|
@@ -4820,7 +5274,7 @@ async function runWatchGroup(group, command, opts, signal) {
|
|
|
4820
5274
|
}
|
|
4821
5275
|
} finally {
|
|
4822
5276
|
const cleanup = await fanout.cleanup();
|
|
4823
|
-
|
|
5277
|
+
process12.stderr.write(
|
|
4824
5278
|
`[cf-inspector] breakpoint cleanup: cleared ${cleanup.cleared.toString()} of ${cleanup.attempted.toString()}; resumed ${cleanup.resumed.toString()} paused isolates.
|
|
4825
5279
|
`
|
|
4826
5280
|
);
|
|
@@ -4918,11 +5372,11 @@ function formatLocation(command, topFrame) {
|
|
|
4918
5372
|
}
|
|
4919
5373
|
function writeWatchSummary(reason, emitted, json) {
|
|
4920
5374
|
if (json) {
|
|
4921
|
-
|
|
5375
|
+
process12.stderr.write(`${JSON.stringify({ stopped: reason, emitted })}
|
|
4922
5376
|
`);
|
|
4923
5377
|
return;
|
|
4924
5378
|
}
|
|
4925
|
-
|
|
5379
|
+
process12.stderr.write(
|
|
4926
5380
|
`Stopped (${reason}); emitted ${emitted.toString()} watch ${emitted === 1 ? "event" : "events"}.
|
|
4927
5381
|
`
|
|
4928
5382
|
);
|
|
@@ -4949,10 +5403,11 @@ var collectStrings = (value, prev = []) => [
|
|
|
4949
5403
|
...prev,
|
|
4950
5404
|
value
|
|
4951
5405
|
];
|
|
5406
|
+
var READY_EVENT_DESCRIPTION = "Emit a versioned breakpoint-armed JSON event on stderr after every current isolate is armed";
|
|
4952
5407
|
function readPackageVersion() {
|
|
4953
5408
|
let current = dirname(fileURLToPath(import.meta.url));
|
|
4954
5409
|
for (let depth = 0; depth < 4; depth += 1) {
|
|
4955
|
-
const candidate =
|
|
5410
|
+
const candidate = join2(current, "package.json");
|
|
4956
5411
|
try {
|
|
4957
5412
|
const parsed = JSON.parse(readFileSync(candidate, "utf8"));
|
|
4958
5413
|
if (typeof parsed === "object" && parsed !== null) {
|
|
@@ -4994,14 +5449,14 @@ function registerSnapshot(program) {
|
|
|
4994
5449
|
applyTargetOptions(
|
|
4995
5450
|
program.command("snapshot").description("Set a breakpoint, wait for it to hit, capture expressions, and resume"),
|
|
4996
5451
|
{ includeTimeout: false }
|
|
4997
|
-
).option("--bp <file:line>", "Breakpoint location (repeatable; first hit wins), e.g. src/handler.ts:42", collectStrings, []).option("--capture <expr,\u2026>", "Top-level comma-separated expressions to evaluate in the paused frame").option("--setup-eval <expr>", "Evaluate a global setup expression before breakpoint setup (repeatable)", collectStrings, []).option("--timeout <seconds>", "How long to wait for the breakpoint to hit (default: 30)").option("--max-value-length <chars>", "Maximum characters per captured value before truncation (default: 131072)").option("--remote-root <value>", "Path-mapping anchor: literal path or regex:<pattern> / /pattern/flags").option("--condition <expr>", "Only pause when this JS expression evaluates truthy in the paused frame").option("--hit-count <n>", "Only pause after the breakpoint has been hit N or more times").option("--stack-depth <n>", "Walk this many call frames when capturing (default: 1, only top frame)").option("--stack-captures <expr,\u2026>", "Expressions to evaluate on each call frame in the stack").option("--allow-mutation", "Allow mutation-capable captures and native breakpoint conditions to run").option("--include-scopes", "Include expanded paused-frame scopes in the snapshot").option("--no-json", "Print a human-readable summary instead of JSON").option("--quiet", "Suppress progress messages on stderr").option("--keep-paused", "Skip Debugger.resume after capture; Node may resume when this CLI disconnects").option("--fail-on-unmatched-pause", "Fail immediately if the target pauses somewhere else").action(async (opts) => {
|
|
5452
|
+
).option("--bp <file:line>", "Breakpoint location (repeatable; first hit wins), e.g. src/handler.ts:42", collectStrings, []).option("--capture <expr,\u2026>", "Top-level comma-separated expressions to evaluate in the paused frame").option("--setup-eval <expr>", "Evaluate a global setup expression before breakpoint setup (repeatable)", collectStrings, []).option("--timeout <seconds>", "How long to wait for the breakpoint to hit (default: 30)").option("--max-value-length <chars>", "Maximum characters per captured value before truncation (default: 131072)").option("--remote-root <value>", "Path-mapping anchor: literal path or regex:<pattern> / /pattern/flags").option("--condition <expr>", "Only pause when this JS expression evaluates truthy in the paused frame").option("--hit-count <n>", "Only pause after the breakpoint has been hit N or more times").option("--stack-depth <n>", "Walk this many call frames when capturing (default: 1, only top frame)").option("--stack-captures <expr,\u2026>", "Expressions to evaluate on each call frame in the stack").option("--allow-mutation", "Allow mutation-capable captures and native breakpoint conditions to run").option("--include-scopes", "Include expanded paused-frame scopes in the snapshot").option("--no-json", "Print a human-readable summary instead of JSON").option("--quiet", "Suppress progress messages on stderr").option("--ready-event", READY_EVENT_DESCRIPTION).option("--keep-paused", "Skip Debugger.resume after capture; Node may resume when this CLI disconnects").option("--fail-on-unmatched-pause", "Fail immediately if the target pauses somewhere else").action(async (opts) => {
|
|
4998
5453
|
await handleSnapshot(opts);
|
|
4999
5454
|
});
|
|
5000
5455
|
}
|
|
5001
5456
|
function registerLog(program) {
|
|
5002
5457
|
applyTargetOptions(
|
|
5003
5458
|
program.command("log").description("Stream a non-pausing logpoint: log an expression each time a line executes")
|
|
5004
|
-
).requiredOption("--at <file:line>", "Logpoint location, e.g. src/handler.ts:42").requiredOption("--expr <expression>", "JavaScript expression to log on each hit").option("--remote-root <value>", "Path-mapping anchor: literal path or regex:<pattern> / /pattern/flags").option("--duration <seconds>", "Stop streaming after N seconds (default: run until SIGINT)").option("--max-events <n>", "Stop streaming after emitting N log events").option("--hit-count <n>", "Start logging once the line has been hit N or more times").option("--condition <expr>", "Only log when this JS expression evaluates truthy on the inspectee").option("--max-value-length <chars>", "Maximum characters per log value before truncation (default: 4096)").option("--no-json", "Print human-readable lines instead of JSON Lines").action(async (opts) => {
|
|
5459
|
+
).requiredOption("--at <file:line>", "Logpoint location, e.g. src/handler.ts:42").requiredOption("--expr <expression>", "JavaScript expression to log on each hit").option("--remote-root <value>", "Path-mapping anchor: literal path or regex:<pattern> / /pattern/flags").option("--duration <seconds>", "Stop streaming after N seconds (default: run until SIGINT)").option("--max-events <n>", "Stop streaming after emitting N log events").option("--hit-count <n>", "Start logging once the line has been hit N or more times").option("--condition <expr>", "Only log when this JS expression evaluates truthy on the inspectee").option("--max-value-length <chars>", "Maximum characters per log value before truncation (default: 4096)").option("--no-json", "Print human-readable lines instead of JSON Lines").option("--ready-event", READY_EVENT_DESCRIPTION).action(async (opts) => {
|
|
5005
5460
|
await handleLog(opts);
|
|
5006
5461
|
});
|
|
5007
5462
|
}
|
|
@@ -5009,7 +5464,7 @@ function registerWatch(program) {
|
|
|
5009
5464
|
applyTargetOptions(
|
|
5010
5465
|
program.command("watch").description("Stream a snapshot per breakpoint hit (multi-shot watch); resume between hits"),
|
|
5011
5466
|
{ includeTimeout: false }
|
|
5012
|
-
).option("--bp <file:line>", "Breakpoint location (repeatable), e.g. src/handler.ts:42", collectStrings, []).option("--capture <expr,\u2026>", "Top-level comma-separated expressions to evaluate per hit").option("--setup-eval <expr>", "Evaluate a global setup expression before breakpoint setup (repeatable)", collectStrings, []).option("--condition <expr>", "Only emit hits where this JS expression evaluates truthy").option("--hit-count <n>", "Start emitting after the line has been hit N or more times").option("--remote-root <value>", "Path-mapping anchor: literal path or regex:<pattern> / /pattern/flags").option("--duration <seconds>", "Stop streaming after N seconds (default: run until SIGINT)").option("--max-events <n>", "Stop streaming after emitting N watch events").option("--timeout <seconds>", "How long to wait for the next hit before giving up (default: 30)").option("--max-value-length <chars>", "Maximum characters per captured value before truncation (default: 4096)").option("--stack-depth <n>", "Walk this many call frames per hit (default: 1)").option("--stack-captures <expr,\u2026>", "Expressions to evaluate on each call frame").option("--allow-mutation", "Allow mutation-capable captures and native breakpoint conditions to run").option("--include-scopes", "Include expanded paused-frame scopes per hit").option("--no-json", "Print human-readable lines instead of JSON Lines").action(async (opts) => {
|
|
5467
|
+
).option("--bp <file:line>", "Breakpoint location (repeatable), e.g. src/handler.ts:42", collectStrings, []).option("--capture <expr,\u2026>", "Top-level comma-separated expressions to evaluate per hit").option("--setup-eval <expr>", "Evaluate a global setup expression before breakpoint setup (repeatable)", collectStrings, []).option("--condition <expr>", "Only emit hits where this JS expression evaluates truthy").option("--hit-count <n>", "Start emitting after the line has been hit N or more times").option("--remote-root <value>", "Path-mapping anchor: literal path or regex:<pattern> / /pattern/flags").option("--duration <seconds>", "Stop streaming after N seconds (default: run until SIGINT)").option("--max-events <n>", "Stop streaming after emitting N watch events").option("--timeout <seconds>", "How long to wait for the next hit before giving up (default: 30)").option("--max-value-length <chars>", "Maximum characters per captured value before truncation (default: 4096)").option("--stack-depth <n>", "Walk this many call frames per hit (default: 1)").option("--stack-captures <expr,\u2026>", "Expressions to evaluate on each call frame").option("--allow-mutation", "Allow mutation-capable captures and native breakpoint conditions to run").option("--include-scopes", "Include expanded paused-frame scopes per hit").option("--no-json", "Print human-readable lines instead of JSON Lines").option("--ready-event", READY_EVENT_DESCRIPTION).action(async (opts) => {
|
|
5013
5468
|
await handleWatch(opts);
|
|
5014
5469
|
});
|
|
5015
5470
|
}
|
|
@@ -5017,7 +5472,7 @@ function registerException(program) {
|
|
|
5017
5472
|
applyTargetOptions(
|
|
5018
5473
|
program.command("exception").description("Pause on a thrown exception, capture the value and frame, then resume"),
|
|
5019
5474
|
{ includeTimeout: false }
|
|
5020
|
-
).option("--type <state>", "Pause type: uncaught (default), caught, or all").option("--capture <expr,\u2026>", "Top-level comma-separated expressions to evaluate in the paused frame").option("--remote-root <value>", "Path-mapping anchor: literal path or regex:<pattern> / /pattern/flags").option("--timeout <seconds>", "How long to wait for an exception (default: 30)").option("--max-value-length <chars>", "Maximum characters per captured value before truncation (default: 131072)").option("--stack-depth <n>", "Walk this many call frames when capturing (default: 1)").option("--stack-captures <expr,\u2026>", "Expressions to evaluate on each call frame in the stack").option("--allow-mutation", "Allow mutation-capable capture expressions to run").option("--include-scopes", "Include expanded paused-frame scopes in the snapshot").option("--keep-paused", "Skip Debugger.resume after capture; Node may resume when this CLI disconnects").option("--no-json", "Print a human-readable summary instead of JSON").action(async (opts) => {
|
|
5475
|
+
).option("--type <state>", "Pause type: uncaught (default), caught, or all").option("--capture <expr,\u2026>", "Top-level comma-separated expressions to evaluate in the paused frame").option("--remote-root <value>", "Path-mapping anchor: literal path or regex:<pattern> / /pattern/flags").option("--timeout <seconds>", "How long to wait for an exception (default: 30)").option("--max-value-length <chars>", "Maximum characters per captured value before truncation (default: 131072)").option("--stack-depth <n>", "Walk this many call frames when capturing (default: 1)").option("--stack-captures <expr,\u2026>", "Expressions to evaluate on each call frame in the stack").option("--allow-mutation", "Allow mutation-capable capture expressions to run").option("--include-scopes", "Include expanded paused-frame scopes in the snapshot").option("--keep-paused", "Skip Debugger.resume after capture; Node may resume when this CLI disconnects").option("--no-json", "Print a human-readable summary instead of JSON").option("--ready-event", READY_EVENT_DESCRIPTION).action(async (opts) => {
|
|
5021
5476
|
await handleException(opts);
|
|
5022
5477
|
});
|
|
5023
5478
|
}
|
|
@@ -5030,8 +5485,10 @@ function registerEval(program) {
|
|
|
5030
5485
|
}
|
|
5031
5486
|
function registerListScripts(program) {
|
|
5032
5487
|
applyTargetOptions(
|
|
5033
|
-
program.command("list-scripts").description(
|
|
5034
|
-
|
|
5488
|
+
program.command("list-scripts").description(
|
|
5489
|
+
"Print scripts from the main isolate and every worker, tagged by isolate"
|
|
5490
|
+
)
|
|
5491
|
+
).option("--filter <pattern>", "Only include script URLs matching this pattern").option("--no-json", "Print scriptId<TAB>url<TAB>isolate instead of JSON").action(async (opts) => {
|
|
5035
5492
|
await handleListScripts(opts);
|
|
5036
5493
|
});
|
|
5037
5494
|
}
|
|
@@ -5060,20 +5517,20 @@ function registerAttach(program) {
|
|
|
5060
5517
|
// src/cli.ts
|
|
5061
5518
|
init_types();
|
|
5062
5519
|
try {
|
|
5063
|
-
await main(
|
|
5520
|
+
await main(process13.argv);
|
|
5064
5521
|
} catch (err) {
|
|
5065
5522
|
if (err instanceof CfInspectorError) {
|
|
5066
|
-
|
|
5523
|
+
process13.stderr.write(`Error [${err.code}]: ${err.message}
|
|
5067
5524
|
`);
|
|
5068
5525
|
if (err.detail !== void 0) {
|
|
5069
|
-
|
|
5526
|
+
process13.stderr.write(` detail: ${err.detail}
|
|
5070
5527
|
`);
|
|
5071
5528
|
}
|
|
5072
|
-
|
|
5529
|
+
process13.exit(1);
|
|
5073
5530
|
}
|
|
5074
5531
|
const message = err instanceof Error ? err.message : String(err);
|
|
5075
|
-
|
|
5532
|
+
process13.stderr.write(`Error: ${message}
|
|
5076
5533
|
`);
|
|
5077
|
-
|
|
5534
|
+
process13.exit(1);
|
|
5078
5535
|
}
|
|
5079
5536
|
//# sourceMappingURL=cli.js.map
|