expo 52.0.39 → 52.0.41
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/android/build.gradle +2 -2
- package/bin/autolinking +3 -0
- package/bin/fingerprint +3 -0
- package/build/devtools/DevToolsPluginClient.d.ts +12 -4
- package/build/devtools/DevToolsPluginClient.d.ts.map +1 -1
- package/build/devtools/DevToolsPluginClientImplApp.d.ts +1 -0
- package/build/devtools/DevToolsPluginClientImplApp.d.ts.map +1 -1
- package/build/devtools/DevToolsPluginClientImplBrowser.d.ts.map +1 -1
- package/build/devtools/MessageFramePacker.d.ts +26 -16
- package/build/devtools/MessageFramePacker.d.ts.map +1 -1
- package/build/devtools/ProtocolVersion.d.ts +7 -0
- package/build/devtools/ProtocolVersion.d.ts.map +1 -0
- package/build/devtools/devtools.types.d.ts +14 -8
- package/build/devtools/devtools.types.d.ts.map +1 -1
- package/build/devtools/getConnectionInfo.d.ts.map +1 -1
- package/build/devtools/getConnectionInfo.native.d.ts.map +1 -1
- package/bundledNativeModules.json +7 -7
- package/package.json +10 -6
- package/src/devtools/DevToolsPluginClient.ts +71 -18
- package/src/devtools/DevToolsPluginClientImplApp.ts +32 -9
- package/src/devtools/DevToolsPluginClientImplBrowser.ts +13 -7
- package/src/devtools/MessageFramePacker.ts +100 -43
- package/src/devtools/ProtocolVersion.ts +6 -0
- package/src/devtools/__tests__/DevToolsPluginClient-test.ts +42 -0
- package/src/devtools/__tests__/DevToolsPluginClientFactory-test.ts +9 -0
- package/src/devtools/__tests__/MessageFramePack-test.node.ts +49 -19
- package/src/devtools/devtools.types.ts +15 -8
- package/src/devtools/getConnectionInfo.native.ts +2 -0
- package/src/devtools/getConnectionInfo.ts +2 -0
package/android/build.gradle
CHANGED
|
@@ -33,7 +33,7 @@ def getRNVersion() {
|
|
|
33
33
|
ensureDependeciesWereEvaluated(project)
|
|
34
34
|
|
|
35
35
|
group = 'host.exp.exponent'
|
|
36
|
-
version = '52.0.
|
|
36
|
+
version = '52.0.41'
|
|
37
37
|
|
|
38
38
|
buildscript {
|
|
39
39
|
// Simple helper that allows the root project to override versions declared by this library.
|
|
@@ -46,7 +46,7 @@ android {
|
|
|
46
46
|
namespace "expo.core"
|
|
47
47
|
defaultConfig {
|
|
48
48
|
versionCode 1
|
|
49
|
-
versionName "52.0.
|
|
49
|
+
versionName "52.0.41"
|
|
50
50
|
consumerProguardFiles("proguard-rules.pro")
|
|
51
51
|
}
|
|
52
52
|
testOptions {
|
package/bin/autolinking
ADDED
package/bin/fingerprint
ADDED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EventEmitter, EventSubscription } from 'fbemitter';
|
|
2
2
|
import { WebSocketBackingStore } from './WebSocketBackingStore';
|
|
3
|
-
import type { ConnectionInfo, DevToolsPluginClientOptions } from './devtools.types';
|
|
3
|
+
import type { ConnectionInfo, DevToolsPluginClientOptions, HandshakeMessageParams } from './devtools.types';
|
|
4
4
|
/**
|
|
5
5
|
* This client is for the Expo DevTools Plugins to communicate between the app and the DevTools webpage hosted in a browser.
|
|
6
6
|
* All the code should be both compatible with browsers and React Native.
|
|
@@ -30,7 +30,6 @@ export declare abstract class DevToolsPluginClient {
|
|
|
30
30
|
* @param params any extra payload.
|
|
31
31
|
*/
|
|
32
32
|
sendMessage(method: string, params: any): void;
|
|
33
|
-
private sendMessageImpl;
|
|
34
33
|
/**
|
|
35
34
|
* Subscribe to a message from the other end of DevTools.
|
|
36
35
|
* @param method Subscribe to a message with a method name.
|
|
@@ -43,6 +42,16 @@ export declare abstract class DevToolsPluginClient {
|
|
|
43
42
|
* @param listener Listener to be called when a message is received.
|
|
44
43
|
*/
|
|
45
44
|
addMessageListenerOnce(method: string, listener: (params: any) => void): void;
|
|
45
|
+
/**
|
|
46
|
+
* Internal handshake message sender.
|
|
47
|
+
* @hidden
|
|
48
|
+
*/
|
|
49
|
+
protected sendHandshakeMessage(params: HandshakeMessageParams): void;
|
|
50
|
+
/**
|
|
51
|
+
* Internal handshake message listener.
|
|
52
|
+
* @hidden
|
|
53
|
+
*/
|
|
54
|
+
protected addHandskakeMessageListener(listener: (params: HandshakeMessageParams) => void): Partial<EventSubscription>;
|
|
46
55
|
/**
|
|
47
56
|
* Returns whether the client is connected to the server.
|
|
48
57
|
*/
|
|
@@ -51,8 +60,7 @@ export declare abstract class DevToolsPluginClient {
|
|
|
51
60
|
* The method to create the WebSocket connection.
|
|
52
61
|
*/
|
|
53
62
|
protected connectAsync(): Promise<WebSocket>;
|
|
54
|
-
protected handleMessage: (event: WebSocketMessageEvent) => void
|
|
55
|
-
private handleMessageImpl;
|
|
63
|
+
protected handleMessage: (event: WebSocketMessageEvent) => Promise<void>;
|
|
56
64
|
/**
|
|
57
65
|
* Get the WebSocket backing store. Exposed for testing.
|
|
58
66
|
* @hidden
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DevToolsPluginClient.d.ts","sourceRoot":"","sources":["../../src/devtools/DevToolsPluginClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAG5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"DevToolsPluginClient.d.ts","sourceRoot":"","sources":["../../src/devtools/DevToolsPluginClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAG5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,OAAO,KAAK,EACV,cAAc,EACd,2BAA2B,EAC3B,sBAAsB,EACvB,MAAM,kBAAkB,CAAC;AAS1B;;;GAGG;AACH,8BAAsB,oBAAoB;aAYtB,cAAc,EAAE,cAAc;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;IAZ3B,SAAS,CAAC,YAAY,EAAE,YAAY,CAAsB;IAE1D,OAAO,CAAC,MAAM,CAAC,cAAc,CAAsD;IACnF,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8D;IAEtF,SAAS,CAAC,QAAQ,UAAS;IAC3B,SAAS,CAAC,OAAO,SAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CACR;gBAGT,cAAc,EAAE,cAAc,EAC7B,OAAO,CAAC,yCAA6B;IAKxD;;;OAGG;IACU,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAQvC;;OAEG;IACU,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAWxC;;;;OAIG;IACI,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG;IAmB9C;;;;OAIG;IACI,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,GAAG,iBAAiB;IAI7F;;;;OAIG;IACI,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI;IAIpF;;;OAGG;IACH,SAAS,CAAC,oBAAoB,CAAC,MAAM,EAAE,sBAAsB;IAQ7D;;;OAGG;IACH,SAAS,CAAC,2BAA2B,CACnC,QAAQ,EAAE,CAAC,MAAM,EAAE,sBAAsB,KAAK,IAAI,GACjD,OAAO,CAAC,iBAAiB,CAAC;IA2B7B;;OAEG;IACI,WAAW,IAAI,OAAO;IAI7B;;OAEG;IACH,SAAS,CAAC,YAAY,IAAI,OAAO,CAAC,SAAS,CAAC;IAyB5C,SAAS,CAAC,aAAa,UAAiB,qBAAqB,mBAuB3D;IAEF;;;OAGG;IACI,wBAAwB,IAAI,qBAAqB;CAGzD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DevToolsPluginClientImplApp.d.ts","sourceRoot":"","sources":["../../src/devtools/DevToolsPluginClientImplApp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"DevToolsPluginClientImplApp.d.ts","sourceRoot":"","sources":["../../src/devtools/DevToolsPluginClientImplApp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAG9D;;GAEG;AACH,qBAAa,2BAA4B,SAAQ,oBAAoB;IAEnE,OAAO,CAAC,gBAAgB,CAA8B;IAEtD;;;OAGG;IACY,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAKzC,OAAO,CAAC,mBAAmB;IA4B3B,OAAO,CAAC,sBAAsB;CAQ/B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DevToolsPluginClientImplBrowser.d.ts","sourceRoot":"","sources":["../../src/devtools/DevToolsPluginClientImplBrowser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAG9D;;GAEG;AACH,qBAAa,+BAAgC,SAAQ,oBAAoB;IACvE,OAAO,CAAC,eAAe,CAAiC;IAExD;;;OAGG;IACY,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAKzC,OAAO,CAAC,cAAc;
|
|
1
|
+
{"version":3,"file":"DevToolsPluginClientImplBrowser.d.ts","sourceRoot":"","sources":["../../src/devtools/DevToolsPluginClientImplBrowser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAG9D;;GAEG;AACH,qBAAa,+BAAgC,SAAQ,oBAAoB;IACvE,OAAO,CAAC,eAAe,CAAiC;IAExD;;;OAGG;IACY,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAKzC,OAAO,CAAC,cAAc;CAmBvB"}
|
|
@@ -1,25 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* A message frame packer that serializes a messageKey and a payload into a
|
|
2
|
+
* A message frame packer that serializes a messageKey and a payload into either a JSON string
|
|
3
|
+
* (fast path) or a binary format (for complex payloads).
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* Fast Path (JSON.stringify/JSON.parse):
|
|
6
|
+
* - For simple payloads (e.g., strings, numbers, null, undefined, or plain objects), the packer
|
|
7
|
+
* uses `JSON.stringify` for serialization and `JSON.parse` for deserialization, ensuring
|
|
8
|
+
* optimal performance.
|
|
8
9
|
*
|
|
9
|
-
*
|
|
10
|
+
* Binary Format:
|
|
11
|
+
* - For more complex payloads (e.g., Uint8Array, ArrayBuffer, Blob), the packer uses a binary
|
|
12
|
+
* format with the following structure:
|
|
10
13
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
14
|
+
* +------------------+-------------------+----------------------------+--------------------------+
|
|
15
|
+
* | 4 bytes (Uint32) | Variable length | 1 byte (Uint8) | Variable length |
|
|
16
|
+
* | MessageKeyLength | MessageKey (JSON) | PayloadTypeIndicator (enum)| Payload (binary data) |
|
|
17
|
+
* +------------------+-------------------+----------------------------+--------------------------+
|
|
13
18
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
19
|
+
* 1. MessageKeyLength (4 bytes):
|
|
20
|
+
* - A 4-byte unsigned integer indicating the length of the MessageKey JSON string.
|
|
16
21
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
22
|
+
* 2. MessageKey (Variable length):
|
|
23
|
+
* - The JSON string representing the message key, encoded as UTF-8.
|
|
19
24
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
25
|
+
* 3. PayloadTypeIndicator (1 byte):
|
|
26
|
+
* - A single byte enum value representing the type of the payload (e.g., Uint8Array, String,
|
|
27
|
+
* Object, ArrayBuffer, Blob).
|
|
22
28
|
*
|
|
29
|
+
* 4. Payload (Variable length):
|
|
30
|
+
* - The actual payload data, which can vary in type and length depending on the PayloadType.
|
|
23
31
|
*/
|
|
24
32
|
type MessageKeyTypeBase = string | object;
|
|
25
33
|
type PayloadType = Uint8Array | string | number | null | undefined | object | ArrayBuffer | Blob;
|
|
@@ -30,9 +38,11 @@ interface MessageFrame<T extends MessageKeyTypeBase> {
|
|
|
30
38
|
export declare class MessageFramePacker<T extends MessageKeyTypeBase> {
|
|
31
39
|
private textEncoder;
|
|
32
40
|
private textDecoder;
|
|
33
|
-
pack({ messageKey, payload }: MessageFrame<T>): Promise<Uint8Array>;
|
|
34
|
-
unpack(packedData: ArrayBuffer):
|
|
41
|
+
pack({ messageKey, payload }: MessageFrame<T>): string | Uint8Array | Promise<Uint8Array>;
|
|
42
|
+
unpack(packedData: string | ArrayBuffer): MessageFrame<T>;
|
|
43
|
+
private isFastPathPayload;
|
|
35
44
|
private payloadToUint8Array;
|
|
45
|
+
private packImpl;
|
|
36
46
|
private deserializePayload;
|
|
37
47
|
private static getPayloadTypeIndicator;
|
|
38
48
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageFramePacker.d.ts","sourceRoot":"","sources":["../../src/devtools/MessageFramePacker.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"MessageFramePacker.d.ts","sourceRoot":"","sources":["../../src/devtools/MessageFramePacker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAIH,KAAK,kBAAkB,GAAG,MAAM,GAAG,MAAM,CAAC;AAC1C,KAAK,WAAW,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,WAAW,GAAG,IAAI,CAAC;AAajG,UAAU,YAAY,CAAC,CAAC,SAAS,kBAAkB;IACjD,UAAU,EAAE,CAAC,CAAC;IACd,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB;AAED,qBAAa,kBAAkB,CAAC,CAAC,SAAS,kBAAkB;IAC1D,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,WAAW,CAAqB;IAEjC,IAAI,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IA2BzF,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,GAAG,YAAY,CAAC,CAAC,CAAC;IA0BhE,OAAO,CAAC,iBAAiB;IAczB,OAAO,CAAC,mBAAmB;IAuB3B,OAAO,CAAC,QAAQ;IA8BhB,OAAO,CAAC,kBAAkB;IAoC1B,OAAO,CAAC,MAAM,CAAC,uBAAuB;CAqBvC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A transport protocol version between the app and the webui.
|
|
3
|
+
* It shows a warning in handshaking stage if the version is different between the app and the webui.
|
|
4
|
+
* The value should be increased when the protocol is changed.
|
|
5
|
+
*/
|
|
6
|
+
export declare const PROTOCOL_VERSION = 1;
|
|
7
|
+
//# sourceMappingURL=ProtocolVersion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProtocolVersion.d.ts","sourceRoot":"","sources":["../../src/devtools/ProtocolVersion.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,IAAI,CAAC"}
|
|
@@ -15,14 +15,10 @@ export interface ConnectionInfo {
|
|
|
15
15
|
* @hidden
|
|
16
16
|
*/
|
|
17
17
|
wsStore?: WebSocketBackingStore;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
*/
|
|
23
|
-
export interface HandshakeMessageParams {
|
|
24
|
-
browserClientId: string;
|
|
25
|
-
pluginName: string;
|
|
18
|
+
/**
|
|
19
|
+
* The transport protocol version between the app and the webui.
|
|
20
|
+
*/
|
|
21
|
+
protocolVersion: number;
|
|
26
22
|
}
|
|
27
23
|
/**
|
|
28
24
|
* Options for the devtools plugin client.
|
|
@@ -33,4 +29,14 @@ export interface DevToolsPluginClientOptions {
|
|
|
33
29
|
*/
|
|
34
30
|
websocketBinaryType?: 'arraybuffer' | 'blob';
|
|
35
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* The handshake messages for the devtools plugin client.
|
|
34
|
+
* @hidden
|
|
35
|
+
*/
|
|
36
|
+
export interface HandshakeMessageParams {
|
|
37
|
+
protocolVersion: number;
|
|
38
|
+
pluginName: string;
|
|
39
|
+
method: 'handshake' | 'terminateBrowserClient';
|
|
40
|
+
browserClientId: string;
|
|
41
|
+
}
|
|
36
42
|
//# sourceMappingURL=devtools.types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"devtools.types.d.ts","sourceRoot":"","sources":["../../src/devtools/devtools.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAErE;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,wDAAwD;IACxD,MAAM,EACF,KAAK,GACL,SAAS,CAAC;IAEd,0BAA0B;IAC1B,SAAS,EAAE,MAAM,CAAC;IAElB,uBAAuB;IACvB,UAAU,EAAE,MAAM,CAAC;IAEnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"devtools.types.d.ts","sourceRoot":"","sources":["../../src/devtools/devtools.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAErE;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,wDAAwD;IACxD,MAAM,EACF,KAAK,GACL,SAAS,CAAC;IAEd,0BAA0B;IAC1B,SAAS,EAAE,MAAM,CAAC;IAElB,uBAAuB;IACvB,UAAU,EAAE,MAAM,CAAC;IAEnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,qBAAqB,CAAC;IAEhC;;OAEG;IACH,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C;;OAEG;IACH,mBAAmB,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC;CAC9C;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,WAAW,GAAG,wBAAwB,CAAC;IAC/C,eAAe,EAAE,MAAM,CAAC;CACzB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getConnectionInfo.d.ts","sourceRoot":"","sources":["../../src/devtools/getConnectionInfo.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"getConnectionInfo.d.ts","sourceRoot":"","sources":["../../src/devtools/getConnectionInfo.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD,wBAAgB,iBAAiB,IAAI,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC,CAQtE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getConnectionInfo.native.d.ts","sourceRoot":"","sources":["../../src/devtools/getConnectionInfo.native.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"getConnectionInfo.native.d.ts","sourceRoot":"","sources":["../../src/devtools/getConnectionInfo.native.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD,wBAAgB,iBAAiB,IAAI,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC,CAUtE"}
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"expo-app-loader-provider": "~8.0.0",
|
|
17
17
|
"expo-apple-authentication": "~7.1.3",
|
|
18
18
|
"expo-application": "~6.0.2",
|
|
19
|
-
"expo-asset": "~11.0.
|
|
19
|
+
"expo-asset": "~11.0.5",
|
|
20
20
|
"expo-audio": "~0.3.5",
|
|
21
21
|
"expo-auth-session": "~6.0.3",
|
|
22
22
|
"expo-av": "~15.0.2",
|
|
@@ -34,16 +34,16 @@
|
|
|
34
34
|
"expo-constants": "~17.0.8",
|
|
35
35
|
"expo-contacts": "~14.0.5",
|
|
36
36
|
"expo-crypto": "~14.0.2",
|
|
37
|
-
"expo-dev-client": "~5.0.
|
|
37
|
+
"expo-dev-client": "~5.0.15",
|
|
38
38
|
"expo-device": "~7.0.2",
|
|
39
39
|
"expo-document-picker": "~13.0.3",
|
|
40
40
|
"expo-face-detector": "~13.0.2",
|
|
41
|
-
"expo-file-system": "~18.0.
|
|
41
|
+
"expo-file-system": "~18.0.12",
|
|
42
42
|
"expo-font": "~13.0.4",
|
|
43
43
|
"expo-gl": "~15.0.4",
|
|
44
44
|
"expo-google-app-auth": "~8.3.0",
|
|
45
45
|
"expo-haptics": "~14.0.1",
|
|
46
|
-
"expo-image": "~2.0.
|
|
46
|
+
"expo-image": "~2.0.7",
|
|
47
47
|
"expo-image-loader": "~5.0.0",
|
|
48
48
|
"expo-image-manipulator": "~13.0.6",
|
|
49
49
|
"expo-image-picker": "~16.0.6",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"expo-network": "~7.0.5",
|
|
64
64
|
"expo-notifications": "~0.29.14",
|
|
65
65
|
"expo-print": "~14.0.3",
|
|
66
|
-
"expo-router": "~4.0.
|
|
66
|
+
"expo-router": "~4.0.19",
|
|
67
67
|
"expo-screen-capture": "~7.0.1",
|
|
68
68
|
"expo-screen-orientation": "~8.0.4",
|
|
69
69
|
"expo-secure-store": "~14.0.1",
|
|
@@ -72,14 +72,14 @@
|
|
|
72
72
|
"expo-sms": "~13.0.1",
|
|
73
73
|
"expo-speech": "~13.0.1",
|
|
74
74
|
"expo-splash-screen": "~0.29.22",
|
|
75
|
-
"expo-sqlite": "~15.1.
|
|
75
|
+
"expo-sqlite": "~15.1.3",
|
|
76
76
|
"expo-status-bar": "~2.0.1",
|
|
77
77
|
"expo-store-review": "~8.0.1",
|
|
78
78
|
"expo-symbols": "~0.2.2",
|
|
79
79
|
"expo-system-ui": "~4.0.8",
|
|
80
80
|
"expo-task-manager": "~12.0.5",
|
|
81
81
|
"expo-tracking-transparency": "~5.1.1",
|
|
82
|
-
"expo-updates": "~0.27.
|
|
82
|
+
"expo-updates": "~0.27.4",
|
|
83
83
|
"expo-video-thumbnails": "~9.0.3",
|
|
84
84
|
"expo-video": "~2.0.6",
|
|
85
85
|
"expo-web-browser": "~14.0.2",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo",
|
|
3
|
-
"version": "52.0.
|
|
3
|
+
"version": "52.0.41",
|
|
4
4
|
"description": "The Expo SDK",
|
|
5
5
|
"main": "src/Expo.ts",
|
|
6
6
|
"module": "src/Expo.ts",
|
|
@@ -10,7 +10,11 @@
|
|
|
10
10
|
"*.fx.web.tsx",
|
|
11
11
|
"./src/winter/*.ts"
|
|
12
12
|
],
|
|
13
|
-
"bin":
|
|
13
|
+
"bin": {
|
|
14
|
+
"expo": "bin/cli",
|
|
15
|
+
"expo-modules-autolinking": "bin/autolinking",
|
|
16
|
+
"fingerprint": "bin/fingerprint"
|
|
17
|
+
},
|
|
14
18
|
"files": [
|
|
15
19
|
"android",
|
|
16
20
|
"bin",
|
|
@@ -68,16 +72,16 @@
|
|
|
68
72
|
"homepage": "https://github.com/expo/expo/tree/main/packages/expo",
|
|
69
73
|
"dependencies": {
|
|
70
74
|
"@babel/runtime": "^7.20.0",
|
|
71
|
-
"@expo/cli": "0.22.
|
|
75
|
+
"@expo/cli": "0.22.22",
|
|
72
76
|
"@expo/config": "~10.0.11",
|
|
73
77
|
"@expo/config-plugins": "~9.0.17",
|
|
74
78
|
"@expo/fingerprint": "0.11.11",
|
|
75
79
|
"@expo/metro-config": "0.19.12",
|
|
76
80
|
"@expo/vector-icons": "^14.0.0",
|
|
77
81
|
"babel-preset-expo": "~12.0.9",
|
|
78
|
-
"expo-asset": "~11.0.
|
|
82
|
+
"expo-asset": "~11.0.5",
|
|
79
83
|
"expo-constants": "~17.0.8",
|
|
80
|
-
"expo-file-system": "~18.0.
|
|
84
|
+
"expo-file-system": "~18.0.12",
|
|
81
85
|
"expo-font": "~13.0.4",
|
|
82
86
|
"expo-keep-awake": "~14.0.3",
|
|
83
87
|
"expo-modules-autolinking": "2.0.8",
|
|
@@ -112,5 +116,5 @@
|
|
|
112
116
|
"optional": true
|
|
113
117
|
}
|
|
114
118
|
},
|
|
115
|
-
"gitHead": "
|
|
119
|
+
"gitHead": "5f0263343cdcddf406eb01fe2fb68182be041fd9"
|
|
116
120
|
}
|
|
@@ -3,7 +3,11 @@ import { EventEmitter, EventSubscription } from 'fbemitter';
|
|
|
3
3
|
import { MessageFramePacker } from './MessageFramePacker';
|
|
4
4
|
import { WebSocketBackingStore } from './WebSocketBackingStore';
|
|
5
5
|
import { WebSocketWithReconnect } from './WebSocketWithReconnect';
|
|
6
|
-
import type {
|
|
6
|
+
import type {
|
|
7
|
+
ConnectionInfo,
|
|
8
|
+
DevToolsPluginClientOptions,
|
|
9
|
+
HandshakeMessageParams,
|
|
10
|
+
} from './devtools.types';
|
|
7
11
|
import * as logger from './logger';
|
|
8
12
|
import { blobToArrayBufferAsync } from '../utils/blobUtils';
|
|
9
13
|
|
|
@@ -70,16 +74,18 @@ export abstract class DevToolsPluginClient {
|
|
|
70
74
|
logger.warn('Unable to send message in a disconnected state.');
|
|
71
75
|
return;
|
|
72
76
|
}
|
|
73
|
-
this.sendMessageImpl(method, params);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
private async sendMessageImpl(method: string, params: any) {
|
|
77
77
|
const messageKey: MessageFramePackerMessageKey = {
|
|
78
78
|
pluginName: this.connectionInfo.pluginName,
|
|
79
79
|
method,
|
|
80
80
|
};
|
|
81
|
-
const packedData =
|
|
82
|
-
|
|
81
|
+
const packedData = this.messageFramePacker.pack({ messageKey, payload: params });
|
|
82
|
+
if (!(packedData instanceof Promise)) {
|
|
83
|
+
this.wsStore.ws?.send(packedData);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
packedData.then((data) => {
|
|
87
|
+
this.wsStore.ws?.send(data);
|
|
88
|
+
});
|
|
83
89
|
}
|
|
84
90
|
|
|
85
91
|
/**
|
|
@@ -100,6 +106,51 @@ export abstract class DevToolsPluginClient {
|
|
|
100
106
|
this.eventEmitter.once(method, listener);
|
|
101
107
|
}
|
|
102
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Internal handshake message sender.
|
|
111
|
+
* @hidden
|
|
112
|
+
*/
|
|
113
|
+
protected sendHandshakeMessage(params: HandshakeMessageParams) {
|
|
114
|
+
if (this.wsStore.ws?.readyState === WebSocket.CLOSED) {
|
|
115
|
+
logger.warn('Unable to send message in a disconnected state.');
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
this.wsStore.ws?.send(JSON.stringify({ ...params, __isHandshakeMessages: true }));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Internal handshake message listener.
|
|
123
|
+
* @hidden
|
|
124
|
+
*/
|
|
125
|
+
protected addHandskakeMessageListener(
|
|
126
|
+
listener: (params: HandshakeMessageParams) => void
|
|
127
|
+
): Partial<EventSubscription> {
|
|
128
|
+
const messageListener = (event: MessageEvent) => {
|
|
129
|
+
if (typeof event.data !== 'string') {
|
|
130
|
+
// binary data is not coming from the handshake messages.
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const data = JSON.parse(event.data);
|
|
135
|
+
if (!data.__isHandshakeMessages) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
delete data.__isHandshakeMessages;
|
|
139
|
+
const params = data as HandshakeMessageParams;
|
|
140
|
+
if (params.pluginName && params.pluginName !== this.connectionInfo.pluginName) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
listener(params);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
this.wsStore.ws?.addEventListener('message', messageListener);
|
|
147
|
+
return {
|
|
148
|
+
remove: () => {
|
|
149
|
+
this.wsStore.ws?.removeEventListener('message', messageListener);
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
103
154
|
/**
|
|
104
155
|
* Returns whether the client is connected to the server.
|
|
105
156
|
*/
|
|
@@ -135,23 +186,25 @@ export abstract class DevToolsPluginClient {
|
|
|
135
186
|
});
|
|
136
187
|
}
|
|
137
188
|
|
|
138
|
-
protected handleMessage = (event: WebSocketMessageEvent) => {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
if (event.data instanceof ArrayBuffer) {
|
|
145
|
-
buffer = event.data;
|
|
189
|
+
protected handleMessage = async (event: WebSocketMessageEvent) => {
|
|
190
|
+
let data: ArrayBuffer | string;
|
|
191
|
+
if (typeof event.data === 'string') {
|
|
192
|
+
data = event.data;
|
|
193
|
+
} else if (event.data instanceof ArrayBuffer) {
|
|
194
|
+
data = event.data;
|
|
146
195
|
} else if (ArrayBuffer.isView(event.data)) {
|
|
147
|
-
|
|
196
|
+
data = event.data.buffer;
|
|
148
197
|
} else if (event.data instanceof Blob) {
|
|
149
|
-
|
|
198
|
+
data = await blobToArrayBufferAsync(event.data);
|
|
150
199
|
} else {
|
|
151
200
|
logger.warn('Unsupported received data type in handleMessageImpl');
|
|
152
201
|
return;
|
|
153
202
|
}
|
|
154
|
-
const { messageKey, payload } =
|
|
203
|
+
const { messageKey, payload, ...rest } = this.messageFramePacker.unpack(data);
|
|
204
|
+
// @ts-expect-error: `__isHandshakeMessages` is a private field that is not part of the MessageFramePacker type.
|
|
205
|
+
if (rest?.__isHandshakeMessages === true) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
155
208
|
if (messageKey.pluginName && messageKey.pluginName !== this.connectionInfo.pluginName) {
|
|
156
209
|
return;
|
|
157
210
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { DevToolsPluginClient } from './DevToolsPluginClient';
|
|
2
|
-
import type { HandshakeMessageParams } from './devtools.types';
|
|
3
2
|
import * as logger from './logger';
|
|
4
3
|
|
|
5
4
|
/**
|
|
@@ -19,15 +18,39 @@ export class DevToolsPluginClientImplApp extends DevToolsPluginClient {
|
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
private addHandshakeHandler() {
|
|
22
|
-
this.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
)
|
|
28
|
-
|
|
21
|
+
this.addHandskakeMessageListener((params) => {
|
|
22
|
+
if (params.method === 'handshake') {
|
|
23
|
+
const { pluginName, protocolVersion } = params;
|
|
24
|
+
|
|
25
|
+
// [0] Check protocol version
|
|
26
|
+
if (protocolVersion !== this.connectionInfo.protocolVersion) {
|
|
27
|
+
// Use console.warn than logger because we want to show the warning even logging is disabled.
|
|
28
|
+
console.warn(
|
|
29
|
+
`Received an incompatible devtools plugin handshake message - pluginName[${pluginName}]`
|
|
30
|
+
);
|
|
31
|
+
this.terminateBrowserClient(pluginName, params.browserClientId);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// [1] Terminate duplicated browser clients for the same plugin
|
|
36
|
+
const previousBrowserClientId = this.browserClientMap[pluginName];
|
|
37
|
+
if (previousBrowserClientId != null && previousBrowserClientId !== params.browserClientId) {
|
|
38
|
+
logger.info(
|
|
39
|
+
`Terminate the previous browser client connection - previousBrowserClientId[${previousBrowserClientId}]`
|
|
40
|
+
);
|
|
41
|
+
this.terminateBrowserClient(pluginName, previousBrowserClientId);
|
|
42
|
+
}
|
|
43
|
+
this.browserClientMap[pluginName] = params.browserClientId;
|
|
29
44
|
}
|
|
30
|
-
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private terminateBrowserClient(pluginName: string, browserClientId: string) {
|
|
49
|
+
this.sendHandshakeMessage({
|
|
50
|
+
protocolVersion: this.connectionInfo.protocolVersion,
|
|
51
|
+
method: 'terminateBrowserClient',
|
|
52
|
+
browserClientId,
|
|
53
|
+
pluginName,
|
|
31
54
|
});
|
|
32
55
|
}
|
|
33
56
|
}
|
|
@@ -17,16 +17,22 @@ export class DevToolsPluginClientImplBrowser extends DevToolsPluginClient {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
private startHandshake() {
|
|
20
|
-
this.
|
|
21
|
-
if (
|
|
22
|
-
|
|
20
|
+
this.addHandskakeMessageListener((params) => {
|
|
21
|
+
if (
|
|
22
|
+
params.method === 'terminateBrowserClient' &&
|
|
23
|
+
this.browserClientId === params.browserClientId
|
|
24
|
+
) {
|
|
25
|
+
logger.info(
|
|
26
|
+
'Received terminateBrowserClient messages and terminate the current connection'
|
|
27
|
+
);
|
|
28
|
+
this.closeAsync();
|
|
23
29
|
}
|
|
24
|
-
logger.info('Received terminateBrowserClient messages and terminate the current connection');
|
|
25
|
-
this.closeAsync();
|
|
26
30
|
});
|
|
27
|
-
this.
|
|
28
|
-
|
|
31
|
+
this.sendHandshakeMessage({
|
|
32
|
+
protocolVersion: this.connectionInfo.protocolVersion,
|
|
29
33
|
pluginName: this.connectionInfo.pluginName,
|
|
34
|
+
method: 'handshake',
|
|
35
|
+
browserClientId: this.browserClientId,
|
|
30
36
|
});
|
|
31
37
|
}
|
|
32
38
|
}
|
|
@@ -1,25 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* A message frame packer that serializes a messageKey and a payload into a
|
|
2
|
+
* A message frame packer that serializes a messageKey and a payload into either a JSON string
|
|
3
|
+
* (fast path) or a binary format (for complex payloads).
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* Fast Path (JSON.stringify/JSON.parse):
|
|
6
|
+
* - For simple payloads (e.g., strings, numbers, null, undefined, or plain objects), the packer
|
|
7
|
+
* uses `JSON.stringify` for serialization and `JSON.parse` for deserialization, ensuring
|
|
8
|
+
* optimal performance.
|
|
8
9
|
*
|
|
9
|
-
*
|
|
10
|
+
* Binary Format:
|
|
11
|
+
* - For more complex payloads (e.g., Uint8Array, ArrayBuffer, Blob), the packer uses a binary
|
|
12
|
+
* format with the following structure:
|
|
10
13
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
14
|
+
* +------------------+-------------------+----------------------------+--------------------------+
|
|
15
|
+
* | 4 bytes (Uint32) | Variable length | 1 byte (Uint8) | Variable length |
|
|
16
|
+
* | MessageKeyLength | MessageKey (JSON) | PayloadTypeIndicator (enum)| Payload (binary data) |
|
|
17
|
+
* +------------------+-------------------+----------------------------+--------------------------+
|
|
13
18
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
19
|
+
* 1. MessageKeyLength (4 bytes):
|
|
20
|
+
* - A 4-byte unsigned integer indicating the length of the MessageKey JSON string.
|
|
16
21
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
22
|
+
* 2. MessageKey (Variable length):
|
|
23
|
+
* - The JSON string representing the message key, encoded as UTF-8.
|
|
19
24
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
25
|
+
* 3. PayloadTypeIndicator (1 byte):
|
|
26
|
+
* - A single byte enum value representing the type of the payload (e.g., Uint8Array, String,
|
|
27
|
+
* Object, ArrayBuffer, Blob).
|
|
22
28
|
*
|
|
29
|
+
* 4. Payload (Variable length):
|
|
30
|
+
* - The actual payload data, which can vary in type and length depending on the PayloadType.
|
|
23
31
|
*/
|
|
24
32
|
|
|
25
33
|
import { blobToArrayBufferAsync } from '../utils/blobUtils';
|
|
@@ -47,34 +55,39 @@ export class MessageFramePacker<T extends MessageKeyTypeBase> {
|
|
|
47
55
|
private textEncoder = new TextEncoder();
|
|
48
56
|
private textDecoder = new TextDecoder();
|
|
49
57
|
|
|
50
|
-
public
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const totalLength = 4 + messageKeyLength + 1 + payloadBinary.byteLength;
|
|
57
|
-
const buffer = new ArrayBuffer(totalLength);
|
|
58
|
-
const packedArray = new Uint8Array(buffer);
|
|
59
|
-
|
|
60
|
-
// [0] messageKeyLength (4 bytes)
|
|
61
|
-
const messageKeyLengthView = new DataView(buffer, 0, 4);
|
|
62
|
-
messageKeyLengthView.setUint32(0, messageKeyLength, false);
|
|
63
|
-
|
|
64
|
-
// [1] messageKey (variable length)
|
|
65
|
-
packedArray.set(messageKeyBytes, 4);
|
|
66
|
-
|
|
67
|
-
// [2] payloadTypeIndicator (1 byte)
|
|
68
|
-
const payloadTypeView = new DataView(buffer, 4 + messageKeyLength, 1);
|
|
69
|
-
payloadTypeView.setUint8(0, MessageFramePacker.getPayloadTypeIndicator(payload));
|
|
58
|
+
public pack({ messageKey, payload }: MessageFrame<T>): string | Uint8Array | Promise<Uint8Array> {
|
|
59
|
+
// Fast path to pack as string given `JSON.stringify` is fast.
|
|
60
|
+
if (this.isFastPathPayload(payload)) {
|
|
61
|
+
return JSON.stringify({ messageKey, payload });
|
|
62
|
+
}
|
|
70
63
|
|
|
71
|
-
//
|
|
72
|
-
|
|
64
|
+
// Slowest path for Blob returns a promise.
|
|
65
|
+
if (payload instanceof Blob) {
|
|
66
|
+
return new Promise(async (resolve, reject) => {
|
|
67
|
+
try {
|
|
68
|
+
const arrayBuffer = await blobToArrayBufferAsync(payload);
|
|
69
|
+
resolve(
|
|
70
|
+
this.packImpl(
|
|
71
|
+
{ messageKey, payload: new Uint8Array(arrayBuffer) },
|
|
72
|
+
PayloadTypeIndicator.Blob
|
|
73
|
+
)
|
|
74
|
+
);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
reject(error);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
73
80
|
|
|
74
|
-
|
|
81
|
+
// Slow path for other types returns a Uint8Array.
|
|
82
|
+
return this.packImpl({ messageKey, payload }, undefined);
|
|
75
83
|
}
|
|
76
84
|
|
|
77
|
-
public
|
|
85
|
+
public unpack(packedData: string | ArrayBuffer): MessageFrame<T> {
|
|
86
|
+
// Fast path to unpack as string given `JSON.parse` is fast.
|
|
87
|
+
if (typeof packedData === 'string') {
|
|
88
|
+
return JSON.parse(packedData);
|
|
89
|
+
}
|
|
90
|
+
|
|
78
91
|
// [0] messageKeyLength (4 bytes)
|
|
79
92
|
const messageKeyLengthView = new DataView(packedData, 0, 4);
|
|
80
93
|
const messageKeyLength = messageKeyLengthView.getUint32(0, false);
|
|
@@ -90,12 +103,26 @@ export class MessageFramePacker<T extends MessageKeyTypeBase> {
|
|
|
90
103
|
|
|
91
104
|
// [3] payload (variable length)
|
|
92
105
|
const payloadBinary = packedData.slice(4 + messageKeyLength + 1);
|
|
93
|
-
const payload =
|
|
106
|
+
const payload = this.deserializePayload(payloadBinary, payloadType);
|
|
94
107
|
|
|
95
108
|
return { messageKey, payload };
|
|
96
109
|
}
|
|
97
110
|
|
|
98
|
-
private
|
|
111
|
+
private isFastPathPayload(payload: PayloadType): boolean {
|
|
112
|
+
if (payload == null) {
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
const payloadType = typeof payload;
|
|
116
|
+
if (payloadType === 'string' || payloadType === 'number') {
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
if (payloadType === 'object' && payload.constructor === Object) {
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private payloadToUint8Array(payload: PayloadType): Uint8Array {
|
|
99
126
|
if (payload instanceof Uint8Array) {
|
|
100
127
|
return payload;
|
|
101
128
|
} else if (typeof payload === 'string') {
|
|
@@ -112,16 +139,46 @@ export class MessageFramePacker<T extends MessageKeyTypeBase> {
|
|
|
112
139
|
} else if (payload instanceof ArrayBuffer) {
|
|
113
140
|
return new Uint8Array(payload);
|
|
114
141
|
} else if (payload instanceof Blob) {
|
|
115
|
-
|
|
142
|
+
throw new Error('Blob is not supported in this callsite.');
|
|
116
143
|
} else {
|
|
117
144
|
return this.textEncoder.encode(JSON.stringify(payload));
|
|
118
145
|
}
|
|
119
146
|
}
|
|
120
147
|
|
|
121
|
-
private
|
|
148
|
+
private packImpl(
|
|
149
|
+
{ messageKey, payload }: MessageFrame<T>,
|
|
150
|
+
payloadType: PayloadTypeIndicator | undefined
|
|
151
|
+
): Promise<Uint8Array> | Uint8Array {
|
|
152
|
+
const messageKeyString = JSON.stringify(messageKey);
|
|
153
|
+
const messageKeyBytes = this.textEncoder.encode(messageKeyString);
|
|
154
|
+
const messageKeyLength = messageKeyBytes.length;
|
|
155
|
+
const payloadBinary = this.payloadToUint8Array(payload);
|
|
156
|
+
|
|
157
|
+
const totalLength = 4 + messageKeyLength + 1 + payloadBinary.byteLength;
|
|
158
|
+
const buffer = new ArrayBuffer(totalLength);
|
|
159
|
+
const packedArray = new Uint8Array(buffer);
|
|
160
|
+
|
|
161
|
+
// [0] messageKeyLength (4 bytes)
|
|
162
|
+
const messageKeyLengthView = new DataView(buffer, 0, 4);
|
|
163
|
+
messageKeyLengthView.setUint32(0, messageKeyLength, false);
|
|
164
|
+
|
|
165
|
+
// [1] messageKey (variable length)
|
|
166
|
+
packedArray.set(messageKeyBytes, 4);
|
|
167
|
+
|
|
168
|
+
// [2] payloadTypeIndicator (1 byte)
|
|
169
|
+
const payloadTypeView = new DataView(buffer, 4 + messageKeyLength, 1);
|
|
170
|
+
payloadTypeView.setUint8(0, payloadType ?? MessageFramePacker.getPayloadTypeIndicator(payload));
|
|
171
|
+
|
|
172
|
+
// [3] payload (variable length)
|
|
173
|
+
packedArray.set(payloadBinary, 4 + messageKeyLength + 1);
|
|
174
|
+
|
|
175
|
+
return packedArray;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
private deserializePayload(
|
|
122
179
|
payloadBinary: ArrayBuffer,
|
|
123
180
|
payloadTypeIndicator: PayloadTypeIndicator
|
|
124
|
-
):
|
|
181
|
+
): PayloadType {
|
|
125
182
|
switch (payloadTypeIndicator) {
|
|
126
183
|
case PayloadTypeIndicator.Uint8Array: {
|
|
127
184
|
return new Uint8Array(payloadBinary);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A transport protocol version between the app and the webui.
|
|
3
|
+
* It shows a warning in handshaking stage if the version is different between the app and the webui.
|
|
4
|
+
* The value should be increased when the protocol is changed.
|
|
5
|
+
*/
|
|
6
|
+
export const PROTOCOL_VERSION = 1;
|
|
@@ -12,6 +12,8 @@ globalThis.WebSocket = MockWebSocket;
|
|
|
12
12
|
globalThis.TextDecoder ??= TextDecoder;
|
|
13
13
|
globalThis.TextEncoder ??= TextEncoder;
|
|
14
14
|
|
|
15
|
+
const TEST_PROTOCOL_VERSION = 1;
|
|
16
|
+
|
|
15
17
|
describe(`DevToolsPluginClient`, () => {
|
|
16
18
|
let appClient: DevToolsPluginClient;
|
|
17
19
|
let testCaseCounter = 0;
|
|
@@ -23,6 +25,7 @@ describe(`DevToolsPluginClient`, () => {
|
|
|
23
25
|
testCaseCounter += 1;
|
|
24
26
|
devServer = `localhost:${8000 + testCaseCounter}`;
|
|
25
27
|
appClient = await createDevToolsPluginClient({
|
|
28
|
+
protocolVersion: TEST_PROTOCOL_VERSION,
|
|
26
29
|
devServer,
|
|
27
30
|
sender: 'app',
|
|
28
31
|
pluginName,
|
|
@@ -62,12 +65,14 @@ describe(`DevToolsPluginClient (browser <> app)`, () => {
|
|
|
62
65
|
const message = { foo: 'bar' };
|
|
63
66
|
|
|
64
67
|
appClient = await createDevToolsPluginClient({
|
|
68
|
+
protocolVersion: TEST_PROTOCOL_VERSION,
|
|
65
69
|
devServer,
|
|
66
70
|
sender: 'app',
|
|
67
71
|
pluginName,
|
|
68
72
|
wsStore: new WebSocketBackingStore(),
|
|
69
73
|
});
|
|
70
74
|
browserClient = await createDevToolsPluginClient({
|
|
75
|
+
protocolVersion: TEST_PROTOCOL_VERSION,
|
|
71
76
|
devServer,
|
|
72
77
|
sender: 'browser',
|
|
73
78
|
pluginName,
|
|
@@ -87,12 +92,14 @@ describe(`DevToolsPluginClient (browser <> app)`, () => {
|
|
|
87
92
|
|
|
88
93
|
it('should support ping-pong messages', async () => {
|
|
89
94
|
appClient = await createDevToolsPluginClient({
|
|
95
|
+
protocolVersion: TEST_PROTOCOL_VERSION,
|
|
90
96
|
devServer,
|
|
91
97
|
sender: 'app',
|
|
92
98
|
pluginName,
|
|
93
99
|
wsStore: new WebSocketBackingStore(),
|
|
94
100
|
});
|
|
95
101
|
browserClient = await createDevToolsPluginClient({
|
|
102
|
+
protocolVersion: TEST_PROTOCOL_VERSION,
|
|
96
103
|
devServer,
|
|
97
104
|
sender: 'browser',
|
|
98
105
|
pluginName,
|
|
@@ -123,12 +130,14 @@ describe(`DevToolsPluginClient (browser <> app)`, () => {
|
|
|
123
130
|
const message = { foo: 'bar' };
|
|
124
131
|
|
|
125
132
|
appClient = await createDevToolsPluginClient({
|
|
133
|
+
protocolVersion: TEST_PROTOCOL_VERSION,
|
|
126
134
|
devServer,
|
|
127
135
|
sender: 'app',
|
|
128
136
|
pluginName,
|
|
129
137
|
wsStore: new WebSocketBackingStore(),
|
|
130
138
|
});
|
|
131
139
|
browserClient = await createDevToolsPluginClient({
|
|
140
|
+
protocolVersion: TEST_PROTOCOL_VERSION,
|
|
132
141
|
devServer,
|
|
133
142
|
sender: 'browser',
|
|
134
143
|
pluginName: 'pluginB',
|
|
@@ -149,6 +158,7 @@ describe(`DevToolsPluginClient (browser <> app)`, () => {
|
|
|
149
158
|
const method = 'testMethod';
|
|
150
159
|
|
|
151
160
|
appClient = await createDevToolsPluginClient({
|
|
161
|
+
protocolVersion: TEST_PROTOCOL_VERSION,
|
|
152
162
|
devServer,
|
|
153
163
|
sender: 'app',
|
|
154
164
|
pluginName,
|
|
@@ -160,6 +170,7 @@ describe(`DevToolsPluginClient (browser <> app)`, () => {
|
|
|
160
170
|
});
|
|
161
171
|
|
|
162
172
|
browserClient = await createDevToolsPluginClient({
|
|
173
|
+
protocolVersion: TEST_PROTOCOL_VERSION,
|
|
163
174
|
devServer,
|
|
164
175
|
sender: 'browser',
|
|
165
176
|
pluginName,
|
|
@@ -168,6 +179,7 @@ describe(`DevToolsPluginClient (browser <> app)`, () => {
|
|
|
168
179
|
|
|
169
180
|
await delayAsync(100);
|
|
170
181
|
const browserClient2 = await createDevToolsPluginClient({
|
|
182
|
+
protocolVersion: TEST_PROTOCOL_VERSION,
|
|
171
183
|
devServer,
|
|
172
184
|
sender: 'browser',
|
|
173
185
|
pluginName,
|
|
@@ -185,6 +197,34 @@ describe(`DevToolsPluginClient (browser <> app)`, () => {
|
|
|
185
197
|
expect(receivedMessages[0]).toEqual({ from: 'browserClient2' });
|
|
186
198
|
await browserClient2.closeAsync();
|
|
187
199
|
});
|
|
200
|
+
|
|
201
|
+
it('should terminate client from incompatible protocol version', async () => {
|
|
202
|
+
const spyConsoleInfo = jest.spyOn(console, 'info').mockImplementation(() => {});
|
|
203
|
+
const spyConsoleWarn = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
204
|
+
appClient = await createDevToolsPluginClient({
|
|
205
|
+
protocolVersion: TEST_PROTOCOL_VERSION,
|
|
206
|
+
devServer,
|
|
207
|
+
sender: 'app',
|
|
208
|
+
pluginName,
|
|
209
|
+
wsStore: new WebSocketBackingStore(),
|
|
210
|
+
});
|
|
211
|
+
browserClient = await createDevToolsPluginClient({
|
|
212
|
+
protocolVersion: -1,
|
|
213
|
+
devServer,
|
|
214
|
+
sender: 'browser',
|
|
215
|
+
pluginName,
|
|
216
|
+
wsStore: new WebSocketBackingStore(),
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
await delayAsync(100);
|
|
220
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
|
221
|
+
`Received an incompatible devtools plugin handshake message - pluginName[${pluginName}]`
|
|
222
|
+
);
|
|
223
|
+
expect(browserClient.isConnected()).toBe(false);
|
|
224
|
+
|
|
225
|
+
spyConsoleInfo.mockRestore();
|
|
226
|
+
spyConsoleWarn.mockRestore();
|
|
227
|
+
});
|
|
188
228
|
});
|
|
189
229
|
|
|
190
230
|
describe(`DevToolsPluginClient - multiplexing`, () => {
|
|
@@ -200,12 +240,14 @@ describe(`DevToolsPluginClient - multiplexing`, () => {
|
|
|
200
240
|
it('should not close the websocket connection while there are alive clients', async () => {
|
|
201
241
|
const wsStore = new WebSocketBackingStore();
|
|
202
242
|
const appClient1 = await createDevToolsPluginClient({
|
|
243
|
+
protocolVersion: TEST_PROTOCOL_VERSION,
|
|
203
244
|
devServer,
|
|
204
245
|
sender: 'app',
|
|
205
246
|
pluginName: 'plugin1',
|
|
206
247
|
wsStore,
|
|
207
248
|
});
|
|
208
249
|
const appClient2 = await createDevToolsPluginClient({
|
|
250
|
+
protocolVersion: TEST_PROTOCOL_VERSION,
|
|
209
251
|
devServer,
|
|
210
252
|
sender: 'app',
|
|
211
253
|
pluginName: 'plugin2',
|
|
@@ -18,6 +18,8 @@ globalThis.WebSocket = MockWebSocket;
|
|
|
18
18
|
globalThis.TextDecoder ??= TextDecoder;
|
|
19
19
|
globalThis.TextEncoder ??= TextEncoder;
|
|
20
20
|
|
|
21
|
+
const TEST_PROTOCOL_VERSION = 1;
|
|
22
|
+
|
|
21
23
|
describe(getDevToolsPluginClientAsync, () => {
|
|
22
24
|
const mockGetConnectionInfo = getConnectionInfo as jest.MockedFunction<typeof getConnectionInfo>;
|
|
23
25
|
|
|
@@ -28,6 +30,7 @@ describe(getDevToolsPluginClientAsync, () => {
|
|
|
28
30
|
|
|
29
31
|
it('should return a DevToolsPluginClientImplApp client when sender is from app', async () => {
|
|
30
32
|
mockGetConnectionInfo.mockReturnValue({
|
|
33
|
+
protocolVersion: TEST_PROTOCOL_VERSION,
|
|
31
34
|
sender: 'app',
|
|
32
35
|
devServer: 'localhost:8081',
|
|
33
36
|
});
|
|
@@ -37,6 +40,7 @@ describe(getDevToolsPluginClientAsync, () => {
|
|
|
37
40
|
|
|
38
41
|
it('should return a DevToolsPluginClientImplApp client when sender is from browser', async () => {
|
|
39
42
|
mockGetConnectionInfo.mockReturnValue({
|
|
43
|
+
protocolVersion: TEST_PROTOCOL_VERSION,
|
|
40
44
|
sender: 'browser',
|
|
41
45
|
devServer: 'localhost:8081',
|
|
42
46
|
});
|
|
@@ -46,6 +50,7 @@ describe(getDevToolsPluginClientAsync, () => {
|
|
|
46
50
|
|
|
47
51
|
it('should return the same client from the same plugin name when called multiple times', async () => {
|
|
48
52
|
mockGetConnectionInfo.mockReturnValue({
|
|
53
|
+
protocolVersion: TEST_PROTOCOL_VERSION,
|
|
49
54
|
sender: 'app',
|
|
50
55
|
devServer: 'localhost:8081',
|
|
51
56
|
});
|
|
@@ -58,6 +63,7 @@ describe(getDevToolsPluginClientAsync, () => {
|
|
|
58
63
|
|
|
59
64
|
it('should return a new client from the same plugin name from disconnected', async () => {
|
|
60
65
|
mockGetConnectionInfo.mockReturnValue({
|
|
66
|
+
protocolVersion: TEST_PROTOCOL_VERSION,
|
|
61
67
|
sender: 'app',
|
|
62
68
|
devServer: 'localhost:8081',
|
|
63
69
|
});
|
|
@@ -73,12 +79,14 @@ describe(getDevToolsPluginClientAsync, () => {
|
|
|
73
79
|
const pluginName = 'testPlugin';
|
|
74
80
|
|
|
75
81
|
mockGetConnectionInfo.mockReturnValueOnce({
|
|
82
|
+
protocolVersion: TEST_PROTOCOL_VERSION,
|
|
76
83
|
sender: 'app',
|
|
77
84
|
devServer: 'localhost:8081',
|
|
78
85
|
});
|
|
79
86
|
const client = await getDevToolsPluginClientAsync(pluginName);
|
|
80
87
|
|
|
81
88
|
mockGetConnectionInfo.mockReturnValueOnce({
|
|
89
|
+
protocolVersion: TEST_PROTOCOL_VERSION,
|
|
82
90
|
sender: 'app',
|
|
83
91
|
devServer: 'localhost:8082',
|
|
84
92
|
});
|
|
@@ -89,6 +97,7 @@ describe(getDevToolsPluginClientAsync, () => {
|
|
|
89
97
|
|
|
90
98
|
it('should have at most one client per plugin name', async () => {
|
|
91
99
|
mockGetConnectionInfo.mockReturnValue({
|
|
100
|
+
protocolVersion: TEST_PROTOCOL_VERSION,
|
|
92
101
|
sender: 'app',
|
|
93
102
|
devServer: 'localhost:8081',
|
|
94
103
|
});
|
|
@@ -13,8 +13,11 @@ describe(MessageFramePacker, () => {
|
|
|
13
13
|
payload: 'testPayload',
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
const packedData =
|
|
17
|
-
|
|
16
|
+
const packedData = packer.pack(messageFrame);
|
|
17
|
+
if (packedData instanceof Promise || packedData instanceof Uint8Array) {
|
|
18
|
+
throw new Error('Unexpected packed data type');
|
|
19
|
+
}
|
|
20
|
+
const unpackedData = packer.unpack(packedData);
|
|
18
21
|
expect(unpackedData).toEqual(messageFrame);
|
|
19
22
|
});
|
|
20
23
|
|
|
@@ -24,8 +27,11 @@ describe(MessageFramePacker, () => {
|
|
|
24
27
|
payload: 12345,
|
|
25
28
|
};
|
|
26
29
|
|
|
27
|
-
const packedData =
|
|
28
|
-
|
|
30
|
+
const packedData = packer.pack(messageFrame);
|
|
31
|
+
if (packedData instanceof Promise || packedData instanceof Uint8Array) {
|
|
32
|
+
throw new Error('Unexpected packed data type');
|
|
33
|
+
}
|
|
34
|
+
const unpackedData = packer.unpack(packedData);
|
|
29
35
|
expect(unpackedData).toEqual(messageFrame);
|
|
30
36
|
});
|
|
31
37
|
|
|
@@ -35,8 +41,11 @@ describe(MessageFramePacker, () => {
|
|
|
35
41
|
payload: null,
|
|
36
42
|
};
|
|
37
43
|
|
|
38
|
-
const packedData =
|
|
39
|
-
|
|
44
|
+
const packedData = packer.pack(messageFrame);
|
|
45
|
+
if (packedData instanceof Promise || packedData instanceof Uint8Array) {
|
|
46
|
+
throw new Error('Unexpected packed data type');
|
|
47
|
+
}
|
|
48
|
+
const unpackedData = packer.unpack(packedData);
|
|
40
49
|
expect(unpackedData).toEqual(messageFrame);
|
|
41
50
|
});
|
|
42
51
|
|
|
@@ -45,8 +54,11 @@ describe(MessageFramePacker, () => {
|
|
|
45
54
|
messageKey: 'testKey',
|
|
46
55
|
};
|
|
47
56
|
|
|
48
|
-
const packedData =
|
|
49
|
-
|
|
57
|
+
const packedData = packer.pack(messageFrame);
|
|
58
|
+
if (packedData instanceof Promise || packedData instanceof Uint8Array) {
|
|
59
|
+
throw new Error('Unexpected packed data type');
|
|
60
|
+
}
|
|
61
|
+
const unpackedData = packer.unpack(packedData);
|
|
50
62
|
expect(unpackedData).toEqual(messageFrame);
|
|
51
63
|
});
|
|
52
64
|
|
|
@@ -56,8 +68,11 @@ describe(MessageFramePacker, () => {
|
|
|
56
68
|
payload: { key: 'value' },
|
|
57
69
|
};
|
|
58
70
|
|
|
59
|
-
const packedData =
|
|
60
|
-
|
|
71
|
+
const packedData = packer.pack(messageFrame);
|
|
72
|
+
if (packedData instanceof Promise || packedData instanceof Uint8Array) {
|
|
73
|
+
throw new Error('Unexpected packed data type');
|
|
74
|
+
}
|
|
75
|
+
const unpackedData = packer.unpack(packedData);
|
|
61
76
|
expect(unpackedData).toEqual(messageFrame);
|
|
62
77
|
});
|
|
63
78
|
|
|
@@ -67,8 +82,11 @@ describe(MessageFramePacker, () => {
|
|
|
67
82
|
payload: new Uint8Array([1, 2, 3, 4]),
|
|
68
83
|
};
|
|
69
84
|
|
|
70
|
-
const packedData =
|
|
71
|
-
|
|
85
|
+
const packedData = packer.pack(messageFrame);
|
|
86
|
+
if (packedData instanceof Promise || typeof packedData === 'string') {
|
|
87
|
+
throw new Error('Unexpected packed data type');
|
|
88
|
+
}
|
|
89
|
+
const unpackedData = packer.unpack(packedData.buffer);
|
|
72
90
|
expect(unpackedData.messageKey).toEqual(messageFrame.messageKey);
|
|
73
91
|
expect(unpackedData.payload).toEqual(messageFrame.payload);
|
|
74
92
|
});
|
|
@@ -83,8 +101,11 @@ describe(MessageFramePacker, () => {
|
|
|
83
101
|
payload: buffer,
|
|
84
102
|
};
|
|
85
103
|
|
|
86
|
-
const packedData =
|
|
87
|
-
|
|
104
|
+
const packedData = packer.pack(messageFrame);
|
|
105
|
+
if (packedData instanceof Promise || typeof packedData === 'string') {
|
|
106
|
+
throw new Error('Unexpected packed data type');
|
|
107
|
+
}
|
|
108
|
+
const unpackedData = packer.unpack(packedData.buffer);
|
|
88
109
|
expect(unpackedData.messageKey).toEqual(messageFrame.messageKey);
|
|
89
110
|
expect(new Uint8Array(unpackedData.payload as ArrayBuffer)).toEqual(view);
|
|
90
111
|
});
|
|
@@ -97,8 +118,12 @@ describe(MessageFramePacker, () => {
|
|
|
97
118
|
payload: blob,
|
|
98
119
|
};
|
|
99
120
|
|
|
100
|
-
const
|
|
101
|
-
|
|
121
|
+
const packedDataPromise = packer.pack(messageFrame);
|
|
122
|
+
if (packedDataPromise instanceof Uint8Array || typeof packedDataPromise === 'string') {
|
|
123
|
+
throw new Error('Unexpected packed data type');
|
|
124
|
+
}
|
|
125
|
+
const packedData = await packedDataPromise;
|
|
126
|
+
const unpackedData = packer.unpack(packedData.buffer);
|
|
102
127
|
expect(unpackedData.messageKey).toEqual(messageFrame.messageKey);
|
|
103
128
|
const unpackedBlob = unpackedData.payload as Blob;
|
|
104
129
|
expect(await unpackedBlob.text()).toEqual(await blob.text());
|
|
@@ -111,8 +136,11 @@ describe(MessageFramePacker, () => {
|
|
|
111
136
|
payload: 'testPayload',
|
|
112
137
|
};
|
|
113
138
|
|
|
114
|
-
const packedData =
|
|
115
|
-
|
|
139
|
+
const packedData = packerWithObjectKey.pack(messageFrame);
|
|
140
|
+
if (packedData instanceof Promise || packedData instanceof Uint8Array) {
|
|
141
|
+
throw new Error('Unexpected packed data type');
|
|
142
|
+
}
|
|
143
|
+
const unpackedData = packerWithObjectKey.unpack(packedData);
|
|
116
144
|
expect(unpackedData).toEqual(messageFrame);
|
|
117
145
|
});
|
|
118
146
|
|
|
@@ -122,6 +150,8 @@ describe(MessageFramePacker, () => {
|
|
|
122
150
|
payload: () => {},
|
|
123
151
|
};
|
|
124
152
|
|
|
125
|
-
|
|
153
|
+
expect(() => {
|
|
154
|
+
packer.pack(messageFrame);
|
|
155
|
+
}).toThrow('Unsupported payload type');
|
|
126
156
|
});
|
|
127
157
|
});
|
|
@@ -21,15 +21,11 @@ export interface ConnectionInfo {
|
|
|
21
21
|
* @hidden
|
|
22
22
|
*/
|
|
23
23
|
wsStore?: WebSocketBackingStore;
|
|
24
|
-
}
|
|
25
24
|
|
|
26
|
-
/**
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
export interface HandshakeMessageParams {
|
|
31
|
-
browserClientId: string;
|
|
32
|
-
pluginName: string;
|
|
25
|
+
/**
|
|
26
|
+
* The transport protocol version between the app and the webui.
|
|
27
|
+
*/
|
|
28
|
+
protocolVersion: number;
|
|
33
29
|
}
|
|
34
30
|
|
|
35
31
|
/**
|
|
@@ -41,3 +37,14 @@ export interface DevToolsPluginClientOptions {
|
|
|
41
37
|
*/
|
|
42
38
|
websocketBinaryType?: 'arraybuffer' | 'blob';
|
|
43
39
|
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The handshake messages for the devtools plugin client.
|
|
43
|
+
* @hidden
|
|
44
|
+
*/
|
|
45
|
+
export interface HandshakeMessageParams {
|
|
46
|
+
protocolVersion: number;
|
|
47
|
+
pluginName: string;
|
|
48
|
+
method: 'handshake' | 'terminateBrowserClient';
|
|
49
|
+
browserClientId: string;
|
|
50
|
+
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Get the dev server address.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import { PROTOCOL_VERSION } from './ProtocolVersion';
|
|
5
6
|
import type { ConnectionInfo } from './devtools.types';
|
|
6
7
|
|
|
7
8
|
export function getConnectionInfo(): Omit<ConnectionInfo, 'pluginName'> {
|
|
@@ -10,6 +11,7 @@ export function getConnectionInfo(): Omit<ConnectionInfo, 'pluginName'> {
|
|
|
10
11
|
.url.replace(/^https?:\/\//, '')
|
|
11
12
|
.replace(/\/?$/, '') as string;
|
|
12
13
|
return {
|
|
14
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
13
15
|
sender: 'app',
|
|
14
16
|
devServer,
|
|
15
17
|
};
|
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
* Get the dev server address.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import { PROTOCOL_VERSION } from './ProtocolVersion';
|
|
5
6
|
import type { ConnectionInfo } from './devtools.types';
|
|
6
7
|
|
|
7
8
|
export function getConnectionInfo(): Omit<ConnectionInfo, 'pluginName'> {
|
|
8
9
|
const devServerQuery = new URLSearchParams(window.location.search).get('devServer');
|
|
9
10
|
const host = window.location.origin.replace(/^https?:\/\//, '');
|
|
10
11
|
return {
|
|
12
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
11
13
|
sender: 'browser',
|
|
12
14
|
devServer: devServerQuery || host,
|
|
13
15
|
};
|