ugly-app 0.1.719 → 0.1.720
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/version.d.ts +1 -1
- package/dist/cli/version.js +1 -1
- package/dist/inspect/index.d.ts +1 -0
- package/dist/inspect/index.d.ts.map +1 -1
- package/dist/inspect/index.js +1 -0
- package/dist/inspect/index.js.map +1 -1
- package/dist/inspect/proxyHostBootstrap.d.ts +21 -0
- package/dist/inspect/proxyHostBootstrap.d.ts.map +1 -0
- package/dist/inspect/proxyHostBootstrap.js +36 -0
- package/dist/inspect/proxyHostBootstrap.js.map +1 -0
- package/package.json +1 -1
- package/src/cli/version.ts +1 -1
- package/src/inspect/index.ts +5 -0
- package/src/inspect/proxyHostBootstrap.test.ts +91 -0
- package/src/inspect/proxyHostBootstrap.ts +58 -0
package/dist/cli/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const CLI_VERSION = "0.1.
|
|
1
|
+
export declare const CLI_VERSION = "0.1.720";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/cli/version.js
CHANGED
package/dist/inspect/index.d.ts
CHANGED
|
@@ -4,4 +4,5 @@ export { createInspectAgent, installInspectAgent } from './agent/install.js';
|
|
|
4
4
|
export { InspectClient, type InspectTransport } from './client.js';
|
|
5
5
|
export { buildTarget, dispatchToAgent, HOST_ONLY_CHANNELS } from './dispatch.js';
|
|
6
6
|
export { createSelfInspectHost, SELF_TARGET_ID, type SelfInspectHost, type SelfInspectHostOpts, } from './selfHost.js';
|
|
7
|
+
export { installInspectProxyHost, type InspectProxyHost, type InspectProxyHostOpts, } from './proxyHostBootstrap.js';
|
|
7
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/inspect/index.ts"],"names":[],"mappings":"AAIA,cAAc,eAAe,CAAC;AAC9B,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACjF,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,KAAK,eAAe,EACpB,KAAK,mBAAmB,GACzB,MAAM,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/inspect/index.ts"],"names":[],"mappings":"AAIA,cAAc,eAAe,CAAC;AAC9B,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACjF,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,KAAK,eAAe,EACpB,KAAK,mBAAmB,GACzB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,uBAAuB,EACvB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,GAC1B,MAAM,yBAAyB,CAAC"}
|
package/dist/inspect/index.js
CHANGED
|
@@ -6,4 +6,5 @@ export { createInspectAgent, installInspectAgent } from './agent/install.js';
|
|
|
6
6
|
export { InspectClient } from './client.js';
|
|
7
7
|
export { buildTarget, dispatchToAgent, HOST_ONLY_CHANNELS } from './dispatch.js';
|
|
8
8
|
export { createSelfInspectHost, SELF_TARGET_ID, } from './selfHost.js';
|
|
9
|
+
export { installInspectProxyHost, } from './proxyHostBootstrap.js';
|
|
9
10
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/inspect/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,6EAA6E;AAC7E,+EAA+E;AAE/E,cAAc,eAAe,CAAC;AAE9B,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAyB,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACjF,OAAO,EACL,qBAAqB,EACrB,cAAc,GAGf,MAAM,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/inspect/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,6EAA6E;AAC7E,+EAA+E;AAE/E,cAAc,eAAe,CAAC;AAE9B,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAyB,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACjF,OAAO,EACL,qBAAqB,EACrB,cAAc,GAGf,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,uBAAuB,GAGxB,MAAM,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ProxySocket } from '../native/proxyClient.js';
|
|
2
|
+
import type { ProxySigner } from '../native/proxyCrypto.js';
|
|
3
|
+
import type { InspectPlatform, Screenshot, ScreenshotRequest } from './protocol.js';
|
|
4
|
+
export interface InspectProxyHostOpts {
|
|
5
|
+
/** App Socket registered as a host (isHost:true in its presence getUrlParams). */
|
|
6
|
+
socket: ProxySocket;
|
|
7
|
+
/** Verify the inspector's offer + sign our answer (MSK-bound). nativeSigner on mobile. */
|
|
8
|
+
signer?: ProxySigner;
|
|
9
|
+
platform: InspectPlatform;
|
|
10
|
+
/** Native screenshot delegate (WKWebView.takeSnapshot / Android PixelCopy via capture.screenshot). */
|
|
11
|
+
screenshot?: (req: ScreenshotRequest) => Promise<Screenshot>;
|
|
12
|
+
iceServers?: RTCIceServer[];
|
|
13
|
+
rtcFactory?: (config: RTCConfiguration) => RTCPeerConnection;
|
|
14
|
+
}
|
|
15
|
+
export interface InspectProxyHost {
|
|
16
|
+
stop(): void;
|
|
17
|
+
/** Connected inspector count. */
|
|
18
|
+
peerCount(): number;
|
|
19
|
+
}
|
|
20
|
+
export declare function installInspectProxyHost(opts: InspectProxyHostOpts): InspectProxyHost;
|
|
21
|
+
//# sourceMappingURL=proxyHostBootstrap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxyHostBootstrap.d.ts","sourceRoot":"","sources":["../../src/inspect/proxyHostBootstrap.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEpF,MAAM,WAAW,oBAAoB;IACnC,kFAAkF;IAClF,MAAM,EAAE,WAAW,CAAC;IACpB,0FAA0F;IAC1F,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,QAAQ,EAAE,eAAe,CAAC;IAC1B,sGAAsG;IACtG,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IAC7D,UAAU,CAAC,EAAE,YAAY,EAAE,CAAC;IAC5B,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,iBAAiB,CAAC;CAC9D;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,IAAI,IAAI,CAAC;IACb,iCAAiC;IACjC,SAAS,IAAI,MAAM,CAAC;CACrB;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,oBAAoB,GAAG,gBAAgB,CAuBpF"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// One-call mobile inspect host: combines the browser proxy HOST (answerer) with
|
|
2
|
+
// the single-page self inspect host, so a remote desktop inspector can connect
|
|
3
|
+
// to this SPA and drive inspect.* against its own page. This is the SPA-side
|
|
4
|
+
// counterpart to the desktop's electron/inspect/inspect-remote.ts client.
|
|
5
|
+
//
|
|
6
|
+
// The caller supplies an app Socket already registered as a host (isHost in its
|
|
7
|
+
// getUrlParams presence), a signer (nativeSigner(native) — MSK in secure
|
|
8
|
+
// storage), and a native screenshot delegate (capture.screenshot). Live
|
|
9
|
+
// console/network/picked events fan out to subscribed inspectors via broadcast.
|
|
10
|
+
import { createProxyHost } from '../native/proxyHost.js';
|
|
11
|
+
import { createSelfInspectHost } from './selfHost.js';
|
|
12
|
+
export function installInspectProxyHost(opts) {
|
|
13
|
+
// Holder so the self-host's onEvent closure can reach the host created after it.
|
|
14
|
+
const ref = {};
|
|
15
|
+
const self = createSelfInspectHost({
|
|
16
|
+
platform: opts.platform,
|
|
17
|
+
screenshot: opts.screenshot,
|
|
18
|
+
// Live agent events → evt frames to every subscribed inspector.
|
|
19
|
+
onEvent: (event, data) => ref.host?.broadcast(event, data),
|
|
20
|
+
});
|
|
21
|
+
ref.host = createProxyHost({
|
|
22
|
+
socket: opts.socket,
|
|
23
|
+
signer: opts.signer,
|
|
24
|
+
iceServers: opts.iceServers,
|
|
25
|
+
rtcFactory: opts.rtcFactory,
|
|
26
|
+
onInvoke: (channel, payload) => self.dispatch(channel, (payload ?? {})),
|
|
27
|
+
});
|
|
28
|
+
return {
|
|
29
|
+
stop() {
|
|
30
|
+
ref.host?.stop();
|
|
31
|
+
self.stop();
|
|
32
|
+
},
|
|
33
|
+
peerCount: () => ref.host?.peerCount() ?? 0,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=proxyHostBootstrap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxyHostBootstrap.js","sourceRoot":"","sources":["../../src/inspect/proxyHostBootstrap.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,+EAA+E;AAC/E,6EAA6E;AAC7E,0EAA0E;AAC1E,EAAE;AACF,gFAAgF;AAChF,yEAAyE;AACzE,wEAAwE;AACxE,gFAAgF;AAEhF,OAAO,EAAE,eAAe,EAAkB,MAAM,wBAAwB,CAAC;AAGzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAqBtD,MAAM,UAAU,uBAAuB,CAAC,IAA0B;IAChE,iFAAiF;IACjF,MAAM,GAAG,GAAyB,EAAE,CAAC;IACrC,MAAM,IAAI,GAAG,qBAAqB,CAAC;QACjC,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,gEAAgE;QAChE,OAAO,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC;KAC3D,CAAC,CAAC;IACH,GAAG,CAAC,IAAI,GAAG,eAAe,CAAC;QACzB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,OAAO,IAAI,EAAE,CAA4B,CAAC;KACnG,CAAC,CAAC;IACH,OAAO;QACL,IAAI;YACF,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;YACjB,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,CAAC;QACD,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC;KAC5C,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ugly-app",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.720",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"comment:files": "Allowlist what ships to npm. dist = runtime; src = sourcemap targets (dist/*.js.map reference ../../src/); templates = CLI scaffold. Everything else at repo root (.pgdata local Postgres, coverage, assets/icons sources, test/, test-results/) is excluded by omission. The !negations strip the scaffold's installed deps + cruft (templates/node_modules is 200MB+ and must never ship). package.json/README/LICENSE ship automatically.",
|
|
6
6
|
"files": [
|
package/src/cli/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Auto-generated by prebuild — do not edit manually
|
|
2
|
-
export const CLI_VERSION = "0.1.
|
|
2
|
+
export const CLI_VERSION = "0.1.720";
|
package/src/inspect/index.ts
CHANGED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { installInspectProxyHost } from './proxyHostBootstrap.js';
|
|
4
|
+
import type { ProxySocket } from '../native/proxyClient.js';
|
|
5
|
+
|
|
6
|
+
afterEach(() => {
|
|
7
|
+
delete (window as { __uglyInspectAgent?: unknown }).__uglyInspectAgent;
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
function fakeSocket() {
|
|
11
|
+
const handlers = new Map<string, (d: unknown) => void>();
|
|
12
|
+
const emits: { type: string; data: Record<string, unknown> }[] = [];
|
|
13
|
+
const socket: ProxySocket = {
|
|
14
|
+
emit: (type, data) => emits.push({ type, data: data as Record<string, unknown> }),
|
|
15
|
+
on: (event, handler) => {
|
|
16
|
+
handlers.set(event, handler);
|
|
17
|
+
return () => handlers.delete(event);
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
return { socket, emits, fire: (event: string, d: unknown) => handlers.get(event)?.(d) };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function fakeChannel() {
|
|
24
|
+
const sent: string[] = [];
|
|
25
|
+
const ch = { readyState: 'open', send: (s: string) => sent.push(s), onmessage: null as null | ((e: { data: unknown }) => void) };
|
|
26
|
+
return { ch, sent, push: (frame: object) => ch.onmessage?.({ data: JSON.stringify(frame) }) };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function fakeRtc() {
|
|
30
|
+
const pc: Record<string, unknown> = {
|
|
31
|
+
onicecandidate: null,
|
|
32
|
+
ondatachannel: null,
|
|
33
|
+
setRemoteDescription: vi.fn(async () => {}),
|
|
34
|
+
createAnswer: vi.fn(async () => ({ type: 'answer', sdp: 'a\na=fingerprint:sha-256 AA' })),
|
|
35
|
+
setLocalDescription: vi.fn(async () => {}),
|
|
36
|
+
localDescription: { sdp: 'a\na=fingerprint:sha-256 AA' },
|
|
37
|
+
addIceCandidate: vi.fn(async () => {}),
|
|
38
|
+
close: vi.fn(),
|
|
39
|
+
};
|
|
40
|
+
return { pc, factory: () => pc as unknown as RTCPeerConnection };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const signer = { sign: vi.fn(async () => 'sig'), verify: vi.fn(async () => true) };
|
|
44
|
+
|
|
45
|
+
describe('installInspectProxyHost (mobile SPA inspect host)', () => {
|
|
46
|
+
it('routes a tunneled inspect.eval through the self-host to the in-page agent', async () => {
|
|
47
|
+
const { socket, fire } = fakeSocket();
|
|
48
|
+
const { pc, factory } = fakeRtc();
|
|
49
|
+
const handle = installInspectProxyHost({ socket, signer, platform: 'ios', rtcFactory: factory });
|
|
50
|
+
|
|
51
|
+
await fire('rtc:offer', { from: 'desktop', sdp: 's\na=fingerprint:sha-256 CC', fpTag: 'good', origin: 'https://studio' });
|
|
52
|
+
await new Promise((r) => setTimeout(r, 0));
|
|
53
|
+
|
|
54
|
+
const { ch, sent, push } = fakeChannel();
|
|
55
|
+
(pc.ondatachannel as (e: { channel: unknown }) => void)({ channel: ch });
|
|
56
|
+
|
|
57
|
+
// listTargets → the single self target on iOS
|
|
58
|
+
push({ t: 'req', id: '1', channel: 'inspect.listTargets', payload: {} });
|
|
59
|
+
await new Promise((r) => setTimeout(r, 0));
|
|
60
|
+
const targetsRes = JSON.parse(sent[0]);
|
|
61
|
+
expect(targetsRes).toMatchObject({ t: 'res', id: '1', ok: true });
|
|
62
|
+
expect(targetsRes.result.targets[0].platform).toBe('ios');
|
|
63
|
+
|
|
64
|
+
// eval → runs in the page agent
|
|
65
|
+
push({ t: 'req', id: '2', channel: 'inspect.eval', payload: { expression: '9 * 9' } });
|
|
66
|
+
await new Promise((r) => setTimeout(r, 0));
|
|
67
|
+
const evalRes = JSON.parse(sent[1]);
|
|
68
|
+
expect(evalRes.result.ok).toBe(true);
|
|
69
|
+
expect(evalRes.result.value.value).toBe(81);
|
|
70
|
+
|
|
71
|
+
expect(handle.peerCount()).toBe(1);
|
|
72
|
+
handle.stop();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('delegates screenshots to the native capture callback', async () => {
|
|
76
|
+
const { socket, fire } = fakeSocket();
|
|
77
|
+
const { pc, factory } = fakeRtc();
|
|
78
|
+
const screenshot = vi.fn(async () => ({ base64: 'PNG', width: 390, height: 844, dpr: 3, format: 'png' as const }));
|
|
79
|
+
installInspectProxyHost({ socket, signer, platform: 'ios', rtcFactory: factory, screenshot });
|
|
80
|
+
|
|
81
|
+
await fire('rtc:offer', { from: 'd', sdp: 's', fpTag: 'good', origin: '' });
|
|
82
|
+
await new Promise((r) => setTimeout(r, 0));
|
|
83
|
+
const { ch, sent, push } = fakeChannel();
|
|
84
|
+
(pc.ondatachannel as (e: { channel: unknown }) => void)({ channel: ch });
|
|
85
|
+
|
|
86
|
+
push({ t: 'req', id: '5', channel: 'inspect.screenshot', payload: { fullPage: false } });
|
|
87
|
+
await new Promise((r) => setTimeout(r, 0));
|
|
88
|
+
expect(screenshot).toHaveBeenCalled();
|
|
89
|
+
expect(JSON.parse(sent[0]).result.base64).toBe('PNG');
|
|
90
|
+
});
|
|
91
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// One-call mobile inspect host: combines the browser proxy HOST (answerer) with
|
|
2
|
+
// the single-page self inspect host, so a remote desktop inspector can connect
|
|
3
|
+
// to this SPA and drive inspect.* against its own page. This is the SPA-side
|
|
4
|
+
// counterpart to the desktop's electron/inspect/inspect-remote.ts client.
|
|
5
|
+
//
|
|
6
|
+
// The caller supplies an app Socket already registered as a host (isHost in its
|
|
7
|
+
// getUrlParams presence), a signer (nativeSigner(native) — MSK in secure
|
|
8
|
+
// storage), and a native screenshot delegate (capture.screenshot). Live
|
|
9
|
+
// console/network/picked events fan out to subscribed inspectors via broadcast.
|
|
10
|
+
|
|
11
|
+
import { createProxyHost, type ProxyHost } from '../native/proxyHost.js';
|
|
12
|
+
import type { ProxySocket } from '../native/proxyClient.js';
|
|
13
|
+
import type { ProxySigner } from '../native/proxyCrypto.js';
|
|
14
|
+
import { createSelfInspectHost } from './selfHost.js';
|
|
15
|
+
import type { InspectPlatform, Screenshot, ScreenshotRequest } from './protocol.js';
|
|
16
|
+
|
|
17
|
+
export interface InspectProxyHostOpts {
|
|
18
|
+
/** App Socket registered as a host (isHost:true in its presence getUrlParams). */
|
|
19
|
+
socket: ProxySocket;
|
|
20
|
+
/** Verify the inspector's offer + sign our answer (MSK-bound). nativeSigner on mobile. */
|
|
21
|
+
signer?: ProxySigner;
|
|
22
|
+
platform: InspectPlatform;
|
|
23
|
+
/** Native screenshot delegate (WKWebView.takeSnapshot / Android PixelCopy via capture.screenshot). */
|
|
24
|
+
screenshot?: (req: ScreenshotRequest) => Promise<Screenshot>;
|
|
25
|
+
iceServers?: RTCIceServer[];
|
|
26
|
+
rtcFactory?: (config: RTCConfiguration) => RTCPeerConnection;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface InspectProxyHost {
|
|
30
|
+
stop(): void;
|
|
31
|
+
/** Connected inspector count. */
|
|
32
|
+
peerCount(): number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function installInspectProxyHost(opts: InspectProxyHostOpts): InspectProxyHost {
|
|
36
|
+
// Holder so the self-host's onEvent closure can reach the host created after it.
|
|
37
|
+
const ref: { host?: ProxyHost } = {};
|
|
38
|
+
const self = createSelfInspectHost({
|
|
39
|
+
platform: opts.platform,
|
|
40
|
+
screenshot: opts.screenshot,
|
|
41
|
+
// Live agent events → evt frames to every subscribed inspector.
|
|
42
|
+
onEvent: (event, data) => ref.host?.broadcast(event, data),
|
|
43
|
+
});
|
|
44
|
+
ref.host = createProxyHost({
|
|
45
|
+
socket: opts.socket,
|
|
46
|
+
signer: opts.signer,
|
|
47
|
+
iceServers: opts.iceServers,
|
|
48
|
+
rtcFactory: opts.rtcFactory,
|
|
49
|
+
onInvoke: (channel, payload) => self.dispatch(channel, (payload ?? {}) as Record<string, unknown>),
|
|
50
|
+
});
|
|
51
|
+
return {
|
|
52
|
+
stop(): void {
|
|
53
|
+
ref.host?.stop();
|
|
54
|
+
self.stop();
|
|
55
|
+
},
|
|
56
|
+
peerCount: () => ref.host?.peerCount() ?? 0,
|
|
57
|
+
};
|
|
58
|
+
}
|