@descryy/runtime-orchestrator 0.2.1 → 0.4.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/LICENSE +6 -0
- package/dist/attach-to-running-jvm-process.d.ts +45 -98
- package/dist/attach-to-running-jvm-process.d.ts.map +1 -1
- package/dist/attach-to-running-jvm-process.js +206 -136
- package/dist/attach-to-running-jvm-process.js.map +1 -1
- package/dist/attach-to-running-node-process.d.ts +45 -103
- package/dist/attach-to-running-node-process.d.ts.map +1 -1
- package/dist/attach-to-running-node-process.js +90 -115
- package/dist/attach-to-running-node-process.js.map +1 -1
- package/dist/attach-to-running-process.d.ts +32 -70
- package/dist/attach-to-running-process.d.ts.map +1 -1
- package/dist/attach-to-running-process.js +26 -54
- package/dist/attach-to-running-process.js.map +1 -1
- package/dist/cdp-client.d.ts +8 -18
- package/dist/cdp-client.d.ts.map +1 -1
- package/dist/cdp-client.js +9 -22
- package/dist/cdp-client.js.map +1 -1
- package/dist/cgroup-partial-restriction.d.ts +42 -89
- package/dist/cgroup-partial-restriction.d.ts.map +1 -1
- package/dist/cgroup-partial-restriction.js +44 -91
- package/dist/cgroup-partial-restriction.js.map +1 -1
- package/dist/collector-version.d.ts +3 -8
- package/dist/collector-version.d.ts.map +1 -1
- package/dist/collector-version.js +3 -8
- package/dist/collector-version.js.map +1 -1
- package/dist/instrumented-execution.d.ts +30 -73
- package/dist/instrumented-execution.d.ts.map +1 -1
- package/dist/instrumented-execution.js +121 -251
- package/dist/instrumented-execution.js.map +1 -1
- package/dist/jvm-agent/build.d.ts +29 -53
- package/dist/jvm-agent/build.d.ts.map +1 -1
- package/dist/jvm-agent/build.js +34 -61
- package/dist/jvm-agent/build.js.map +1 -1
- package/dist/polling-output-source.d.ts +8 -19
- package/dist/polling-output-source.d.ts.map +1 -1
- package/dist/polling-output-source.js +14 -31
- package/dist/polling-output-source.js.map +1 -1
- package/dist/profile-backend-observation.d.ts +26 -53
- package/dist/profile-backend-observation.d.ts.map +1 -1
- package/dist/profile-backend-observation.js +26 -55
- package/dist/profile-backend-observation.js.map +1 -1
- package/dist/respawn-and-supervise.d.ts +39 -72
- package/dist/respawn-and-supervise.d.ts.map +1 -1
- package/dist/respawn-and-supervise.js +43 -84
- package/dist/respawn-and-supervise.js.map +1 -1
- package/package.json +14 -9
|
@@ -1,85 +1,41 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Retroactive attach to an already-running **Node** process, via its own
|
|
3
|
-
*
|
|
4
|
-
* `documents/decisions-inbox/RT-attach-to-running-process-scope.md`
|
|
5
|
-
* deliberately did not build. That entry's own "deliberately not built"
|
|
6
|
-
* list names it directly: "Node's `SIGUSR1` inspector activation + a CDP
|
|
7
|
-
* WebSocket client — real, but Node-only and a new protocol surface, not
|
|
8
|
-
* built this pass." This is that pass, for Node only — the other two items
|
|
9
|
-
* on that list (JVM Attach API, ptrace) remain out of scope, unchanged.
|
|
2
|
+
* Retroactive attach to an already-running **Node** process, via its own inspector
|
|
3
|
+
* protocol (JVM Attach API and ptrace remain out of scope, per
|
|
4
|
+
* `documents/decisions-inbox/RT-attach-to-running-process-scope.md`).
|
|
10
5
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* to anything already running." This one needs nothing declared at launch:
|
|
16
|
-
* `SIGUSR1` (POSIX only; Node's own signal handler, not something this
|
|
17
|
-
* process installs) turns on the target's inspector **after the fact**, on
|
|
18
|
-
* a process that was never started with `--inspect` and never expected to
|
|
19
|
-
* be debugged. From that moment its debugger discovery endpoint is
|
|
20
|
-
* reachable at `http://127.0.0.1:<port>/json`, by the target itself, not by
|
|
21
|
-
* anything this collector primed in advance.
|
|
6
|
+
* Unlike the file-based `attachToRunningProcess`, this needs nothing declared at
|
|
7
|
+
* launch: `SIGUSR1` (POSIX only) turns on the target's inspector after the fact,
|
|
8
|
+
* making `http://127.0.0.1:<port>/json` reachable even on a process never started
|
|
9
|
+
* with `--inspect`.
|
|
22
10
|
*
|
|
23
|
-
* **
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* `SIGUSR1` binds to when nothing else is already listening there), and if
|
|
30
|
-
* a caller already knows the target was configured for a different port
|
|
31
|
-
* (`--inspect-port`, `NODE_OPTIONS`), they supply it. **If the port is
|
|
32
|
-
* genuinely unknown and is not 9229, this module cannot discover it** — not
|
|
33
|
-
* attempted, not guessed at by scanning a port range, which would risk
|
|
34
|
-
* attaching to the wrong process's inspector entirely.
|
|
11
|
+
* **Disclosed limit:** `SIGUSR1` doesn't report which port the inspector bound —
|
|
12
|
+
* Node prints that to the target's own stderr, unreadable for a process we didn't
|
|
13
|
+
* spawn (RT-024). So discovery tries the default port (9229) unless the caller
|
|
14
|
+
* supplies `discoveryPort`; a genuinely unknown non-default port cannot be
|
|
15
|
+
* discovered (not guessed at by port-scanning, which risks attaching to the wrong
|
|
16
|
+
* process).
|
|
35
17
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* Playwright's own browser-automation abstraction (`page.on("console")`),
|
|
39
|
-
* which assumes a `Target`/`Page`-domain browser session — a Node inspector
|
|
40
|
-
* session has neither domain, being a single top-level `Runtime` session
|
|
41
|
-
* instead. `cdp-client.ts` in this package is the actual reusable piece:
|
|
42
|
-
* protocol-family-generic, so a future browser-side raw-CDP need could
|
|
43
|
-
* reuse it too, instead of a third client getting written.
|
|
18
|
+
* CDP client is `cdp-client.ts`, not Playwright's console API, which assumes a
|
|
19
|
+
* Target/Page-domain session a Node inspector doesn't have (see that file).
|
|
44
20
|
*
|
|
45
|
-
* **Measured
|
|
46
|
-
* 100ms
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* purpose — attaching to something genuinely already running, which by
|
|
51
|
-
* definition has been alive far longer than that window — but real, and
|
|
52
|
-
* worth naming for a caller tempted to attach immediately after spawning
|
|
53
|
-
* something themselves.
|
|
21
|
+
* **Measured:** a freshly-spawned target has a brief window (sometimes under
|
|
22
|
+
* 100ms) before Node installs its `SIGUSR1` handler; a signal sent inside it hits
|
|
23
|
+
* POSIX's default terminate action instead of toggling the inspector. Irrelevant
|
|
24
|
+
* to attaching to something already running, but real for a caller attaching
|
|
25
|
+
* right after spawning.
|
|
54
26
|
*
|
|
55
|
-
* **Measured side effect
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
* inspect the paused, crashed state before the process actually exits.
|
|
61
|
-
* Measured directly (a naive test that waited for the child's own `exit`
|
|
62
|
-
* event after attach hung indefinitely) rather than assumed from docs. This
|
|
63
|
-
* is standard CDP/V8 behaviour, not a defect this collector introduces, and
|
|
64
|
-
* not silently worked around: the process resumes its exit exactly when
|
|
65
|
-
* `stop()` closes the CDP session, which is also when the exception's own
|
|
66
|
-
* evidence has already been captured, so nothing about the timing costs a
|
|
67
|
-
* caller the evidence. A caller relying on "did the target exit yet?" as a
|
|
68
|
-
* signal must call `stop()` first.
|
|
27
|
+
* **Measured side effect:** once CDP connects, V8 no longer terminates on an
|
|
28
|
+
* uncaught exception — it blocks ("Waiting for the debugger to disconnect...")
|
|
29
|
+
* exactly as under `--inspect-brk`, until `stop()` closes the session. Standard
|
|
30
|
+
* CDP/V8 behaviour, not worked around; a caller checking "did the target exit
|
|
31
|
+
* yet?" must call `stop()` first.
|
|
69
32
|
*
|
|
70
|
-
* **
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* backend process being observed, and `EvidenceSource` already names what
|
|
77
|
-
* was observed rather than which mechanism did it (`inbound-proxy.ts`'s own
|
|
78
|
-
* precedent, restated there for exactly this reason). `capabilities()`
|
|
79
|
-
* reports `backendLogAccess`, not `consoleObservation` — `consoleObservation`
|
|
80
|
-
* is `browser-console-collector`'s claim on a *browser page's* console,
|
|
81
|
-
* kept apart from a backend process's console the same way `LogCollector`
|
|
82
|
-
* already keeps them apart for its own text-based capture.
|
|
33
|
+
* **Vocabulary:** `Runtime.consoleAPICalled`→`CONSOLE_MESSAGE`,
|
|
34
|
+
* `Runtime.exceptionThrown`→`EXCEPTION`, same `RuntimeEventType`s
|
|
35
|
+
* `browser-console-collector.ts` uses for the browser-page analogues.
|
|
36
|
+
* `source: "backend-process"` (not a new value — `EvidenceSource` names what was
|
|
37
|
+
* observed, not the mechanism). `capabilities()` reports `backendLogAccess`, not
|
|
38
|
+
* `consoleObservation` (reserved for a browser page's console).
|
|
83
39
|
*/
|
|
84
40
|
import type { Collector } from "@descryy/runtime-contracts";
|
|
85
41
|
export interface AttachToRunningNodeProcessOptions {
|
|
@@ -89,28 +45,19 @@ export interface AttachToRunningNodeProcessOptions {
|
|
|
89
45
|
readonly service?: string;
|
|
90
46
|
/** Node's own default inspector bind address. Overridable for a target known to bind elsewhere. */
|
|
91
47
|
readonly discoveryHost?: string;
|
|
92
|
-
/**
|
|
93
|
-
* Node's own default inspector port, and the only one `SIGUSR1` reliably
|
|
94
|
-
* produces on an unmodified target. See this file's own module doc for
|
|
95
|
-
* why a non-default port cannot be discovered from outside and must be
|
|
96
|
-
* supplied here when known.
|
|
97
|
-
*/
|
|
48
|
+
/** Node's default inspector port — the only one `SIGUSR1` reliably produces on an unmodified target. See module doc: a non-default port must be supplied here. */
|
|
98
49
|
readonly discoveryPort?: number;
|
|
99
50
|
/** How long to poll the discovery endpoint after sending SIGUSR1 before giving up. The inspector does not bind instantaneously. */
|
|
100
51
|
readonly discoveryTimeoutMs?: number;
|
|
101
52
|
}
|
|
102
53
|
/**
|
|
103
54
|
* Sends `SIGUSR1` to `pid`, then polls `http://<host>:<port>/json` until the
|
|
104
|
-
*
|
|
105
|
-
* `webSocketDebuggerUrl`
|
|
106
|
-
*
|
|
107
|
-
* unlike a browser's `/json`, which lists one entry per open tab.
|
|
55
|
+
* inspector answers or `timeoutMs` elapses. Resolves with the first entry's
|
|
56
|
+
* `webSocketDebuggerUrl` — a Node process presents exactly one inspectable
|
|
57
|
+
* target, unlike a browser's `/json` (one per tab).
|
|
108
58
|
*
|
|
109
|
-
* Rejects
|
|
110
|
-
*
|
|
111
|
-
* port that never answers (most often because the real inspector bound
|
|
112
|
-
* somewhere other than `port`, which this function has no way to learn —
|
|
113
|
-
* see the module doc).
|
|
59
|
+
* Rejects naming the exact blocker rather than hanging or guessing: dead pid,
|
|
60
|
+
* non-POSIX platform, or a port that never answers (see module doc).
|
|
114
61
|
*/
|
|
115
62
|
export declare function discoverNodeInspectorUrl(pid: number, options?: {
|
|
116
63
|
readonly host?: string;
|
|
@@ -118,21 +65,16 @@ export declare function discoverNodeInspectorUrl(pid: number, options?: {
|
|
|
118
65
|
readonly timeoutMs?: number;
|
|
119
66
|
}): Promise<string>;
|
|
120
67
|
/**
|
|
121
|
-
* Attach to an already-running Node process via `SIGUSR1` + CDP,
|
|
122
|
-
*
|
|
68
|
+
* Attach to an already-running Node process via `SIGUSR1` + CDP, capturing
|
|
69
|
+
* `CONSOLE_MESSAGE`/`EXCEPTION` evidence from that moment forward.
|
|
123
70
|
*
|
|
124
|
-
* **Retroactive, not historical.** Anything
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
* sibling) is the one that can recover pre-attach lines, and only because a
|
|
128
|
-
* file on disk already held them; nothing analogous exists for CDP, which
|
|
129
|
-
* is a live event stream with no buffer of its own.
|
|
71
|
+
* **Retroactive, not historical.** Anything logged or thrown before attach is
|
|
72
|
+
* gone — CDP is a live event stream with no buffer of its own (unlike the
|
|
73
|
+
* file-based `attachToRunningProcess`, which recovers pre-attach lines from disk).
|
|
130
74
|
*
|
|
131
|
-
* Discovery
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
* `{ available: false, reason }`, never a thrown exception a caller has to
|
|
135
|
-
* remember to catch.
|
|
75
|
+
* Discovery/connection happen inside `start()`, matching every other `Collector`
|
|
76
|
+
* here: a routine failure resolves as `{ available: false, reason }`, never a
|
|
77
|
+
* thrown exception.
|
|
136
78
|
*/
|
|
137
79
|
export declare function attachToRunningNodeProcess(options: AttachToRunningNodeProcessOptions): Collector;
|
|
138
80
|
//# sourceMappingURL=attach-to-running-node-process.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attach-to-running-node-process.d.ts","sourceRoot":"","sources":["../src/attach-to-running-node-process.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"attach-to-running-node-process.d.ts","sourceRoot":"","sources":["../src/attach-to-running-node-process.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAyG,MAAM,4BAA4B,CAAC;AAsCnK,MAAM,WAAW,iCAAiC;IAChD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,uIAAuI;IACvI,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,mGAAmG;IACnG,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,kKAAkK;IAClK,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,mIAAmI;IACnI,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;CACtC;AAOD;;;;;;;;GAQG;AACH,wBAAsB,wBAAwB,CAC5C,GAAG,EAAE,MAAM,EACX,OAAO,GAAE;IAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5F,OAAO,CAAC,MAAM,CAAC,CA+CjB;AAsED;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,iCAAiC,GAAG,SAAS,CAmHhG"}
|
|
@@ -1,101 +1,85 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Retroactive attach to an already-running **Node** process, via its own
|
|
3
|
-
*
|
|
4
|
-
* `documents/decisions-inbox/RT-attach-to-running-process-scope.md`
|
|
5
|
-
* deliberately did not build. That entry's own "deliberately not built"
|
|
6
|
-
* list names it directly: "Node's `SIGUSR1` inspector activation + a CDP
|
|
7
|
-
* WebSocket client — real, but Node-only and a new protocol surface, not
|
|
8
|
-
* built this pass." This is that pass, for Node only — the other two items
|
|
9
|
-
* on that list (JVM Attach API, ptrace) remain out of scope, unchanged.
|
|
2
|
+
* Retroactive attach to an already-running **Node** process, via its own inspector
|
|
3
|
+
* protocol (JVM Attach API and ptrace remain out of scope, per
|
|
4
|
+
* `documents/decisions-inbox/RT-attach-to-running-process-scope.md`).
|
|
10
5
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* to anything already running." This one needs nothing declared at launch:
|
|
16
|
-
* `SIGUSR1` (POSIX only; Node's own signal handler, not something this
|
|
17
|
-
* process installs) turns on the target's inspector **after the fact**, on
|
|
18
|
-
* a process that was never started with `--inspect` and never expected to
|
|
19
|
-
* be debugged. From that moment its debugger discovery endpoint is
|
|
20
|
-
* reachable at `http://127.0.0.1:<port>/json`, by the target itself, not by
|
|
21
|
-
* anything this collector primed in advance.
|
|
6
|
+
* Unlike the file-based `attachToRunningProcess`, this needs nothing declared at
|
|
7
|
+
* launch: `SIGUSR1` (POSIX only) turns on the target's inspector after the fact,
|
|
8
|
+
* making `http://127.0.0.1:<port>/json` reachable even on a process never started
|
|
9
|
+
* with `--inspect`.
|
|
22
10
|
*
|
|
23
|
-
* **
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* `SIGUSR1` binds to when nothing else is already listening there), and if
|
|
30
|
-
* a caller already knows the target was configured for a different port
|
|
31
|
-
* (`--inspect-port`, `NODE_OPTIONS`), they supply it. **If the port is
|
|
32
|
-
* genuinely unknown and is not 9229, this module cannot discover it** — not
|
|
33
|
-
* attempted, not guessed at by scanning a port range, which would risk
|
|
34
|
-
* attaching to the wrong process's inspector entirely.
|
|
11
|
+
* **Disclosed limit:** `SIGUSR1` doesn't report which port the inspector bound —
|
|
12
|
+
* Node prints that to the target's own stderr, unreadable for a process we didn't
|
|
13
|
+
* spawn (RT-024). So discovery tries the default port (9229) unless the caller
|
|
14
|
+
* supplies `discoveryPort`; a genuinely unknown non-default port cannot be
|
|
15
|
+
* discovered (not guessed at by port-scanning, which risks attaching to the wrong
|
|
16
|
+
* process).
|
|
35
17
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* Playwright's own browser-automation abstraction (`page.on("console")`),
|
|
39
|
-
* which assumes a `Target`/`Page`-domain browser session — a Node inspector
|
|
40
|
-
* session has neither domain, being a single top-level `Runtime` session
|
|
41
|
-
* instead. `cdp-client.ts` in this package is the actual reusable piece:
|
|
42
|
-
* protocol-family-generic, so a future browser-side raw-CDP need could
|
|
43
|
-
* reuse it too, instead of a third client getting written.
|
|
18
|
+
* CDP client is `cdp-client.ts`, not Playwright's console API, which assumes a
|
|
19
|
+
* Target/Page-domain session a Node inspector doesn't have (see that file).
|
|
44
20
|
*
|
|
45
|
-
* **Measured
|
|
46
|
-
* 100ms
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* purpose — attaching to something genuinely already running, which by
|
|
51
|
-
* definition has been alive far longer than that window — but real, and
|
|
52
|
-
* worth naming for a caller tempted to attach immediately after spawning
|
|
53
|
-
* something themselves.
|
|
21
|
+
* **Measured:** a freshly-spawned target has a brief window (sometimes under
|
|
22
|
+
* 100ms) before Node installs its `SIGUSR1` handler; a signal sent inside it hits
|
|
23
|
+
* POSIX's default terminate action instead of toggling the inspector. Irrelevant
|
|
24
|
+
* to attaching to something already running, but real for a caller attaching
|
|
25
|
+
* right after spawning.
|
|
54
26
|
*
|
|
55
|
-
* **Measured side effect
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
* inspect the paused, crashed state before the process actually exits.
|
|
61
|
-
* Measured directly (a naive test that waited for the child's own `exit`
|
|
62
|
-
* event after attach hung indefinitely) rather than assumed from docs. This
|
|
63
|
-
* is standard CDP/V8 behaviour, not a defect this collector introduces, and
|
|
64
|
-
* not silently worked around: the process resumes its exit exactly when
|
|
65
|
-
* `stop()` closes the CDP session, which is also when the exception's own
|
|
66
|
-
* evidence has already been captured, so nothing about the timing costs a
|
|
67
|
-
* caller the evidence. A caller relying on "did the target exit yet?" as a
|
|
68
|
-
* signal must call `stop()` first.
|
|
27
|
+
* **Measured side effect:** once CDP connects, V8 no longer terminates on an
|
|
28
|
+
* uncaught exception — it blocks ("Waiting for the debugger to disconnect...")
|
|
29
|
+
* exactly as under `--inspect-brk`, until `stop()` closes the session. Standard
|
|
30
|
+
* CDP/V8 behaviour, not worked around; a caller checking "did the target exit
|
|
31
|
+
* yet?" must call `stop()` first.
|
|
69
32
|
*
|
|
70
|
-
* **
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* backend process being observed, and `EvidenceSource` already names what
|
|
77
|
-
* was observed rather than which mechanism did it (`inbound-proxy.ts`'s own
|
|
78
|
-
* precedent, restated there for exactly this reason). `capabilities()`
|
|
79
|
-
* reports `backendLogAccess`, not `consoleObservation` — `consoleObservation`
|
|
80
|
-
* is `browser-console-collector`'s claim on a *browser page's* console,
|
|
81
|
-
* kept apart from a backend process's console the same way `LogCollector`
|
|
82
|
-
* already keeps them apart for its own text-based capture.
|
|
33
|
+
* **Vocabulary:** `Runtime.consoleAPICalled`→`CONSOLE_MESSAGE`,
|
|
34
|
+
* `Runtime.exceptionThrown`→`EXCEPTION`, same `RuntimeEventType`s
|
|
35
|
+
* `browser-console-collector.ts` uses for the browser-page analogues.
|
|
36
|
+
* `source: "backend-process"` (not a new value — `EvidenceSource` names what was
|
|
37
|
+
* observed, not the mechanism). `capabilities()` reports `backendLogAccess`, not
|
|
38
|
+
* `consoleObservation` (reserved for a browser page's console).
|
|
83
39
|
*/
|
|
40
|
+
import { spawnSync } from "node:child_process";
|
|
84
41
|
import { connectCdp } from "./cdp-client.js";
|
|
85
42
|
import { isProcessAlive } from "./attach-to-running-process.js";
|
|
86
43
|
import { COLLECTOR_VERSION } from "./collector-version.js";
|
|
44
|
+
/**
|
|
45
|
+
* A-F10: verifies `pid` is owned by this process's own user AND looks like a
|
|
46
|
+
* Node process, BEFORE `SIGUSR1` is sent — a wrong-kind pid with no handler hits
|
|
47
|
+
* POSIX's default terminate action; `isProcessAlive` alone doesn't rule that out.
|
|
48
|
+
*
|
|
49
|
+
* Uses `ps -o uid=,comm= -p <pid>` rather than `/proc/<pid>` since this module is
|
|
50
|
+
* POSIX-only and `ps` works on both Linux and macOS. Refuses rather than guesses
|
|
51
|
+
* when `ps` itself can't answer.
|
|
52
|
+
*
|
|
53
|
+
* Same-user, not same-session: the kernel lets any same-user process signal any
|
|
54
|
+
* other, so this check is the only backstop for `SIGUSR1` — unlike HotSpot's
|
|
55
|
+
* attach socket (the JVM sibling), which enforces uid at the OS level itself.
|
|
56
|
+
*/
|
|
57
|
+
function verifyLikelyNodeProcessOwnedBySelf(pid) {
|
|
58
|
+
const result = spawnSync("ps", ["-o", "uid=,comm=", "-p", String(pid)], { encoding: "utf8" });
|
|
59
|
+
const line = (result.stdout ?? "").trim().split("\n")[0]?.trim();
|
|
60
|
+
if (result.status !== 0 || line === undefined || line === "") {
|
|
61
|
+
return { ok: false, reason: `could not verify pid ${String(pid)}'s owner/command via ps (exit ${String(result.status)}) — refusing to signal a process this module cannot confirm the identity of` };
|
|
62
|
+
}
|
|
63
|
+
const [uidField, ...commFields] = line.split(/\s+/);
|
|
64
|
+
const uid = Number(uidField);
|
|
65
|
+
const comm = commFields.join(" ").toLowerCase();
|
|
66
|
+
const ownUid = process.getuid?.();
|
|
67
|
+
if (ownUid !== undefined && uid !== ownUid) {
|
|
68
|
+
return { ok: false, reason: `pid ${String(pid)} is owned by uid ${String(uid)}, not this process's own uid ${String(ownUid)} — refusing to signal a process this session does not own` };
|
|
69
|
+
}
|
|
70
|
+
if (!comm.includes("node")) {
|
|
71
|
+
return { ok: false, reason: `pid ${String(pid)}'s command is "${comm}", which does not look like a Node process — refusing to send SIGUSR1 to a process that may not handle it` };
|
|
72
|
+
}
|
|
73
|
+
return { ok: true };
|
|
74
|
+
}
|
|
87
75
|
/**
|
|
88
76
|
* Sends `SIGUSR1` to `pid`, then polls `http://<host>:<port>/json` until the
|
|
89
|
-
*
|
|
90
|
-
* `webSocketDebuggerUrl`
|
|
91
|
-
*
|
|
92
|
-
* unlike a browser's `/json`, which lists one entry per open tab.
|
|
77
|
+
* inspector answers or `timeoutMs` elapses. Resolves with the first entry's
|
|
78
|
+
* `webSocketDebuggerUrl` — a Node process presents exactly one inspectable
|
|
79
|
+
* target, unlike a browser's `/json` (one per tab).
|
|
93
80
|
*
|
|
94
|
-
* Rejects
|
|
95
|
-
*
|
|
96
|
-
* port that never answers (most often because the real inspector bound
|
|
97
|
-
* somewhere other than `port`, which this function has no way to learn —
|
|
98
|
-
* see the module doc).
|
|
81
|
+
* Rejects naming the exact blocker rather than hanging or guessing: dead pid,
|
|
82
|
+
* non-POSIX platform, or a port that never answers (see module doc).
|
|
99
83
|
*/
|
|
100
84
|
export async function discoverNodeInspectorUrl(pid, options = {}) {
|
|
101
85
|
if (!isProcessAlive(pid)) {
|
|
@@ -104,6 +88,11 @@ export async function discoverNodeInspectorUrl(pid, options = {}) {
|
|
|
104
88
|
if (process.platform === "win32") {
|
|
105
89
|
throw new Error("discoverNodeInspectorUrl: SIGUSR1 inspector activation is POSIX-only; not available on win32.");
|
|
106
90
|
}
|
|
91
|
+
// A-F10: verified BEFORE the signal — a wrong pid must never reach process.kill
|
|
92
|
+
const identity = verifyLikelyNodeProcessOwnedBySelf(pid);
|
|
93
|
+
if (!identity.ok) {
|
|
94
|
+
throw new Error(`discoverNodeInspectorUrl: ${identity.reason}.`);
|
|
95
|
+
}
|
|
107
96
|
const host = options.host ?? "127.0.0.1";
|
|
108
97
|
const port = options.port ?? 9229;
|
|
109
98
|
const timeoutMs = options.timeoutMs ?? 5000;
|
|
@@ -135,7 +124,7 @@ export async function discoverNodeInspectorUrl(pid, options = {}) {
|
|
|
135
124
|
"process, or the target was itself configured with --inspect-port/NODE_OPTIONS) — this module cannot discover a " +
|
|
136
125
|
"non-default port from outside; a caller who knows the real port must supply discoveryPort.");
|
|
137
126
|
}
|
|
138
|
-
/**
|
|
127
|
+
/** Decodes a `file://` URL to a plain filesystem path, matching every other adapter's convention. Anything else is passed through verbatim. */
|
|
139
128
|
function pathFromCdpUrl(url) {
|
|
140
129
|
if (url === undefined || url === "")
|
|
141
130
|
return null;
|
|
@@ -148,16 +137,14 @@ function pathFromCdpUrl(url) {
|
|
|
148
137
|
return url;
|
|
149
138
|
}
|
|
150
139
|
}
|
|
151
|
-
/** CDP reports 0-based line/column;
|
|
140
|
+
/** CDP reports 0-based line/column; converted to this codebase's 1-based convention here, once. */
|
|
152
141
|
function locationFromCallFrame(frame) {
|
|
153
142
|
return {
|
|
154
143
|
file: pathFromCdpUrl(frame.url),
|
|
155
144
|
line: typeof frame.lineNumber === "number" ? frame.lineNumber + 1 : null,
|
|
156
145
|
column: typeof frame.columnNumber === "number" ? frame.columnNumber + 1 : null,
|
|
157
146
|
functionName: frame.functionName !== undefined && frame.functionName !== "" ? frame.functionName : null,
|
|
158
|
-
// V8's own reported state, captured live
|
|
159
|
-
// same class a Python traceback or Ruby backtrace gets, never a side
|
|
160
|
-
// artifact this collector resolved through.
|
|
147
|
+
// V8's own reported state, captured live -- never a side artifact resolved through
|
|
161
148
|
reliability: "self-contained",
|
|
162
149
|
resolvedVia: null,
|
|
163
150
|
};
|
|
@@ -178,19 +165,14 @@ function notThisCollectorsJob(what) {
|
|
|
178
165
|
}
|
|
179
166
|
const CAPABILITIES = {
|
|
180
167
|
domObservation: notThisCollectorsJob("DOM inspection"),
|
|
181
|
-
//
|
|
182
|
-
//
|
|
183
|
-
// backendLogAccess instead, matching LogCollector's own split.
|
|
168
|
+
// reserved for a browser page's console; this is a backend process's, reported
|
|
169
|
+
// under backendLogAccess instead, matching LogCollector's own split
|
|
184
170
|
consoleObservation: notThisCollectorsJob("a browser page's console"),
|
|
185
171
|
networkObservation: notThisCollectorsJob("network traffic"),
|
|
186
172
|
backendLogAccess: { availability: "available", reason: null },
|
|
187
173
|
distributedTrace: notThisCollectorsJob("trace-id/request-id correlation — CDP's Runtime domain carries no such fields to extract"),
|
|
188
|
-
//
|
|
189
|
-
//
|
|
190
|
-
// artifact this collector resolved through. A target running compiled or
|
|
191
|
-
// bundled output would still report positions in that output verbatim,
|
|
192
|
-
// the same honest limit every self-contained-reliability adapter in this
|
|
193
|
-
// repo carries, not something specific to Node inspector observation.
|
|
174
|
+
// self-contained reliability: a bundled/compiled target still reports positions
|
|
175
|
+
// in that output verbatim, same limit every self-contained adapter carries
|
|
194
176
|
sourceMapping: { availability: "available", reason: null },
|
|
195
177
|
stackCapture: { availability: "available", reason: null },
|
|
196
178
|
processLifecycle: notThisCollectorsJob("process lifecycle — spawn/ready/exit are ProcessCollector's to observe"),
|
|
@@ -198,21 +180,16 @@ const CAPABILITIES = {
|
|
|
198
180
|
externalServiceObservation: notThisCollectorsJob("outbound external requests"),
|
|
199
181
|
};
|
|
200
182
|
/**
|
|
201
|
-
* Attach to an already-running Node process via `SIGUSR1` + CDP,
|
|
202
|
-
*
|
|
183
|
+
* Attach to an already-running Node process via `SIGUSR1` + CDP, capturing
|
|
184
|
+
* `CONSOLE_MESSAGE`/`EXCEPTION` evidence from that moment forward.
|
|
203
185
|
*
|
|
204
|
-
* **Retroactive, not historical.** Anything
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
* sibling) is the one that can recover pre-attach lines, and only because a
|
|
208
|
-
* file on disk already held them; nothing analogous exists for CDP, which
|
|
209
|
-
* is a live event stream with no buffer of its own.
|
|
186
|
+
* **Retroactive, not historical.** Anything logged or thrown before attach is
|
|
187
|
+
* gone — CDP is a live event stream with no buffer of its own (unlike the
|
|
188
|
+
* file-based `attachToRunningProcess`, which recovers pre-attach lines from disk).
|
|
210
189
|
*
|
|
211
|
-
* Discovery
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
* `{ available: false, reason }`, never a thrown exception a caller has to
|
|
215
|
-
* remember to catch.
|
|
190
|
+
* Discovery/connection happen inside `start()`, matching every other `Collector`
|
|
191
|
+
* here: a routine failure resolves as `{ available: false, reason }`, never a
|
|
192
|
+
* thrown exception.
|
|
216
193
|
*/
|
|
217
194
|
export function attachToRunningNodeProcess(options) {
|
|
218
195
|
let session = null;
|
|
@@ -271,10 +248,8 @@ export function attachToRunningNodeProcess(options) {
|
|
|
271
248
|
: (details.text ?? "Uncaught exception");
|
|
272
249
|
const callFrames = details.stackTrace?.callFrames ?? [];
|
|
273
250
|
const frames = callFrames.map((frame) => ({ location: locationFromCallFrame(frame), raw: `${frame.functionName ?? "<anonymous>"} (${frame.url ?? ""}:${String(frame.lineNumber)}:${String(frame.columnNumber)})` }));
|
|
274
|
-
//
|
|
275
|
-
//
|
|
276
|
-
// still real, so it becomes a synthetic one-frame trace rather than
|
|
277
|
-
// being discarded.
|
|
251
|
+
// no frames from CDP: fall back to the throw site itself as a synthetic
|
|
252
|
+
// one-frame trace rather than discarding it
|
|
278
253
|
const stackTrace = frames.length > 0
|
|
279
254
|
? { fidelity: "synchronous", frames, primaryFrameIndex: 0 }
|
|
280
255
|
: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attach-to-running-node-process.js","sourceRoot":"","sources":["../src/attach-to-running-node-process.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"attach-to-running-node-process.js","sourceRoot":"","sources":["../src/attach-to-running-node-process.ts"],"names":[],"mappings":"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"}
|