@react-native-harness/bridge 1.5.0 → 1.7.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/dist/app-liveness.d.ts +33 -0
- package/dist/app-liveness.d.ts.map +1 -0
- package/dist/app-liveness.js +57 -0
- package/dist/binary.d.ts +16 -0
- package/dist/binary.d.ts.map +1 -0
- package/dist/binary.js +47 -0
- package/dist/client.d.ts +6 -4
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +112 -105
- package/dist/connection-check.d.ts +22 -0
- package/dist/connection-check.d.ts.map +1 -0
- package/dist/connection-check.js +30 -0
- package/dist/errors.d.ts +6 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +12 -4
- package/dist/image-snapshot.d.ts +2 -2
- package/dist/image-snapshot.d.ts.map +1 -1
- package/dist/image-snapshot.js +21 -8
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -2
- package/dist/js-block-budget-policy.d.ts +31 -0
- package/dist/js-block-budget-policy.d.ts.map +1 -0
- package/dist/js-block-budget-policy.js +60 -0
- package/dist/js-watchdog.d.ts +31 -0
- package/dist/js-watchdog.d.ts.map +1 -0
- package/dist/js-watchdog.js +46 -0
- package/dist/link/channel.d.ts +45 -0
- package/dist/link/channel.d.ts.map +1 -0
- package/dist/link/channel.js +414 -0
- package/dist/link/envelope.d.ts +38 -0
- package/dist/link/envelope.d.ts.map +1 -0
- package/dist/link/envelope.js +90 -0
- package/dist/link/index.d.ts +22 -0
- package/dist/link/index.d.ts.map +1 -0
- package/dist/link/index.js +271 -0
- package/dist/link/ports.d.ts +31 -0
- package/dist/link/ports.d.ts.map +1 -0
- package/dist/link/ports.js +7 -0
- package/dist/link/scheduler.d.ts +21 -0
- package/dist/link/scheduler.d.ts.map +1 -0
- package/dist/link/scheduler.js +116 -0
- package/dist/link/standard-websocket.d.ts +36 -0
- package/dist/link/standard-websocket.d.ts.map +1 -0
- package/dist/link/standard-websocket.js +214 -0
- package/dist/link/streams.d.ts +4 -0
- package/dist/link/streams.d.ts.map +1 -0
- package/dist/link/streams.js +15 -0
- package/dist/protocol.d.ts +10 -5
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +2 -2
- package/dist/rpc-peer.d.ts +3 -1
- package/dist/rpc-peer.d.ts.map +1 -1
- package/dist/rpc-peer.js +2 -2
- package/dist/server.d.ts +4 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +71 -56
- package/dist/shared/test-runner.d.ts +11 -0
- package/dist/shared/test-runner.d.ts.map +1 -1
- package/dist/shared.d.ts +5 -1
- package/dist/shared.d.ts.map +1 -1
- package/package.json +4 -3
- package/src/app-liveness.ts +103 -0
- package/src/binary.ts +74 -0
- package/src/client.ts +172 -170
- package/src/connection-check.ts +60 -0
- package/src/errors.ts +16 -5
- package/src/image-snapshot.ts +31 -9
- package/src/index.ts +0 -2
- package/src/js-block-budget-policy.ts +90 -0
- package/src/js-watchdog.ts +78 -0
- package/src/link/README.md +43 -0
- package/src/link/channel.ts +473 -0
- package/src/link/envelope.ts +110 -0
- package/src/link/index.ts +321 -0
- package/src/link/ports.ts +42 -0
- package/src/link/scheduler.ts +132 -0
- package/src/link/standard-websocket.ts +251 -0
- package/src/link/streams.ts +34 -0
- package/src/protocol.ts +14 -9
- package/src/rpc-peer.ts +6 -3
- package/src/server.ts +99 -67
- package/src/shared/test-runner.ts +12 -0
- package/src/shared.ts +6 -1
- package/dist/binary-transfer.d.ts +0 -17
- package/dist/binary-transfer.d.ts.map +0 -1
- package/dist/binary-transfer.js +0 -60
- package/dist/heartbeat.d.ts +0 -13
- package/dist/heartbeat.d.ts.map +0 -1
- package/dist/heartbeat.js +0 -49
- package/dist/transport.d.ts +0 -22
- package/dist/transport.d.ts.map +0 -1
- package/dist/transport.js +0 -22
- package/dist/websocket-client-transport.d.ts +0 -3
- package/dist/websocket-client-transport.d.ts.map +0 -1
- package/dist/websocket-client-transport.js +0 -45
- package/dist/websocket-server-transport.d.ts +0 -4
- package/dist/websocket-server-transport.d.ts.map +0 -1
- package/dist/websocket-server-transport.js +0 -43
- package/src/binary-transfer.ts +0 -79
- package/src/heartbeat.ts +0 -67
- package/src/transport.ts +0 -47
- package/src/websocket-client-transport.ts +0 -85
- package/src/websocket-server-transport.ts +0 -54
package/src/shared.ts
CHANGED
|
@@ -148,7 +148,8 @@ export type BridgeClientFunctions = {
|
|
|
148
148
|
|
|
149
149
|
export type BinaryDataReference = {
|
|
150
150
|
type: 'binary';
|
|
151
|
-
|
|
151
|
+
/** The link channel carrying the bytes. */
|
|
152
|
+
channelId: string;
|
|
152
153
|
size: number;
|
|
153
154
|
mimeType: 'image/png';
|
|
154
155
|
};
|
|
@@ -168,6 +169,10 @@ export type BridgeServerFunctions = {
|
|
|
168
169
|
) => Promise<{ pass: boolean; message: string }>;
|
|
169
170
|
};
|
|
170
171
|
|
|
172
|
+
export type SnapshotUpdateState = 'all' | 'new' | 'none';
|
|
173
|
+
|
|
171
174
|
export type HarnessContext = {
|
|
172
175
|
platform: HarnessPlatform;
|
|
176
|
+
/** Jest's snapshot update state; when absent, a missing image snapshot is written. */
|
|
177
|
+
updateSnapshot?: SnapshotUpdateState;
|
|
173
178
|
};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export declare const HEADER_SIZE = 8;
|
|
2
|
-
export declare function createBinaryFrame(transferId: number, data: Uint8Array): Uint8Array;
|
|
3
|
-
export declare function parseBinaryFrame(frame: Uint8Array): {
|
|
4
|
-
transferId: number;
|
|
5
|
-
data: Uint8Array;
|
|
6
|
-
};
|
|
7
|
-
export declare class BinaryStore {
|
|
8
|
-
private store;
|
|
9
|
-
private timeouts;
|
|
10
|
-
private readonly TIMEOUT_MS;
|
|
11
|
-
add(transferId: number, data: Uint8Array): void;
|
|
12
|
-
get(transferId: number): Uint8Array | undefined;
|
|
13
|
-
delete(transferId: number): boolean;
|
|
14
|
-
dispose(): void;
|
|
15
|
-
}
|
|
16
|
-
export declare function generateTransferId(): number;
|
|
17
|
-
//# sourceMappingURL=binary-transfer.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"binary-transfer.d.ts","sourceRoot":"","sources":["../src/binary-transfer.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,IAAI,CAAC;AAE7B,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,UAAU,GACf,UAAU,CAcZ;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,UAAU,CAAC;CAClB,CAMA;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,KAAK,CAAiC;IAC9C,OAAO,CAAC,QAAQ,CAAoD;IAEpE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAiB;IAE5C,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI;IAS/C,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAI/C,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IASnC,OAAO,IAAI,IAAI;CAOhB;AAGD,wBAAgB,kBAAkB,IAAI,MAAM,CAQ3C"}
|
package/dist/binary-transfer.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
export const HEADER_SIZE = 8;
|
|
2
|
-
export function createBinaryFrame(transferId, data) {
|
|
3
|
-
const frame = new Uint8Array(HEADER_SIZE + data.length);
|
|
4
|
-
const view = new DataView(frame.buffer);
|
|
5
|
-
// Transfer ID (4 bytes, Big Endian)
|
|
6
|
-
view.setUint32(0, transferId, false);
|
|
7
|
-
// Reserved (4 bytes) - set to 0
|
|
8
|
-
view.setUint32(4, 0, false);
|
|
9
|
-
// Copy data
|
|
10
|
-
frame.set(data, HEADER_SIZE);
|
|
11
|
-
return frame;
|
|
12
|
-
}
|
|
13
|
-
export function parseBinaryFrame(frame) {
|
|
14
|
-
const view = new DataView(frame.buffer, frame.byteOffset, frame.byteLength);
|
|
15
|
-
const transferId = view.getUint32(0, false);
|
|
16
|
-
const data = frame.subarray(HEADER_SIZE);
|
|
17
|
-
return { transferId, data };
|
|
18
|
-
}
|
|
19
|
-
export class BinaryStore {
|
|
20
|
-
store = new Map();
|
|
21
|
-
timeouts = new Map();
|
|
22
|
-
// 5 minutes timeout for binary data
|
|
23
|
-
TIMEOUT_MS = 5 * 60 * 1000;
|
|
24
|
-
add(transferId, data) {
|
|
25
|
-
this.store.set(transferId, data);
|
|
26
|
-
const timeout = setTimeout(() => {
|
|
27
|
-
this.store.delete(transferId);
|
|
28
|
-
this.timeouts.delete(transferId);
|
|
29
|
-
}, this.TIMEOUT_MS);
|
|
30
|
-
this.timeouts.set(transferId, timeout);
|
|
31
|
-
}
|
|
32
|
-
get(transferId) {
|
|
33
|
-
return this.store.get(transferId);
|
|
34
|
-
}
|
|
35
|
-
delete(transferId) {
|
|
36
|
-
const timeout = this.timeouts.get(transferId);
|
|
37
|
-
if (timeout) {
|
|
38
|
-
clearTimeout(timeout);
|
|
39
|
-
this.timeouts.delete(transferId);
|
|
40
|
-
}
|
|
41
|
-
return this.store.delete(transferId);
|
|
42
|
-
}
|
|
43
|
-
dispose() {
|
|
44
|
-
for (const timeout of this.timeouts.values()) {
|
|
45
|
-
clearTimeout(timeout);
|
|
46
|
-
}
|
|
47
|
-
this.timeouts.clear();
|
|
48
|
-
this.store.clear();
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
let nextTransferId = 1;
|
|
52
|
-
export function generateTransferId() {
|
|
53
|
-
// Use a rolling counter, but ensure it doesn't overflow 32-bit integer just in case
|
|
54
|
-
// though JS numbers are doubles, we are writing to Uint32.
|
|
55
|
-
const id = nextTransferId++;
|
|
56
|
-
if (nextTransferId > 0xffffffff) {
|
|
57
|
-
nextTransferId = 1;
|
|
58
|
-
}
|
|
59
|
-
return id;
|
|
60
|
-
}
|
package/dist/heartbeat.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export declare const DEFAULT_HEARTBEAT_INTERVAL_MS = 5000;
|
|
2
|
-
export declare const DEFAULT_HEARTBEAT_TIMEOUT_MS = 20000;
|
|
3
|
-
export type BridgeHeartbeat = {
|
|
4
|
-
notifyPong: (id: number) => void;
|
|
5
|
-
dispose: () => void;
|
|
6
|
-
};
|
|
7
|
-
export declare const createHeartbeat: (options: {
|
|
8
|
-
sendPing: (id: number) => void;
|
|
9
|
-
onTimeout: () => void;
|
|
10
|
-
intervalMs?: number;
|
|
11
|
-
timeoutMs?: number;
|
|
12
|
-
}) => BridgeHeartbeat;
|
|
13
|
-
//# sourceMappingURL=heartbeat.d.ts.map
|
package/dist/heartbeat.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"heartbeat.d.ts","sourceRoot":"","sources":["../src/heartbeat.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,6BAA6B,OAAQ,CAAC;AACnD,eAAO,MAAM,4BAA4B,QAAS,CAAC;AAEnD,MAAM,MAAM,eAAe,GAAG;IAC5B,UAAU,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,SAAS;IACvC,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,KAAG,eAqDH,CAAC"}
|
package/dist/heartbeat.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
export const DEFAULT_HEARTBEAT_INTERVAL_MS = 5_000;
|
|
2
|
-
export const DEFAULT_HEARTBEAT_TIMEOUT_MS = 20_000;
|
|
3
|
-
export const createHeartbeat = (options) => {
|
|
4
|
-
const intervalMs = options.intervalMs ?? DEFAULT_HEARTBEAT_INTERVAL_MS;
|
|
5
|
-
const timeoutMs = options.timeoutMs ?? DEFAULT_HEARTBEAT_TIMEOUT_MS;
|
|
6
|
-
let nextPingId = 1;
|
|
7
|
-
let pendingPingId = null;
|
|
8
|
-
let disposed = false;
|
|
9
|
-
let timeoutHandle = null;
|
|
10
|
-
const clearPendingTimeout = () => {
|
|
11
|
-
if (timeoutHandle) {
|
|
12
|
-
clearTimeout(timeoutHandle);
|
|
13
|
-
timeoutHandle = null;
|
|
14
|
-
}
|
|
15
|
-
};
|
|
16
|
-
const intervalHandle = setInterval(() => {
|
|
17
|
-
if (disposed || pendingPingId !== null) {
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
const pingId = nextPingId++;
|
|
21
|
-
pendingPingId = pingId;
|
|
22
|
-
options.sendPing(pingId);
|
|
23
|
-
timeoutHandle = setTimeout(() => {
|
|
24
|
-
if (disposed || pendingPingId !== pingId) {
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
pendingPingId = null;
|
|
28
|
-
timeoutHandle = null;
|
|
29
|
-
options.onTimeout();
|
|
30
|
-
}, timeoutMs);
|
|
31
|
-
}, intervalMs);
|
|
32
|
-
return {
|
|
33
|
-
notifyPong: (id) => {
|
|
34
|
-
if (id !== pendingPingId) {
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
pendingPingId = null;
|
|
38
|
-
clearPendingTimeout();
|
|
39
|
-
},
|
|
40
|
-
dispose: () => {
|
|
41
|
-
if (disposed) {
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
disposed = true;
|
|
45
|
-
clearInterval(intervalHandle);
|
|
46
|
-
clearPendingTimeout();
|
|
47
|
-
},
|
|
48
|
-
};
|
|
49
|
-
};
|
package/dist/transport.d.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
export type BridgeTransportState = 'connecting' | 'open' | 'closing' | 'closed';
|
|
2
|
-
export type BridgeTransportMessage = string | Uint8Array;
|
|
3
|
-
export type BridgeTransportCloseEvent = {
|
|
4
|
-
code: number;
|
|
5
|
-
reason: string;
|
|
6
|
-
};
|
|
7
|
-
export type BridgeTransport = {
|
|
8
|
-
readonly state: BridgeTransportState;
|
|
9
|
-
send: (message: BridgeTransportMessage) => void;
|
|
10
|
-
close: (code?: number, reason?: string) => void;
|
|
11
|
-
onOpen: (listener: () => void) => () => void;
|
|
12
|
-
onMessage: (listener: (message: BridgeTransportMessage) => void) => () => void;
|
|
13
|
-
onClose: (listener: (event: BridgeTransportCloseEvent) => void) => () => void;
|
|
14
|
-
onError: (listener: (error: Error) => void) => () => void;
|
|
15
|
-
};
|
|
16
|
-
export type RpcTransport = {
|
|
17
|
-
readonly state: BridgeTransportState;
|
|
18
|
-
send: (message: string) => void;
|
|
19
|
-
};
|
|
20
|
-
export declare const toTransportState: (readyState: number) => BridgeTransportState;
|
|
21
|
-
export declare const createRpcTransport: (transport: BridgeTransport) => RpcTransport;
|
|
22
|
-
//# sourceMappingURL=transport.d.ts.map
|
package/dist/transport.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,oBAAoB,GAAG,YAAY,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEhF,MAAM,MAAM,sBAAsB,GAAG,MAAM,GAAG,UAAU,CAAC;AAEzD,MAAM,MAAM,yBAAyB,GAAG;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,KAAK,EAAE,oBAAoB,CAAC;IACrC,IAAI,EAAE,CAAC,OAAO,EAAE,sBAAsB,KAAK,IAAI,CAAC;IAChD,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAC;IAC7C,SAAS,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,sBAAsB,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;IAC/E,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,yBAAyB,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;IAC9E,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;CAC3D,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,KAAK,EAAE,oBAAoB,CAAC;IACrC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,YAAY,MAAM,KAAG,oBAWrD,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,WAAW,eAAe,KAAG,YAS/D,CAAC"}
|
package/dist/transport.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
export const toTransportState = (readyState) => {
|
|
2
|
-
switch (readyState) {
|
|
3
|
-
case 0:
|
|
4
|
-
return 'connecting';
|
|
5
|
-
case 1:
|
|
6
|
-
return 'open';
|
|
7
|
-
case 2:
|
|
8
|
-
return 'closing';
|
|
9
|
-
default:
|
|
10
|
-
return 'closed';
|
|
11
|
-
}
|
|
12
|
-
};
|
|
13
|
-
export const createRpcTransport = (transport) => {
|
|
14
|
-
return {
|
|
15
|
-
get state() {
|
|
16
|
-
return transport.state;
|
|
17
|
-
},
|
|
18
|
-
send: (message) => {
|
|
19
|
-
transport.send(message);
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"websocket-client-transport.d.ts","sourceRoot":"","sources":["../src/websocket-client-transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,gBAAgB,CAAC;AAiCxB,eAAO,MAAM,8BAA8B,GAAI,KAAK,MAAM,KAAG,eAgD5D,CAAC"}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { toTransportState, } from './transport.js';
|
|
2
|
-
export const createWebSocketClientTransport = (url) => {
|
|
3
|
-
const socket = new WebSocket(url);
|
|
4
|
-
socket.binaryType = 'arraybuffer';
|
|
5
|
-
return {
|
|
6
|
-
get state() {
|
|
7
|
-
return toTransportState(socket.readyState);
|
|
8
|
-
},
|
|
9
|
-
send: (message) => {
|
|
10
|
-
socket.send(message);
|
|
11
|
-
},
|
|
12
|
-
close: (code, reason) => {
|
|
13
|
-
socket.close(code, reason);
|
|
14
|
-
},
|
|
15
|
-
onOpen: (listener) => {
|
|
16
|
-
socket.addEventListener('open', listener);
|
|
17
|
-
return () => socket.removeEventListener('open', listener);
|
|
18
|
-
},
|
|
19
|
-
onMessage: (listener) => {
|
|
20
|
-
const handleMessage = (event) => {
|
|
21
|
-
if (typeof event.data === 'string') {
|
|
22
|
-
listener(event.data);
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
listener(new Uint8Array(event.data));
|
|
26
|
-
};
|
|
27
|
-
socket.addEventListener('message', handleMessage);
|
|
28
|
-
return () => socket.removeEventListener('message', handleMessage);
|
|
29
|
-
},
|
|
30
|
-
onClose: (listener) => {
|
|
31
|
-
const handleClose = (event) => {
|
|
32
|
-
listener({ code: event.code, reason: event.reason });
|
|
33
|
-
};
|
|
34
|
-
socket.addEventListener('close', handleClose);
|
|
35
|
-
return () => socket.removeEventListener('close', handleClose);
|
|
36
|
-
},
|
|
37
|
-
onError: (listener) => {
|
|
38
|
-
const handleError = (event) => {
|
|
39
|
-
listener(new Error(event.message || 'Harness connection error'));
|
|
40
|
-
};
|
|
41
|
-
socket.addEventListener('error', handleError);
|
|
42
|
-
return () => socket.removeEventListener('error', handleError);
|
|
43
|
-
},
|
|
44
|
-
};
|
|
45
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"websocket-server-transport.d.ts","sourceRoot":"","sources":["../src/websocket-server-transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,SAAS,IAAI,aAAa,EAAE,MAAM,IAAI,CAAC;AAC9D,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,gBAAgB,CAAC;AAYxB,eAAO,MAAM,4BAA4B,GACvC,QAAQ,aAAa,KACpB,eAmCF,CAAC"}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { toTransportState, } from './transport.js';
|
|
2
|
-
const toUint8Array = (message) => {
|
|
3
|
-
const buffer = Array.isArray(message)
|
|
4
|
-
? Buffer.concat(message)
|
|
5
|
-
: Buffer.isBuffer(message)
|
|
6
|
-
? message
|
|
7
|
-
: Buffer.from(message);
|
|
8
|
-
return new Uint8Array(buffer);
|
|
9
|
-
};
|
|
10
|
-
export const createNodeWebSocketTransport = (socket) => {
|
|
11
|
-
return {
|
|
12
|
-
get state() {
|
|
13
|
-
return toTransportState(socket.readyState);
|
|
14
|
-
},
|
|
15
|
-
send: (message) => {
|
|
16
|
-
socket.send(message);
|
|
17
|
-
},
|
|
18
|
-
close: (code, reason) => {
|
|
19
|
-
socket.close(code, reason);
|
|
20
|
-
},
|
|
21
|
-
onOpen: () => {
|
|
22
|
-
return () => undefined;
|
|
23
|
-
},
|
|
24
|
-
onMessage: (listener) => {
|
|
25
|
-
const handleMessage = (message, isBinary) => {
|
|
26
|
-
listener(isBinary ? toUint8Array(message) : message.toString());
|
|
27
|
-
};
|
|
28
|
-
socket.on('message', handleMessage);
|
|
29
|
-
return () => socket.off('message', handleMessage);
|
|
30
|
-
},
|
|
31
|
-
onClose: (listener) => {
|
|
32
|
-
const handleClose = (code, reason) => {
|
|
33
|
-
listener({ code, reason: reason.toString() });
|
|
34
|
-
};
|
|
35
|
-
socket.on('close', handleClose);
|
|
36
|
-
return () => socket.off('close', handleClose);
|
|
37
|
-
},
|
|
38
|
-
onError: (listener) => {
|
|
39
|
-
socket.on('error', listener);
|
|
40
|
-
return () => socket.off('error', listener);
|
|
41
|
-
},
|
|
42
|
-
};
|
|
43
|
-
};
|
package/src/binary-transfer.ts
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
export const HEADER_SIZE = 8;
|
|
2
|
-
|
|
3
|
-
export function createBinaryFrame(
|
|
4
|
-
transferId: number,
|
|
5
|
-
data: Uint8Array
|
|
6
|
-
): Uint8Array {
|
|
7
|
-
const frame = new Uint8Array(HEADER_SIZE + data.length);
|
|
8
|
-
const view = new DataView(frame.buffer);
|
|
9
|
-
|
|
10
|
-
// Transfer ID (4 bytes, Big Endian)
|
|
11
|
-
view.setUint32(0, transferId, false);
|
|
12
|
-
|
|
13
|
-
// Reserved (4 bytes) - set to 0
|
|
14
|
-
view.setUint32(4, 0, false);
|
|
15
|
-
|
|
16
|
-
// Copy data
|
|
17
|
-
frame.set(data, HEADER_SIZE);
|
|
18
|
-
|
|
19
|
-
return frame;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function parseBinaryFrame(frame: Uint8Array): {
|
|
23
|
-
transferId: number;
|
|
24
|
-
data: Uint8Array;
|
|
25
|
-
} {
|
|
26
|
-
const view = new DataView(frame.buffer, frame.byteOffset, frame.byteLength);
|
|
27
|
-
const transferId = view.getUint32(0, false);
|
|
28
|
-
const data = frame.subarray(HEADER_SIZE);
|
|
29
|
-
|
|
30
|
-
return { transferId, data };
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export class BinaryStore {
|
|
34
|
-
private store = new Map<number, Uint8Array>();
|
|
35
|
-
private timeouts = new Map<number, ReturnType<typeof setTimeout>>();
|
|
36
|
-
// 5 minutes timeout for binary data
|
|
37
|
-
private readonly TIMEOUT_MS = 5 * 60 * 1000;
|
|
38
|
-
|
|
39
|
-
add(transferId: number, data: Uint8Array): void {
|
|
40
|
-
this.store.set(transferId, data);
|
|
41
|
-
const timeout = setTimeout(() => {
|
|
42
|
-
this.store.delete(transferId);
|
|
43
|
-
this.timeouts.delete(transferId);
|
|
44
|
-
}, this.TIMEOUT_MS);
|
|
45
|
-
this.timeouts.set(transferId, timeout);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
get(transferId: number): Uint8Array | undefined {
|
|
49
|
-
return this.store.get(transferId);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
delete(transferId: number): boolean {
|
|
53
|
-
const timeout = this.timeouts.get(transferId);
|
|
54
|
-
if (timeout) {
|
|
55
|
-
clearTimeout(timeout);
|
|
56
|
-
this.timeouts.delete(transferId);
|
|
57
|
-
}
|
|
58
|
-
return this.store.delete(transferId);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
dispose(): void {
|
|
62
|
-
for (const timeout of this.timeouts.values()) {
|
|
63
|
-
clearTimeout(timeout);
|
|
64
|
-
}
|
|
65
|
-
this.timeouts.clear();
|
|
66
|
-
this.store.clear();
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
let nextTransferId = 1;
|
|
71
|
-
export function generateTransferId(): number {
|
|
72
|
-
// Use a rolling counter, but ensure it doesn't overflow 32-bit integer just in case
|
|
73
|
-
// though JS numbers are doubles, we are writing to Uint32.
|
|
74
|
-
const id = nextTransferId++;
|
|
75
|
-
if (nextTransferId > 0xffffffff) {
|
|
76
|
-
nextTransferId = 1;
|
|
77
|
-
}
|
|
78
|
-
return id;
|
|
79
|
-
}
|
package/src/heartbeat.ts
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
export const DEFAULT_HEARTBEAT_INTERVAL_MS = 5_000;
|
|
2
|
-
export const DEFAULT_HEARTBEAT_TIMEOUT_MS = 20_000;
|
|
3
|
-
|
|
4
|
-
export type BridgeHeartbeat = {
|
|
5
|
-
notifyPong: (id: number) => void;
|
|
6
|
-
dispose: () => void;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export const createHeartbeat = (options: {
|
|
10
|
-
sendPing: (id: number) => void;
|
|
11
|
-
onTimeout: () => void;
|
|
12
|
-
intervalMs?: number;
|
|
13
|
-
timeoutMs?: number;
|
|
14
|
-
}): BridgeHeartbeat => {
|
|
15
|
-
const intervalMs = options.intervalMs ?? DEFAULT_HEARTBEAT_INTERVAL_MS;
|
|
16
|
-
const timeoutMs = options.timeoutMs ?? DEFAULT_HEARTBEAT_TIMEOUT_MS;
|
|
17
|
-
let nextPingId = 1;
|
|
18
|
-
let pendingPingId: number | null = null;
|
|
19
|
-
let disposed = false;
|
|
20
|
-
let timeoutHandle: ReturnType<typeof setTimeout> | null = null;
|
|
21
|
-
|
|
22
|
-
const clearPendingTimeout = () => {
|
|
23
|
-
if (timeoutHandle) {
|
|
24
|
-
clearTimeout(timeoutHandle);
|
|
25
|
-
timeoutHandle = null;
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
const intervalHandle = setInterval(() => {
|
|
30
|
-
if (disposed || pendingPingId !== null) {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const pingId = nextPingId++;
|
|
35
|
-
pendingPingId = pingId;
|
|
36
|
-
options.sendPing(pingId);
|
|
37
|
-
timeoutHandle = setTimeout(() => {
|
|
38
|
-
if (disposed || pendingPingId !== pingId) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
pendingPingId = null;
|
|
43
|
-
timeoutHandle = null;
|
|
44
|
-
options.onTimeout();
|
|
45
|
-
}, timeoutMs);
|
|
46
|
-
}, intervalMs);
|
|
47
|
-
|
|
48
|
-
return {
|
|
49
|
-
notifyPong: (id) => {
|
|
50
|
-
if (id !== pendingPingId) {
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
pendingPingId = null;
|
|
55
|
-
clearPendingTimeout();
|
|
56
|
-
},
|
|
57
|
-
dispose: () => {
|
|
58
|
-
if (disposed) {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
disposed = true;
|
|
63
|
-
clearInterval(intervalHandle);
|
|
64
|
-
clearPendingTimeout();
|
|
65
|
-
},
|
|
66
|
-
};
|
|
67
|
-
};
|
package/src/transport.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
export type BridgeTransportState = 'connecting' | 'open' | 'closing' | 'closed';
|
|
2
|
-
|
|
3
|
-
export type BridgeTransportMessage = string | Uint8Array;
|
|
4
|
-
|
|
5
|
-
export type BridgeTransportCloseEvent = {
|
|
6
|
-
code: number;
|
|
7
|
-
reason: string;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export type BridgeTransport = {
|
|
11
|
-
readonly state: BridgeTransportState;
|
|
12
|
-
send: (message: BridgeTransportMessage) => void;
|
|
13
|
-
close: (code?: number, reason?: string) => void;
|
|
14
|
-
onOpen: (listener: () => void) => () => void;
|
|
15
|
-
onMessage: (listener: (message: BridgeTransportMessage) => void) => () => void;
|
|
16
|
-
onClose: (listener: (event: BridgeTransportCloseEvent) => void) => () => void;
|
|
17
|
-
onError: (listener: (error: Error) => void) => () => void;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export type RpcTransport = {
|
|
21
|
-
readonly state: BridgeTransportState;
|
|
22
|
-
send: (message: string) => void;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export const toTransportState = (readyState: number): BridgeTransportState => {
|
|
26
|
-
switch (readyState) {
|
|
27
|
-
case 0:
|
|
28
|
-
return 'connecting';
|
|
29
|
-
case 1:
|
|
30
|
-
return 'open';
|
|
31
|
-
case 2:
|
|
32
|
-
return 'closing';
|
|
33
|
-
default:
|
|
34
|
-
return 'closed';
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export const createRpcTransport = (transport: BridgeTransport): RpcTransport => {
|
|
39
|
-
return {
|
|
40
|
-
get state() {
|
|
41
|
-
return transport.state;
|
|
42
|
-
},
|
|
43
|
-
send: (message) => {
|
|
44
|
-
transport.send(message);
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
};
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
toTransportState,
|
|
3
|
-
type BridgeTransport,
|
|
4
|
-
} from './transport.js';
|
|
5
|
-
|
|
6
|
-
type BrowserWebSocketLike = {
|
|
7
|
-
readonly readyState: number;
|
|
8
|
-
binaryType: BinaryType;
|
|
9
|
-
send: (data: string | ArrayBufferLike | Blob | ArrayBufferView) => void;
|
|
10
|
-
close: (code?: number, reason?: string) => void;
|
|
11
|
-
addEventListener: {
|
|
12
|
-
(type: 'open', listener: () => void): void;
|
|
13
|
-
(
|
|
14
|
-
type: 'message',
|
|
15
|
-
listener: (event: MessageEvent<string | ArrayBuffer>) => void,
|
|
16
|
-
): void;
|
|
17
|
-
(type: 'close', listener: (event: CloseEvent) => void): void;
|
|
18
|
-
(
|
|
19
|
-
type: 'error',
|
|
20
|
-
listener: (event: Event & { message?: string }) => void,
|
|
21
|
-
): void;
|
|
22
|
-
};
|
|
23
|
-
removeEventListener: {
|
|
24
|
-
(type: 'open', listener: () => void): void;
|
|
25
|
-
(
|
|
26
|
-
type: 'message',
|
|
27
|
-
listener: (event: MessageEvent<string | ArrayBuffer>) => void,
|
|
28
|
-
): void;
|
|
29
|
-
(type: 'close', listener: (event: CloseEvent) => void): void;
|
|
30
|
-
(
|
|
31
|
-
type: 'error',
|
|
32
|
-
listener: (event: Event & { message?: string }) => void,
|
|
33
|
-
): void;
|
|
34
|
-
};
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export const createWebSocketClientTransport = (url: string): BridgeTransport => {
|
|
38
|
-
const socket = new WebSocket(url) as BrowserWebSocketLike;
|
|
39
|
-
socket.binaryType = 'arraybuffer';
|
|
40
|
-
|
|
41
|
-
return {
|
|
42
|
-
get state() {
|
|
43
|
-
return toTransportState(socket.readyState);
|
|
44
|
-
},
|
|
45
|
-
send: (message) => {
|
|
46
|
-
socket.send(message);
|
|
47
|
-
},
|
|
48
|
-
close: (code, reason) => {
|
|
49
|
-
socket.close(code, reason);
|
|
50
|
-
},
|
|
51
|
-
onOpen: (listener) => {
|
|
52
|
-
socket.addEventListener('open', listener);
|
|
53
|
-
return () => socket.removeEventListener('open', listener);
|
|
54
|
-
},
|
|
55
|
-
onMessage: (listener) => {
|
|
56
|
-
const handleMessage = (event: MessageEvent<string | ArrayBuffer>) => {
|
|
57
|
-
if (typeof event.data === 'string') {
|
|
58
|
-
listener(event.data);
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
listener(new Uint8Array(event.data));
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
socket.addEventListener('message', handleMessage);
|
|
66
|
-
return () => socket.removeEventListener('message', handleMessage);
|
|
67
|
-
},
|
|
68
|
-
onClose: (listener) => {
|
|
69
|
-
const handleClose = (event: CloseEvent) => {
|
|
70
|
-
listener({ code: event.code, reason: event.reason });
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
socket.addEventListener('close', handleClose);
|
|
74
|
-
return () => socket.removeEventListener('close', handleClose);
|
|
75
|
-
},
|
|
76
|
-
onError: (listener) => {
|
|
77
|
-
const handleError = (event: Event & { message?: string }) => {
|
|
78
|
-
listener(new Error(event.message || 'Harness connection error'));
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
socket.addEventListener('error', handleError);
|
|
82
|
-
return () => socket.removeEventListener('error', handleError);
|
|
83
|
-
},
|
|
84
|
-
};
|
|
85
|
-
};
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import type { RawData, WebSocket as NodeWebSocket } from 'ws';
|
|
2
|
-
import {
|
|
3
|
-
toTransportState,
|
|
4
|
-
type BridgeTransport,
|
|
5
|
-
} from './transport.js';
|
|
6
|
-
|
|
7
|
-
const toUint8Array = (message: RawData): Uint8Array => {
|
|
8
|
-
const buffer = Array.isArray(message)
|
|
9
|
-
? Buffer.concat(message)
|
|
10
|
-
: Buffer.isBuffer(message)
|
|
11
|
-
? message
|
|
12
|
-
: Buffer.from(message);
|
|
13
|
-
|
|
14
|
-
return new Uint8Array(buffer);
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export const createNodeWebSocketTransport = (
|
|
18
|
-
socket: NodeWebSocket,
|
|
19
|
-
): BridgeTransport => {
|
|
20
|
-
return {
|
|
21
|
-
get state() {
|
|
22
|
-
return toTransportState(socket.readyState);
|
|
23
|
-
},
|
|
24
|
-
send: (message) => {
|
|
25
|
-
socket.send(message);
|
|
26
|
-
},
|
|
27
|
-
close: (code, reason) => {
|
|
28
|
-
socket.close(code, reason);
|
|
29
|
-
},
|
|
30
|
-
onOpen: () => {
|
|
31
|
-
return () => undefined;
|
|
32
|
-
},
|
|
33
|
-
onMessage: (listener) => {
|
|
34
|
-
const handleMessage = (message: RawData, isBinary: boolean) => {
|
|
35
|
-
listener(isBinary ? toUint8Array(message) : message.toString());
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
socket.on('message', handleMessage);
|
|
39
|
-
return () => socket.off('message', handleMessage);
|
|
40
|
-
},
|
|
41
|
-
onClose: (listener) => {
|
|
42
|
-
const handleClose = (code: number, reason: Buffer) => {
|
|
43
|
-
listener({ code, reason: reason.toString() });
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
socket.on('close', handleClose);
|
|
47
|
-
return () => socket.off('close', handleClose);
|
|
48
|
-
},
|
|
49
|
-
onError: (listener) => {
|
|
50
|
-
socket.on('error', listener);
|
|
51
|
-
return () => socket.off('error', listener);
|
|
52
|
-
},
|
|
53
|
-
};
|
|
54
|
-
};
|