@saptools/cf-inspector 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +168 -77
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +123 -35
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/cli.d.ts +0 -2
package/dist/index.d.ts
CHANGED
|
@@ -140,11 +140,15 @@ interface CdpTransport {
|
|
|
140
140
|
on<E extends keyof CdpTransportEventMap>(event: E, listener: CdpTransportEventMap[E]): void;
|
|
141
141
|
off<E extends keyof CdpTransportEventMap>(event: E, listener: CdpTransportEventMap[E]): void;
|
|
142
142
|
}
|
|
143
|
-
|
|
143
|
+
interface CdpTransportFactoryOptions {
|
|
144
|
+
readonly connectTimeoutMs?: number;
|
|
145
|
+
}
|
|
146
|
+
type CdpTransportFactory = (url: string, options?: CdpTransportFactoryOptions) => Promise<CdpTransport>;
|
|
144
147
|
interface CdpClientOptions {
|
|
145
148
|
readonly url: string;
|
|
146
149
|
readonly transportFactory?: CdpTransportFactory;
|
|
147
150
|
readonly requestTimeoutMs?: number;
|
|
151
|
+
readonly connectTimeoutMs?: number;
|
|
148
152
|
}
|
|
149
153
|
declare class CdpClient {
|
|
150
154
|
private readonly transport;
|
|
@@ -155,6 +159,7 @@ declare class CdpClient {
|
|
|
155
159
|
private closed;
|
|
156
160
|
private closeReason;
|
|
157
161
|
private readonly handleMessage;
|
|
162
|
+
private safeEmit;
|
|
158
163
|
private readonly handleClose;
|
|
159
164
|
private readonly handleError;
|
|
160
165
|
private constructor();
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
1
|
var __defProp = Object.defineProperty;
|
|
3
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
3
|
var __esm = (fn, res) => function __init() {
|
|
@@ -35,10 +34,19 @@ __export(wsTransport_exports, {
|
|
|
35
34
|
wsTransportFactory: () => wsTransportFactory
|
|
36
35
|
});
|
|
37
36
|
import { WebSocket } from "ws";
|
|
38
|
-
async function wsTransportFactory(url) {
|
|
37
|
+
async function wsTransportFactory(url, options = {}) {
|
|
39
38
|
const socket = new WebSocket(url, { perMessageDeflate: false });
|
|
40
|
-
await waitForOpen(socket, url);
|
|
41
|
-
const wrappers = /* @__PURE__ */ new
|
|
39
|
+
await waitForOpen(socket, url, options.connectTimeoutMs);
|
|
40
|
+
const wrappers = /* @__PURE__ */ new Map();
|
|
41
|
+
function wrappersFor(event) {
|
|
42
|
+
const existing = wrappers.get(event);
|
|
43
|
+
if (existing !== void 0) {
|
|
44
|
+
return existing;
|
|
45
|
+
}
|
|
46
|
+
const created = /* @__PURE__ */ new WeakMap();
|
|
47
|
+
wrappers.set(event, created);
|
|
48
|
+
return created;
|
|
49
|
+
}
|
|
42
50
|
return {
|
|
43
51
|
send(payload) {
|
|
44
52
|
socket.send(payload);
|
|
@@ -50,11 +58,12 @@ async function wsTransportFactory(url) {
|
|
|
50
58
|
return socket.readyState;
|
|
51
59
|
},
|
|
52
60
|
on(event, listener) {
|
|
53
|
-
const wrapped = wrapListener(event, listener
|
|
61
|
+
const wrapped = wrapListener(event, listener);
|
|
62
|
+
wrappersFor(event).set(listener, wrapped);
|
|
54
63
|
socket.on(event, wrapped);
|
|
55
64
|
},
|
|
56
65
|
off(event, listener) {
|
|
57
|
-
const wrapped =
|
|
66
|
+
const wrapped = wrappersFor(event).get(listener);
|
|
58
67
|
if (!wrapped) {
|
|
59
68
|
return;
|
|
60
69
|
}
|
|
@@ -62,14 +71,30 @@ async function wsTransportFactory(url) {
|
|
|
62
71
|
}
|
|
63
72
|
};
|
|
64
73
|
}
|
|
65
|
-
async function waitForOpen(socket, url) {
|
|
74
|
+
async function waitForOpen(socket, url, timeoutMs) {
|
|
66
75
|
await new Promise((resolve, reject) => {
|
|
67
|
-
|
|
76
|
+
let settled = false;
|
|
77
|
+
const cleanup = () => {
|
|
78
|
+
socket.off("open", onOpen);
|
|
68
79
|
socket.off("error", onError);
|
|
80
|
+
if (timer !== void 0) {
|
|
81
|
+
clearTimeout(timer);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
const onOpen = () => {
|
|
85
|
+
if (settled) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
settled = true;
|
|
89
|
+
cleanup();
|
|
69
90
|
resolve();
|
|
70
91
|
};
|
|
71
92
|
const onError = (err) => {
|
|
72
|
-
|
|
93
|
+
if (settled) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
settled = true;
|
|
97
|
+
cleanup();
|
|
73
98
|
reject(
|
|
74
99
|
new CfInspectorError(
|
|
75
100
|
"INSPECTOR_CONNECTION_FAILED",
|
|
@@ -77,29 +102,45 @@ async function waitForOpen(socket, url) {
|
|
|
77
102
|
)
|
|
78
103
|
);
|
|
79
104
|
};
|
|
105
|
+
const timer = timeoutMs === void 0 ? void 0 : setTimeout(() => {
|
|
106
|
+
if (settled) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
settled = true;
|
|
110
|
+
cleanup();
|
|
111
|
+
socket.on("error", () => {
|
|
112
|
+
});
|
|
113
|
+
try {
|
|
114
|
+
socket.terminate();
|
|
115
|
+
} catch {
|
|
116
|
+
}
|
|
117
|
+
reject(
|
|
118
|
+
new CfInspectorError(
|
|
119
|
+
"INSPECTOR_CONNECTION_FAILED",
|
|
120
|
+
`WebSocket handshake to ${url} timed out after ${timeoutMs.toString()}ms`
|
|
121
|
+
)
|
|
122
|
+
);
|
|
123
|
+
}, timeoutMs);
|
|
80
124
|
socket.once("open", onOpen);
|
|
81
125
|
socket.once("error", onError);
|
|
82
126
|
});
|
|
83
127
|
}
|
|
84
|
-
function wrapListener(event, listener
|
|
128
|
+
function wrapListener(event, listener) {
|
|
85
129
|
if (event === "message") {
|
|
86
130
|
const wrapped2 = (data) => {
|
|
87
131
|
listener(data.toString("utf8"));
|
|
88
132
|
};
|
|
89
|
-
wrappers.set(listener, wrapped2);
|
|
90
133
|
return wrapped2;
|
|
91
134
|
}
|
|
92
135
|
if (event === "close") {
|
|
93
136
|
const wrapped2 = () => {
|
|
94
137
|
listener();
|
|
95
138
|
};
|
|
96
|
-
wrappers.set(listener, wrapped2);
|
|
97
139
|
return wrapped2;
|
|
98
140
|
}
|
|
99
141
|
const wrapped = (err) => {
|
|
100
142
|
listener(err);
|
|
101
143
|
};
|
|
102
|
-
wrappers.set(listener, wrapped);
|
|
103
144
|
return wrapped;
|
|
104
145
|
}
|
|
105
146
|
var init_wsTransport = __esm({
|
|
@@ -212,9 +253,11 @@ function normalizeRegexRootPattern(pattern) {
|
|
|
212
253
|
const withoutEndAnchor = withoutStartAnchor.endsWith("$") && !isEscaped(withoutStartAnchor, withoutStartAnchor.length - 1) ? withoutStartAnchor.slice(0, -1) : withoutStartAnchor;
|
|
213
254
|
return stripTrailingSlash(withoutEndAnchor);
|
|
214
255
|
}
|
|
215
|
-
function buildFileUrlRegex(
|
|
216
|
-
|
|
217
|
-
|
|
256
|
+
function buildFileUrlRegex(embeddedRoot, tail, separator) {
|
|
257
|
+
return `^file://${embeddedRoot}${separator}${tail}$`;
|
|
258
|
+
}
|
|
259
|
+
function rootSeparator(rawPattern) {
|
|
260
|
+
return rawPattern.endsWith("/") ? "" : "/";
|
|
218
261
|
}
|
|
219
262
|
function escapeRegExp(value) {
|
|
220
263
|
return value.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
|
|
@@ -241,12 +284,12 @@ function buildBreakpointUrlRegex(input) {
|
|
|
241
284
|
return `(?:^|/)${tail}$`;
|
|
242
285
|
}
|
|
243
286
|
case "literal": {
|
|
244
|
-
const
|
|
245
|
-
return buildFileUrlRegex(
|
|
287
|
+
const root = input.remoteRoot.value;
|
|
288
|
+
return buildFileUrlRegex(escapeRegExp(root), tail, rootSeparator(root));
|
|
246
289
|
}
|
|
247
290
|
case "regex": {
|
|
248
|
-
const
|
|
249
|
-
return buildFileUrlRegex(
|
|
291
|
+
const root = normalizeRegexRootPattern(input.remoteRoot.pattern);
|
|
292
|
+
return buildFileUrlRegex(`(?:${root})`, tail, rootSeparator(root));
|
|
250
293
|
}
|
|
251
294
|
}
|
|
252
295
|
}
|
|
@@ -757,10 +800,19 @@ var CdpClient = class _CdpClient {
|
|
|
757
800
|
return;
|
|
758
801
|
}
|
|
759
802
|
if (typeof parsed.method === "string") {
|
|
760
|
-
this.
|
|
761
|
-
this.
|
|
803
|
+
this.safeEmit(parsed.method, parsed.params);
|
|
804
|
+
this.safeEmit("event", { method: parsed.method, params: parsed.params });
|
|
762
805
|
}
|
|
763
806
|
};
|
|
807
|
+
safeEmit(event, payload) {
|
|
808
|
+
const listeners = this.emitter.listeners(event);
|
|
809
|
+
for (const listener of listeners) {
|
|
810
|
+
try {
|
|
811
|
+
listener(payload);
|
|
812
|
+
} catch {
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
}
|
|
764
816
|
handleClose = () => {
|
|
765
817
|
this.markClosed(new CfInspectorError("INSPECTOR_CONNECTION_FAILED", "Inspector connection closed"));
|
|
766
818
|
};
|
|
@@ -778,7 +830,8 @@ var CdpClient = class _CdpClient {
|
|
|
778
830
|
}
|
|
779
831
|
static async connect(options) {
|
|
780
832
|
const factory = options.transportFactory ?? await loadDefaultFactory();
|
|
781
|
-
const
|
|
833
|
+
const factoryOptions = options.connectTimeoutMs === void 0 ? {} : { connectTimeoutMs: options.connectTimeoutMs };
|
|
834
|
+
const transport = await factory(options.url, factoryOptions);
|
|
782
835
|
return new _CdpClient(transport, options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS);
|
|
783
836
|
}
|
|
784
837
|
async send(method, params = {}) {
|
|
@@ -828,8 +881,16 @@ var CdpClient = class _CdpClient {
|
|
|
828
881
|
return;
|
|
829
882
|
}
|
|
830
883
|
const params = raw;
|
|
831
|
-
if (options.predicate
|
|
832
|
-
|
|
884
|
+
if (options.predicate) {
|
|
885
|
+
let accepted;
|
|
886
|
+
try {
|
|
887
|
+
accepted = options.predicate(params);
|
|
888
|
+
} catch {
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
if (!accepted) {
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
833
894
|
}
|
|
834
895
|
finish(params);
|
|
835
896
|
});
|
|
@@ -959,7 +1020,18 @@ async function connectInspector(options) {
|
|
|
959
1020
|
`No inspector targets available on ${host}:${options.port.toString()}`
|
|
960
1021
|
);
|
|
961
1022
|
}
|
|
962
|
-
const client = await CdpClient.connect({
|
|
1023
|
+
const client = await CdpClient.connect({
|
|
1024
|
+
url: target.webSocketDebuggerUrl,
|
|
1025
|
+
connectTimeoutMs
|
|
1026
|
+
});
|
|
1027
|
+
try {
|
|
1028
|
+
return await initSession(client, target);
|
|
1029
|
+
} catch (err) {
|
|
1030
|
+
client.dispose();
|
|
1031
|
+
throw err;
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
async function initSession(client, target) {
|
|
963
1035
|
const scripts = /* @__PURE__ */ new Map();
|
|
964
1036
|
client.on("Debugger.scriptParsed", (raw) => {
|
|
965
1037
|
const params = raw;
|
|
@@ -1080,19 +1152,32 @@ function scalarFromVariable(variable) {
|
|
|
1080
1152
|
}
|
|
1081
1153
|
return value === "null" ? null : value;
|
|
1082
1154
|
}
|
|
1155
|
+
function isArrayLikeChildren(children) {
|
|
1156
|
+
let hasNumeric = false;
|
|
1157
|
+
for (const child of children) {
|
|
1158
|
+
if (child.name === "length") {
|
|
1159
|
+
continue;
|
|
1160
|
+
}
|
|
1161
|
+
if (parseNumericIndex(child.name) === void 0) {
|
|
1162
|
+
return false;
|
|
1163
|
+
}
|
|
1164
|
+
hasNumeric = true;
|
|
1165
|
+
}
|
|
1166
|
+
return hasNumeric;
|
|
1167
|
+
}
|
|
1083
1168
|
function toStructuredValue(variable) {
|
|
1084
1169
|
const children = variable.children;
|
|
1085
1170
|
if (children === void 0 || children.length === 0) {
|
|
1086
1171
|
return scalarFromVariable(variable);
|
|
1087
1172
|
}
|
|
1088
|
-
|
|
1089
|
-
const
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1173
|
+
if (isArrayLikeChildren(children)) {
|
|
1174
|
+
const indexed = children.flatMap((child) => {
|
|
1175
|
+
const index = parseNumericIndex(child.name);
|
|
1176
|
+
if (index === void 0) {
|
|
1177
|
+
return [];
|
|
1178
|
+
}
|
|
1179
|
+
return [[index, toStructuredValue(child)]];
|
|
1180
|
+
});
|
|
1096
1181
|
const maxIndex = Math.max(...indexed.map(([index]) => index));
|
|
1097
1182
|
const out2 = Array.from({ length: maxIndex + 1 }, () => null);
|
|
1098
1183
|
for (const [index, entry] of indexed) {
|
|
@@ -1694,7 +1779,10 @@ async function streamLogpoint(session, options) {
|
|
|
1694
1779
|
return;
|
|
1695
1780
|
}
|
|
1696
1781
|
emitted += 1;
|
|
1697
|
-
|
|
1782
|
+
try {
|
|
1783
|
+
options.onEvent(event);
|
|
1784
|
+
} catch {
|
|
1785
|
+
}
|
|
1698
1786
|
if (maxEvents !== void 0 && emitted >= maxEvents) {
|
|
1699
1787
|
maxEventsReached = true;
|
|
1700
1788
|
stopMaxEvents?.();
|