@saptools/cf-inspector 0.4.12 โ 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +217 -32
- package/dist/cli.js +1509 -538
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +145 -9
- package/dist/index.js +1130 -250
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -25,11 +25,13 @@ Built so an AI agent (or a CI job) can drive a debugger from a single shell comm
|
|
|
25
25
|
- ๐ช **Stack capture** โ `--stack-depth N --stack-captures 'this, args'` walks call frames and evaluates expressions per frame
|
|
26
26
|
- ๐ **Watch streaming** โ `cf-inspector watch --bp file:line --capture user.id --duration 30` re-captures on every hit and emits JSON Lines (the streaming counterpart of `snapshot`)
|
|
27
27
|
- ๐ฅ **Exception breakpoints** โ `cf-inspector exception --type uncaught --capture err.message` pauses on the next thrown error and materializes the exception value
|
|
28
|
-
- ๐ก **Non-pausing logpoints** โ `cf-inspector log --at file:line --expr 'JSON.stringify({โฆ})'` streams JSON Lines as the line executes
|
|
29
|
-
-
|
|
28
|
+
- ๐ก **Non-pausing logpoints** โ `cf-inspector log --at file:line --expr 'JSON.stringify({โฆ})'` streams JSON Lines as the line executes without pausing the inspectee, with optional `--condition`, `--hit-count`, and `--max-events`
|
|
29
|
+
- ๐ก๏ธ **Read-only capture guard** โ snapshot, watch, and exception captures use V8's side-effect analysis by default; `--allow-mutation` is an explicit escape hatch
|
|
30
|
+
- ๐งต **Worker-aware sessions** โ `list-targets` discovers raw inspector targets and nested NodeWorker sessions; use `--target` or `--worker` to select an isolate
|
|
31
|
+
- ๐ง **Agent-friendly** โ JSON-by-default I/O, deterministic shapes, and explicit `truncated`/`originalLength`/`omittedCount` metadata for bounded values
|
|
30
32
|
- ๐งญ **Path mapping** โ local `src/handler.ts:42` is matched against the remote URL via a `urlRegex`, with optional `--remote-root` literal or regex (same DSL as `cds-debug`)
|
|
31
33
|
- ๐ **Composes with `cf-debugger`** โ pass `--app/--region/--org/--space` and the tunnel is opened automatically; pass `--port` to attach to anything CDP-speaking
|
|
32
|
-
- ๐ชถ **Tiny dependency footprint** โ `commander` + `ws
|
|
34
|
+
- ๐ชถ **Tiny dependency footprint** โ `@saptools/cf-debugger` + `commander` + `ws`, with no heavy CDP framework
|
|
33
35
|
- ๐งฉ **Typed API** โ every CLI command has a programmatic equivalent with full TypeScript definitions
|
|
34
36
|
|
|
35
37
|
---
|
|
@@ -46,7 +48,7 @@ cf-inspector --version
|
|
|
46
48
|
|
|
47
49
|
> [!NOTE]
|
|
48
50
|
> Requires **Node.js โฅ 20**.
|
|
49
|
-
>
|
|
51
|
+
> Cloud Foundry support uses [`@saptools/cf-debugger`](https://www.npmjs.com/package/@saptools/cf-debugger), which is installed automatically as a normal runtime dependency.
|
|
50
52
|
|
|
51
53
|
---
|
|
52
54
|
|
|
@@ -66,6 +68,11 @@ cf-inspector snapshot \
|
|
|
66
68
|
|
|
67
69
|
This command internally calls `@saptools/cf-debugger` to open the SSH tunnel, runs the snapshot through it, and tears the tunnel down on exit.
|
|
68
70
|
|
|
71
|
+
Cloud Foundry targeting is deliberately deterministic: `--app` requires
|
|
72
|
+
`--region`, `--org`, and `--space`. The CLI never inherits missing selectors
|
|
73
|
+
from ambient `cf target` state. Use `--api-endpoint` only when the selected
|
|
74
|
+
region needs an explicit endpoint override.
|
|
75
|
+
|
|
69
76
|
---
|
|
70
77
|
|
|
71
78
|
## ๐งฐ CLI
|
|
@@ -92,15 +99,20 @@ cf-inspector snapshot --port 9229 \
|
|
|
92
99
|
| Flag | Description |
|
|
93
100
|
| --- | --- |
|
|
94
101
|
| `--port <number>` | Local port the inspector or tunnel listens on. **Required** unless `--app/--region/--org/--space` are all set |
|
|
102
|
+
| `--region/--org/--space/--app` | Explicit Cloud Foundry target. All four are required when `--port` is omitted; ambient `cf target` is never consulted |
|
|
103
|
+
| `--api-endpoint <url>` | Override the API endpoint resolved from `--region` |
|
|
104
|
+
| `--target <index>` | Raw `/json/list` target index (default: `0`) |
|
|
105
|
+
| `--worker <index>` | Nested NodeWorker index reported under the selected raw target by `list-targets` |
|
|
95
106
|
| `--bp <file:line>` | **Required.** Source location to break at. Pass multiple times to race several locations โ the first one to hit wins |
|
|
96
|
-
| `--condition <expr>` |
|
|
107
|
+
| `--condition <expr>` | Native breakpoint condition. It is compile-checked before arming; mutation-shaped conditions require `--allow-mutation` because CDP provides no side-effect guard for native conditions |
|
|
97
108
|
| `--hit-count <n>` | Skip the first N โ 1 hits and only pause on the Nth (combines with `--condition` via logical AND) |
|
|
98
|
-
| `--capture <expr,โฆ>` | Top-level comma-separated expressions
|
|
99
|
-
| `--setup-eval <expr>` | Repeatable, order-preserving global expression evaluated
|
|
109
|
+
| `--capture <expr,โฆ>` | Top-level comma-separated expressions evaluated in the paused frame under V8's side-effect guard. Nested commas inside objects, arrays, calls, or strings are preserved. Objects are materialized to JSON strings when serializable |
|
|
110
|
+
| `--setup-eval <expr>` | Repeatable, order-preserving global expression evaluated before breakpoint setup. It is mutation-capable and only receives an advisory warning |
|
|
100
111
|
| `--stack-depth <n>` | Walk this many call frames per hit (default: `1`, top frame only). When `> 1`, the result includes a `stack` array |
|
|
101
|
-
| `--stack-captures <expr,โฆ>` | Expressions
|
|
112
|
+
| `--stack-captures <expr,โฆ>` | Expressions evaluated on each captured call frame under the same side-effect guard as `--capture` |
|
|
113
|
+
| `--allow-mutation` | Disable V8's capture side-effect guard and explicitly allow mutation-shaped native conditions. Heuristic matches are annotated with `mutationRisk: true` |
|
|
102
114
|
| `--timeout <seconds>` | How long to wait for the breakpoint to hit (default: `30`) |
|
|
103
|
-
| `--max-value-length <chars>` | Maximum characters per captured value before truncation (default: `
|
|
115
|
+
| `--max-value-length <chars>` | Maximum characters per captured value before truncation (one-shot default: `131072`). Explicit values are honored exactly |
|
|
104
116
|
| `--remote-root <value>` | Optional path-mapping anchor: literal path or `regex:<pattern>` / `/pattern/flags` |
|
|
105
117
|
| `--include-scopes` | Include expanded paused-frame scopes under `topFrame.scopes`. Omitted by default to keep targeted captures concise |
|
|
106
118
|
| `--no-json` | Print a human-readable summary instead of JSON |
|
|
@@ -120,6 +132,56 @@ is only present with `--include-scopes` because scope objects can be large and
|
|
|
120
132
|
drown out targeted captures. Values are raw debugger values, so be careful when
|
|
121
133
|
sharing logs.
|
|
122
134
|
|
|
135
|
+
Capture expressions are read-only by default. `cf-inspector` sends
|
|
136
|
+
`throwOnSideEffect: true` to V8 for both `--capture` and `--stack-captures`.
|
|
137
|
+
Assignments, mutating methods such as `push`, and calls V8 cannot prove pure
|
|
138
|
+
are returned as a blocked capture with `blocked: true`, `mutationRisk: true`,
|
|
139
|
+
and a `MUTATION_NOT_ALLOWED` error. Pass `--allow-mutation` only when changing
|
|
140
|
+
the live inspectee is intentional. The opt-in disables the V8 guard and adds
|
|
141
|
+
`mutationRisk: true` when the advisory syntax scan recognizes a likely
|
|
142
|
+
mutation; arbitrary function calls can still mutate without being recognized.
|
|
143
|
+
|
|
144
|
+
`--condition` is different: V8 executes it internally as a native breakpoint
|
|
145
|
+
condition, where CDP has no `throwOnSideEffect` option. Mutation-shaped native
|
|
146
|
+
conditions are rejected unless `--allow-mutation` is present. `--setup-eval`
|
|
147
|
+
and the standalone `eval` command remain mutation-capable by design and emit
|
|
148
|
+
advisory warnings for recognizable mutation syntax.
|
|
149
|
+
|
|
150
|
+
A blocked capture remains a normal additive `CapturedExpression`, so one unsafe
|
|
151
|
+
expression does not corrupt the rest of the snapshot:
|
|
152
|
+
|
|
153
|
+
```json
|
|
154
|
+
{"expression":"items.push(1)","error":"MUTATION_NOT_ALLOWED: V8 blocked the capture expression ...","mutationRisk":true,"blocked":true}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
With `--allow-mutation`, recognized mutation syntax runs and the result carries
|
|
158
|
+
`"mutationRisk": true`; ordinary reads do not gain the field.
|
|
159
|
+
|
|
160
|
+
#### Truncation contract
|
|
161
|
+
|
|
162
|
+
JSON truncation is always out-of-band. A text value longer than the effective
|
|
163
|
+
limit is cut to exactly that many JavaScript characters and gains
|
|
164
|
+
`"truncated": true` plus its full `"originalLength"`; no ellipsis is appended
|
|
165
|
+
to the JSON value. These fields are absent when no cut occurs. Human output may
|
|
166
|
+
add a visual ellipsis.
|
|
167
|
+
|
|
168
|
+
Expanded objects and scopes also report bounded structural capture. The
|
|
169
|
+
`VariableSnapshot`, `ScopeSnapshot`, or `FrameSnapshot` whose properties,
|
|
170
|
+
variables, or scopes were cut gains `truncated: true` and the exact direct
|
|
171
|
+
`omittedCount`. A serialized object capture propagates the aggregate known
|
|
172
|
+
omission count to its `CapturedExpression`. `ExceptionSnapshot` additionally
|
|
173
|
+
uses `valueOriginalLength` and `descriptionOriginalLength` so consumers can
|
|
174
|
+
identify which field was cut; its compatibility `originalLength` is the larger
|
|
175
|
+
reported field length.
|
|
176
|
+
|
|
177
|
+
One-shot `snapshot` and `exception` commands default to `131072` characters.
|
|
178
|
+
Repeated `watch` and `log` events default to `4096`. All four accept
|
|
179
|
+
`--max-value-length`, and an explicit limit is applied exactly.
|
|
180
|
+
|
|
181
|
+
```json
|
|
182
|
+
{"expression":"largeText","value":"exactly-N-characters","type":"string","truncated":true,"originalLength":250000}
|
|
183
|
+
```
|
|
184
|
+
|
|
123
185
|
`pausedDurationMs` measures the client-observed time from receiving the matching
|
|
124
186
|
pause event until `Debugger.resume` completes. With `--keep-paused`, it is `null`
|
|
125
187
|
because resume is intentionally skipped.
|
|
@@ -139,7 +201,9 @@ readiness keeps the 180-second default.
|
|
|
139
201
|
|
|
140
202
|
### ๐ก `cf-inspector log`
|
|
141
203
|
|
|
142
|
-
Set a non-pausing logpoint and stream the evaluated expression each time the
|
|
204
|
+
Set a non-pausing logpoint and stream the evaluated expression each time the
|
|
205
|
+
line executes. The inspectee does not pause, but the expression and condition
|
|
206
|
+
still execute against live state and can mutate it.
|
|
143
207
|
|
|
144
208
|
```bash
|
|
145
209
|
# Stream user IDs hitting handler.ts:42 for 30 seconds
|
|
@@ -168,15 +232,22 @@ When the user expression throws, the event is emitted with `error` instead of `v
|
|
|
168
232
|
| Flag | Description |
|
|
169
233
|
| --- | --- |
|
|
170
234
|
| `--port <number>` | Local port the inspector or tunnel listens on. **Required** unless `--app/--region/--org/--space` are all set |
|
|
235
|
+
| `--target <index>` / `--worker <index>` | Select a raw inspector target or nested NodeWorker session from `list-targets` |
|
|
171
236
|
| `--at <file:line>` | **Required.** Source location to log at |
|
|
172
|
-
| `--expr <expression>` | **Required.**
|
|
237
|
+
| `--expr <expression>` | **Required.** JavaScript expression evaluated at each hit, wrapped in try/catch on the inspectee side. It is mutation-capable; recognizable risks produce a warning |
|
|
173
238
|
| `--duration <seconds>` | Stop streaming after N seconds (default: run until SIGINT) |
|
|
174
239
|
| `--max-events <n>` | Stop streaming after emitting N log events. The trailer reports `stopped: "max-events"` |
|
|
175
240
|
| `--hit-count <n>` | Start emitting once the line has been hit N or more times |
|
|
176
|
-
| `--condition <expr>` |
|
|
241
|
+
| `--condition <expr>` | Mutation-capable native condition evaluated on the inspectee. Recognizable risks produce a warning. Composes with `--hit-count` via logical AND |
|
|
242
|
+
| `--max-value-length <chars>` | Maximum characters per log value (streaming default: `4096`). Truncated events include `truncated` and `originalLength` |
|
|
177
243
|
| `--remote-root <value>` | Optional path-mapping anchor (same DSL as `snapshot`) |
|
|
178
244
|
| `--no-json` | Print human-readable lines instead of JSON Lines |
|
|
179
245
|
|
|
246
|
+
Native logpoint expressions and conditions have no V8 side-effect gate. The
|
|
247
|
+
CLI warns when its best-effort syntax scan recognizes assignments or common
|
|
248
|
+
mutating calls, but that scan cannot prove an arbitrary function is pure. Treat
|
|
249
|
+
logpoint expressions as executable live code.
|
|
250
|
+
|
|
180
251
|
### ๐ `cf-inspector watch`
|
|
181
252
|
|
|
182
253
|
Stream a snapshot per breakpoint hit. The inspectee is paused briefly while
|
|
@@ -203,19 +274,21 @@ Each event is a `WatchEvent`:
|
|
|
203
274
|
|
|
204
275
|
| Flag | Description |
|
|
205
276
|
| --- | --- |
|
|
206
|
-
| `--port <number>` | Local port the inspector or tunnel listens on |
|
|
277
|
+
| `--port <number>` | Local port the inspector or tunnel listens on. Otherwise pass all explicit Cloud Foundry selectors |
|
|
278
|
+
| `--target <index>` / `--worker <index>` | Select a raw inspector target or nested NodeWorker session from `list-targets` |
|
|
207
279
|
| `--bp <file:line>` | **Required.** Source location to capture on (repeatable) |
|
|
208
|
-
| `--capture <expr,โฆ>` | Top-level comma-separated expressions
|
|
209
|
-
| `--setup-eval <expr>` | Repeatable
|
|
210
|
-
| `--condition <expr>` |
|
|
280
|
+
| `--capture <expr,โฆ>` | Top-level comma-separated expressions evaluated per hit under V8's side-effect guard |
|
|
281
|
+
| `--setup-eval <expr>` | Repeatable mutation-capable global expression evaluated before breakpoint setup; recognizable risks produce a warning |
|
|
282
|
+
| `--condition <expr>` | Native condition; mutation-shaped conditions require `--allow-mutation` |
|
|
211
283
|
| `--hit-count <n>` | Start emitting once the line has been hit N or more times |
|
|
212
284
|
| `--remote-root <value>` | Path-mapping anchor (same DSL as `snapshot`) |
|
|
213
285
|
| `--duration <seconds>` | Stop streaming after N seconds (default: until SIGINT) |
|
|
214
286
|
| `--max-events <n>` | Stop streaming after emitting N events |
|
|
215
287
|
| `--timeout <seconds>` | How long to wait for the next hit before giving up (default: `30`) |
|
|
216
|
-
| `--max-value-length <chars>` | Maximum characters per captured value
|
|
288
|
+
| `--max-value-length <chars>` | Maximum characters per captured value (streaming default: `4096`) |
|
|
217
289
|
| `--stack-depth <n>` | Walk this many call frames per hit (default: `1`) |
|
|
218
|
-
| `--stack-captures <expr,โฆ>` | Expressions
|
|
290
|
+
| `--stack-captures <expr,โฆ>` | Expressions evaluated on each call frame under the capture side-effect guard |
|
|
291
|
+
| `--allow-mutation` | Disable the capture side-effect guard and explicitly allow mutation-shaped native conditions |
|
|
219
292
|
| `--include-scopes` | Include expanded paused-frame scopes per hit |
|
|
220
293
|
| `--no-json` | Print human-readable lines instead of JSON Lines |
|
|
221
294
|
|
|
@@ -250,20 +323,29 @@ Result is a `SnapshotResult` with an extra `exception` field:
|
|
|
250
323
|
|
|
251
324
|
| Flag | Description |
|
|
252
325
|
| --- | --- |
|
|
326
|
+
| `--port` or explicit `--region/--org/--space/--app` | Select the local inspector or deterministic Cloud Foundry target |
|
|
327
|
+
| `--target <index>` / `--worker <index>` | Select a raw inspector target or nested NodeWorker session from `list-targets` |
|
|
253
328
|
| `--type <state>` | Pause on which exceptions: `uncaught` (default), `caught`, or `all` |
|
|
254
|
-
| `--capture <expr,โฆ>` | Top-level expressions
|
|
329
|
+
| `--capture <expr,โฆ>` | Top-level expressions evaluated in the paused frame under V8's side-effect guard |
|
|
255
330
|
| `--stack-depth <n>` | Walk this many call frames (default: `1`) |
|
|
256
|
-
| `--stack-captures <expr,โฆ>` | Expressions
|
|
331
|
+
| `--stack-captures <expr,โฆ>` | Expressions evaluated on each frame under V8's side-effect guard |
|
|
332
|
+
| `--allow-mutation` | Disable the capture side-effect guard; heuristic matches gain `mutationRisk: true` |
|
|
257
333
|
| `--include-scopes` | Include paused-frame scopes |
|
|
258
334
|
| `--remote-root <value>` | Path-mapping anchor (only used if you also wire snapshot helpers) |
|
|
259
335
|
| `--timeout <seconds>` | How long to wait for an exception (default: `30`) |
|
|
260
|
-
| `--max-value-length <chars>` | Maximum characters per captured value
|
|
336
|
+
| `--max-value-length <chars>` | Maximum characters per captured value (one-shot default: `131072`) |
|
|
261
337
|
| `--keep-paused` | Skip `Debugger.resume` after capture |
|
|
262
338
|
| `--no-json` | Print a human-readable summary instead of JSON |
|
|
263
339
|
|
|
264
340
|
### ๐งฎ `cf-inspector eval`
|
|
265
341
|
|
|
266
|
-
Evaluate one expression with `Runtime.evaluate` in the
|
|
342
|
+
Evaluate one expression with `Runtime.evaluate` in the selected isolate's
|
|
343
|
+
global scope and print the result. `eval` is intentionally mutation-capable and
|
|
344
|
+
has no side-effect gate; recognizable mutation syntax emits an advisory warning
|
|
345
|
+
to `stderr`. For read-only paused-frame values, use `snapshot --capture` or call
|
|
346
|
+
the programmatic `evaluateOnFrame(..., { throwOnSideEffect: true })` API. Plain
|
|
347
|
+
`evaluateOnFrame(...)` remains unrestricted by default for backward
|
|
348
|
+
compatibility.
|
|
267
349
|
|
|
268
350
|
```bash
|
|
269
351
|
cf-inspector eval --port 9229 --expr 'process.uptime()'
|
|
@@ -279,14 +361,55 @@ cf-inspector list-scripts --port 9229 --filter 'dist/.+\.js'
|
|
|
279
361
|
|
|
280
362
|
### ๐ฏ `cf-inspector list-targets`
|
|
281
363
|
|
|
282
|
-
Print `/json/list` inspector targets with stable
|
|
364
|
+
Print raw `/json/list` inspector targets with stable `index` values, likely
|
|
365
|
+
worker labels, and the total target/worker counts on `stderr`. For each raw
|
|
366
|
+
target, the command also probes Node's `NodeWorker` CDP domain and lists live
|
|
367
|
+
nested workers with their own indexes.
|
|
283
368
|
|
|
284
369
|
```bash
|
|
285
370
|
cf-inspector list-targets --port 9229
|
|
371
|
+
cf-inspector snapshot --port 9229 --worker 0 --bp dist/worker.js:42
|
|
372
|
+
# If a runtime publishes a worker as another raw /json/list target instead:
|
|
286
373
|
cf-inspector snapshot --port 9229 --target 1 --bp dist/worker.js:42
|
|
287
374
|
```
|
|
288
375
|
|
|
289
|
-
|
|
376
|
+
JSON output nests workers beneath their raw target:
|
|
377
|
+
|
|
378
|
+
```json
|
|
379
|
+
[
|
|
380
|
+
{
|
|
381
|
+
"index": 0,
|
|
382
|
+
"description": "node.js instance",
|
|
383
|
+
"id": "target-id",
|
|
384
|
+
"type": "node",
|
|
385
|
+
"title": "app.mjs",
|
|
386
|
+
"url": "file:///app/app.mjs",
|
|
387
|
+
"webSocketDebuggerUrl": "ws://127.0.0.1:9229/target-id",
|
|
388
|
+
"likelyWorker": false,
|
|
389
|
+
"workerDiscoverySupported": true,
|
|
390
|
+
"workers": [
|
|
391
|
+
{"index": 0, "workerId": "1", "type": "worker", "title": "jobs", "url": "file:///app/worker.mjs"}
|
|
392
|
+
]
|
|
393
|
+
}
|
|
394
|
+
]
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
`--target` selects a complete raw inspector endpoint. `--worker` selects a
|
|
398
|
+
nested NodeWorker session under the chosen raw target (raw target `0` unless
|
|
399
|
+
`--target` is also passed). Modern Node.js 20โ25 verification found workers on
|
|
400
|
+
the `NodeWorker` path, including workers already alive before post-hoc
|
|
401
|
+
`SIGUSR1` inspector activation; the raw-target selector remains supported for
|
|
402
|
+
runtimes that publish that shape.
|
|
403
|
+
|
|
404
|
+
When multiple raw targets or nested workers exist and no selector is passed,
|
|
405
|
+
commands attach to raw target `0` and print a selection notice. A bound
|
|
406
|
+
breakpoint that sees no hit prints a worker-isolate hint. If only one raw target
|
|
407
|
+
and no workers are visible, `list-targets` explains that the worker may have
|
|
408
|
+
exited, the runtime may not expose NodeWorker discovery, or a separate worker
|
|
409
|
+
port may be unreachable through the single Cloud Foundry tunnel. Rerun the
|
|
410
|
+
command while the worker is alive before selecting an index.
|
|
411
|
+
|
|
412
|
+
If `list-targets`, `attach`, or another command reports `ECONNREFUSED`, the local inspector or tunnel on that port is usually stale/closed. Restart the local Node inspector or tunnel and retry; for Cloud Foundry targets, pass the complete `--region/--org/--space/--app` selector so `cf-inspector` can open a fresh tunnel.
|
|
290
413
|
|
|
291
414
|
### ๐ `cf-inspector attach`
|
|
292
415
|
|
|
@@ -296,19 +419,74 @@ Connect, fetch the runtime version, print it, disconnect. Useful as a smoke-test
|
|
|
296
419
|
cf-inspector attach --port 9229
|
|
297
420
|
```
|
|
298
421
|
|
|
422
|
+
`attach` checks the port-level `/json/version` endpoint, so raw-target and
|
|
423
|
+
worker selectors do not apply to this smoke test.
|
|
424
|
+
|
|
425
|
+
### Exact CDP tracing APIs
|
|
426
|
+
|
|
427
|
+
The library also exports lower-level, validated primitives for tools that need to plan and step an
|
|
428
|
+
exact loaded function instead of using a URL-regex breakpoint:
|
|
429
|
+
|
|
430
|
+
```ts
|
|
431
|
+
const scripts = listScripts(session);
|
|
432
|
+
const source = await getScriptSource(session, scripts[0].scriptId);
|
|
433
|
+
const locations = await getPossibleBreakpoints(session, {
|
|
434
|
+
start: { scriptId: scripts[0].scriptId, lineNumber: 10 },
|
|
435
|
+
restrictToFunction: true,
|
|
436
|
+
});
|
|
437
|
+
const breakpoint = await setBreakpointAtLocation(session, { location: locations[0] });
|
|
438
|
+
const pause = await waitForPause(session, {
|
|
439
|
+
timeoutMs: 30_000,
|
|
440
|
+
breakpointIds: [breakpoint.breakpointId],
|
|
441
|
+
signal: abortController.signal,
|
|
442
|
+
});
|
|
443
|
+
await stepOver(session);
|
|
444
|
+
await releaseObject(session, objectId);
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
`ScriptLocation` and `BreakLocation` use CDP-native zero-based line and column numbers. Exact
|
|
448
|
+
breakpoint setup returns both the requested and actual location, then fails closed and removes the
|
|
449
|
+
breakpoint if V8 resolves a different script, line, or column. An omitted column means CDP column
|
|
450
|
+
zero. `RemoteObjectInfo.completeness` is `truncated` for logical values stored in internal slots
|
|
451
|
+
(including maps, sets, promises, and dates) and `unavailable` for proxies; it is omitted for
|
|
452
|
+
ordinary objects. `waitForPause` accepts an `AbortSignal` and cleans its event listener and timer
|
|
453
|
+
on success, timeout, abort, or session close. The same layer exports `stepInto`, `stepOver`,
|
|
454
|
+
`stepOut`, `releaseObject`, and `releaseObjectGroup` for bounded controllers.
|
|
455
|
+
|
|
456
|
+
Programmatic Cloud Foundry tunnels can select the same process instance and Node PID used for both
|
|
457
|
+
the remote signal and SSH forwarding:
|
|
458
|
+
|
|
459
|
+
```ts
|
|
460
|
+
const tunnel = await openCfTunnel({
|
|
461
|
+
region: "eu10",
|
|
462
|
+
org: "my-org",
|
|
463
|
+
space: "dev",
|
|
464
|
+
app: "orders-srv",
|
|
465
|
+
process: "worker",
|
|
466
|
+
instance: 2,
|
|
467
|
+
nodePid: 4312,
|
|
468
|
+
});
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
`openCfTunnel` retains backward-compatible reuse when `cf-debugger` reports a healthy local port
|
|
472
|
+
for an existing session. Controllers that must prove they own and can dispose the tunnel should use
|
|
473
|
+
`openOwnedCfTunnel`; it propagates `SESSION_ALREADY_RUNNING` instead of parsing or borrowing a
|
|
474
|
+
pre-existing session.
|
|
475
|
+
|
|
299
476
|
---
|
|
300
477
|
|
|
301
478
|
## ๐ญ How it works
|
|
302
479
|
|
|
303
480
|
```
|
|
304
481
|
โโโโโโโโโโโโโโโโโโโโโโโโ 1. GET http://127.0.0.1:<port>/json/list
|
|
305
|
-
โ cf-inspector โ 2. Open
|
|
306
|
-
โ snapshot --bp X:Y โ โโบ3.
|
|
307
|
-
โโโโโโโโโโโโโโโโโโโโโโโโ 4. Debugger.
|
|
308
|
-
โ 5.
|
|
309
|
-
โผ 6. Debugger.
|
|
310
|
-
JSON snapshot 7.
|
|
311
|
-
8.
|
|
482
|
+
โ cf-inspector โ 2. Open the selected raw WebSocket target
|
|
483
|
+
โ snapshot --bp X:Y โ โโบ3. Optionally attach to a selected NodeWorker sub-session
|
|
484
|
+
โโโโโโโโโโโโโโโโโโโโโโโโ 4. Debugger.enable + Runtime.enable
|
|
485
|
+
โ 5. Debugger.setBreakpointByUrl({ urlRegex, lineNumber: Y - 1 })
|
|
486
|
+
โผ 6. Wait for `Debugger.paused`
|
|
487
|
+
JSON snapshot 7. Debugger.evaluateOnCallFrame({ throwOnSideEffect: true, ... })
|
|
488
|
+
8. Runtime.getProperties(...) when object/scopes are expanded
|
|
489
|
+
9. Debugger.resume (unless --keep-paused)
|
|
312
490
|
```
|
|
313
491
|
|
|
314
492
|
Path mapping uses CDP's first-class `urlRegex`:
|
|
@@ -326,7 +504,14 @@ Path mapping uses CDP's first-class `urlRegex`:
|
|
|
326
504
|
|
|
327
505
|
## โ๏ธ Composing with `cf-debugger`
|
|
328
506
|
|
|
329
|
-
If `--port` is omitted
|
|
507
|
+
If `--port` is omitted, all of `--region/--org/--space/--app` are required. The
|
|
508
|
+
CLI does not read ambient `cf target` state. It calls `startDebugger(...)` from
|
|
509
|
+
`@saptools/cf-debugger`, attaches over the SSH tunnel, and disposes the tunnel
|
|
510
|
+
on exit. You get the same one-shot UX whether the target is local or in CF.
|
|
511
|
+
|
|
512
|
+
The tunnel forwards one inspector port. Nested NodeWorker sessions carried by
|
|
513
|
+
that inspector connection are selectable with `--worker`; a worker exposing
|
|
514
|
+
only an unrelated separate port is outside that tunnel's reach.
|
|
330
515
|
|
|
331
516
|
```bash
|
|
332
517
|
cf-inspector snapshot \
|