@dxos/edge-client 0.6.11 → 0.6.12-main.5a87ad5
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/lib/browser/chunk-ZWJXA37R.mjs +113 -0
- package/dist/lib/browser/chunk-ZWJXA37R.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +57 -157
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +122 -0
- package/dist/lib/browser/testing/index.mjs.map +7 -0
- package/dist/lib/node/chunk-ANV2HBEH.cjs +136 -0
- package/dist/lib/node/chunk-ANV2HBEH.cjs.map +7 -0
- package/dist/lib/node/index.cjs +56 -154
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +152 -0
- package/dist/lib/node/testing/index.cjs.map +7 -0
- package/dist/lib/node-esm/chunk-HNVT57AU.mjs +115 -0
- package/dist/lib/node-esm/chunk-HNVT57AU.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +378 -0
- package/dist/lib/node-esm/index.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -0
- package/dist/lib/node-esm/testing/index.mjs +123 -0
- package/dist/lib/node-esm/testing/index.mjs.map +7 -0
- package/dist/types/src/defs.d.ts.map +1 -1
- package/dist/types/src/edge-client.d.ts +3 -2
- package/dist/types/src/edge-client.d.ts.map +1 -1
- package/dist/types/src/errors.d.ts +4 -1
- package/dist/types/src/errors.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/protocol.d.ts +2 -2
- package/dist/types/src/protocol.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +2 -0
- package/dist/types/src/testing/index.d.ts.map +1 -0
- package/dist/types/src/testing/test-utils.d.ts +20 -0
- package/dist/types/src/testing/test-utils.d.ts.map +1 -0
- package/package.json +26 -14
- package/src/defs.ts +2 -3
- package/src/edge-client.test.ts +11 -11
- package/src/edge-client.ts +17 -8
- package/src/errors.ts +8 -2
- package/src/index.ts +1 -0
- package/src/persistent-lifecycle.test.ts +2 -2
- package/src/protocol.test.ts +1 -2
- package/src/protocol.ts +2 -2
- package/src/testing/index.ts +5 -0
- package/src/testing/test-utils.ts +111 -0
- package/src/websocket.test.ts +5 -4
- package/dist/types/src/test-utils.d.ts +0 -11
- package/dist/types/src/test-utils.d.ts.map +0 -1
- package/src/test-utils.ts +0 -49
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// packages/core/mesh/edge-client/src/protocol.ts
|
|
2
|
+
import { invariant } from "@dxos/invariant";
|
|
3
|
+
import { buf, bufWkt } from "@dxos/protocols/buf";
|
|
4
|
+
import { MessageSchema } from "@dxos/protocols/buf/dxos/edge/messenger_pb";
|
|
5
|
+
import { bufferToArray } from "@dxos/util";
|
|
6
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/protocol.ts";
|
|
7
|
+
var getTypename = (typeName) => `type.googleapis.com/${typeName}`;
|
|
8
|
+
var Protocol = class {
|
|
9
|
+
constructor(types) {
|
|
10
|
+
this._typeRegistry = buf.createRegistry(...types);
|
|
11
|
+
}
|
|
12
|
+
get typeRegistry() {
|
|
13
|
+
return this._typeRegistry;
|
|
14
|
+
}
|
|
15
|
+
toJson(message) {
|
|
16
|
+
try {
|
|
17
|
+
return buf.toJson(MessageSchema, message, {
|
|
18
|
+
registry: this.typeRegistry
|
|
19
|
+
});
|
|
20
|
+
} catch (err) {
|
|
21
|
+
return {
|
|
22
|
+
type: this.getPayloadType(message)
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Return the payload with the given type.
|
|
28
|
+
*/
|
|
29
|
+
getPayload(message, type) {
|
|
30
|
+
invariant(message.payload, void 0, {
|
|
31
|
+
F: __dxlog_file,
|
|
32
|
+
L: 40,
|
|
33
|
+
S: this,
|
|
34
|
+
A: [
|
|
35
|
+
"message.payload",
|
|
36
|
+
""
|
|
37
|
+
]
|
|
38
|
+
});
|
|
39
|
+
const payloadTypename = this.getPayloadType(message);
|
|
40
|
+
if (type && type.typeName !== payloadTypename) {
|
|
41
|
+
throw new Error(`Unexpected payload type: ${payloadTypename}; expected ${type.typeName}`);
|
|
42
|
+
}
|
|
43
|
+
invariant(bufWkt.anyIs(message.payload, type), `Unexpected payload type: ${payloadTypename}}`, {
|
|
44
|
+
F: __dxlog_file,
|
|
45
|
+
L: 46,
|
|
46
|
+
S: this,
|
|
47
|
+
A: [
|
|
48
|
+
"bufWkt.anyIs(message.payload, type)",
|
|
49
|
+
"`Unexpected payload type: ${payloadTypename}}`"
|
|
50
|
+
]
|
|
51
|
+
});
|
|
52
|
+
const payload = bufWkt.anyUnpack(message.payload, this.typeRegistry);
|
|
53
|
+
invariant(payload, `Empty payload: ${payloadTypename}}`, {
|
|
54
|
+
F: __dxlog_file,
|
|
55
|
+
L: 48,
|
|
56
|
+
S: this,
|
|
57
|
+
A: [
|
|
58
|
+
"payload",
|
|
59
|
+
"`Empty payload: ${payloadTypename}}`"
|
|
60
|
+
]
|
|
61
|
+
});
|
|
62
|
+
return payload;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Get the payload type.
|
|
66
|
+
*/
|
|
67
|
+
getPayloadType(message) {
|
|
68
|
+
if (!message.payload) {
|
|
69
|
+
return void 0;
|
|
70
|
+
}
|
|
71
|
+
const [, type] = message.payload.typeUrl.split("/");
|
|
72
|
+
return type;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Create a packed message.
|
|
76
|
+
*/
|
|
77
|
+
createMessage(type, { source, target, payload, serviceId }) {
|
|
78
|
+
return buf.create(MessageSchema, {
|
|
79
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
80
|
+
source,
|
|
81
|
+
target,
|
|
82
|
+
serviceId,
|
|
83
|
+
payload: payload ? bufWkt.anyPack(type, buf.create(type, payload)) : void 0
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
var toUint8Array = async (data) => {
|
|
88
|
+
if (data instanceof Buffer) {
|
|
89
|
+
return bufferToArray(data);
|
|
90
|
+
}
|
|
91
|
+
if (data instanceof Blob) {
|
|
92
|
+
return new Uint8Array(await data.arrayBuffer());
|
|
93
|
+
}
|
|
94
|
+
throw new Error(`Unexpected datatype: ${data}`);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// packages/core/mesh/edge-client/src/defs.ts
|
|
98
|
+
import { bufWkt as bufWkt2 } from "@dxos/protocols/buf";
|
|
99
|
+
import { SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema } from "@dxos/protocols/buf/dxos/edge/messenger_pb";
|
|
100
|
+
var protocol = new Protocol([
|
|
101
|
+
SwarmRequestSchema,
|
|
102
|
+
SwarmResponseSchema,
|
|
103
|
+
TextMessageSchema,
|
|
104
|
+
bufWkt2.AnySchema
|
|
105
|
+
]);
|
|
106
|
+
|
|
107
|
+
export {
|
|
108
|
+
getTypename,
|
|
109
|
+
Protocol,
|
|
110
|
+
toUint8Array,
|
|
111
|
+
protocol
|
|
112
|
+
};
|
|
113
|
+
//# sourceMappingURL=chunk-ZWJXA37R.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/protocol.ts", "../../../src/defs.ts"],
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { invariant } from '@dxos/invariant';\nimport { buf, bufWkt } from '@dxos/protocols/buf';\nimport { type Message, MessageSchema, type PeerSchema } from '@dxos/protocols/buf/dxos/edge/messenger_pb';\nimport { bufferToArray } from '@dxos/util';\n\nexport type PeerData = buf.MessageInitShape<typeof PeerSchema>;\n\nexport const getTypename = (typeName: string) => `type.googleapis.com/${typeName}`;\n\n/**\n * NOTE: The type registry should be extended with all message types.\n */\nexport class Protocol {\n private readonly _typeRegistry: buf.Registry;\n\n constructor(types: buf.DescMessage[]) {\n this._typeRegistry = buf.createRegistry(...types);\n }\n\n get typeRegistry(): buf.Registry {\n return this._typeRegistry;\n }\n\n toJson(message: Message): any {\n try {\n return buf.toJson(MessageSchema, message, { registry: this.typeRegistry });\n } catch (err) {\n return { type: this.getPayloadType(message) };\n }\n }\n\n /**\n * Return the payload with the given type.\n */\n getPayload<Desc extends buf.DescMessage>(message: Message, type: Desc): buf.MessageShape<Desc> {\n invariant(message.payload);\n const payloadTypename = this.getPayloadType(message);\n if (type && type.typeName !== payloadTypename) {\n throw new Error(`Unexpected payload type: ${payloadTypename}; expected ${type.typeName}`);\n }\n\n invariant(bufWkt.anyIs(message.payload, type), `Unexpected payload type: ${payloadTypename}}`);\n const payload = bufWkt.anyUnpack(message.payload, this.typeRegistry) as buf.MessageShape<Desc>;\n invariant(payload, `Empty payload: ${payloadTypename}}`);\n return payload;\n }\n\n /**\n * Get the payload type.\n */\n getPayloadType(message: Message): string | undefined {\n if (!message.payload) {\n return undefined;\n }\n\n const [, type] = message.payload.typeUrl.split('/');\n return type;\n }\n\n /**\n * Create a packed message.\n */\n createMessage<Desc extends buf.DescMessage>(\n type: Desc,\n {\n source,\n target,\n payload,\n serviceId,\n }: {\n source?: PeerData;\n target?: PeerData[];\n payload?: buf.MessageInitShape<Desc>;\n serviceId?: string;\n },\n ) {\n return buf.create(MessageSchema, {\n timestamp: new Date().toISOString(),\n source,\n target,\n serviceId,\n payload: payload ? bufWkt.anyPack(type, buf.create(type, payload)) : undefined,\n });\n }\n}\n\n/**\n * Convert websocket data to Uint8Array.\n */\nexport const toUint8Array = async (data: any): Promise<Uint8Array> => {\n // Node.\n if (data instanceof Buffer) {\n return bufferToArray(data);\n }\n\n // Browser.\n if (data instanceof Blob) {\n return new Uint8Array(await (data as Blob).arrayBuffer());\n }\n\n throw new Error(`Unexpected datatype: ${data}`);\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { bufWkt } from '@dxos/protocols/buf';\nimport { SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema } from '@dxos/protocols/buf/dxos/edge/messenger_pb';\n\nimport { Protocol } from './protocol';\n\nexport const protocol = new Protocol([SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema, bufWkt.AnySchema]);\n"],
|
|
5
|
+
"mappings": ";AAIA,SAASA,iBAAiB;AAC1B,SAASC,KAAKC,cAAc;AAC5B,SAAuBC,qBAAsC;AAC7D,SAASC,qBAAqB;;AAIvB,IAAMC,cAAc,CAACC,aAAqB,uBAAuBA,QAAAA;AAKjE,IAAMC,WAAN,MAAMA;EAGXC,YAAYC,OAA0B;AACpC,SAAKC,gBAAgBT,IAAIU,eAAc,GAAIF,KAAAA;EAC7C;EAEA,IAAIG,eAA6B;AAC/B,WAAO,KAAKF;EACd;EAEAG,OAAOC,SAAuB;AAC5B,QAAI;AACF,aAAOb,IAAIY,OAAOV,eAAeW,SAAS;QAAEC,UAAU,KAAKH;MAAa,CAAA;IAC1E,SAASI,KAAK;AACZ,aAAO;QAAEC,MAAM,KAAKC,eAAeJ,OAAAA;MAAS;IAC9C;EACF;;;;EAKAK,WAAyCL,SAAkBG,MAAoC;AAC7FjB,cAAUc,QAAQM,SAAO,QAAA;;;;;;;;;AACzB,UAAMC,kBAAkB,KAAKH,eAAeJ,OAAAA;AAC5C,QAAIG,QAAQA,KAAKX,aAAae,iBAAiB;AAC7C,YAAM,IAAIC,MAAM,4BAA4BD,eAAAA,cAA6BJ,KAAKX,QAAQ,EAAE;IAC1F;AAEAN,cAAUE,OAAOqB,MAAMT,QAAQM,SAASH,IAAAA,GAAO,4BAA4BI,eAAAA,KAAkB;;;;;;;;;AAC7F,UAAMD,UAAUlB,OAAOsB,UAAUV,QAAQM,SAAS,KAAKR,YAAY;AACnEZ,cAAUoB,SAAS,kBAAkBC,eAAAA,KAAkB;;;;;;;;;AACvD,WAAOD;EACT;;;;EAKAF,eAAeJ,SAAsC;AACnD,QAAI,CAACA,QAAQM,SAAS;AACpB,aAAOK;IACT;AAEA,UAAM,CAAA,EAAGR,IAAAA,IAAQH,QAAQM,QAAQM,QAAQC,MAAM,GAAA;AAC/C,WAAOV;EACT;;;;EAKAW,cACEX,MACA,EACEY,QACAC,QACAV,SACAW,UAAS,GAOX;AACA,WAAO9B,IAAI+B,OAAO7B,eAAe;MAC/B8B,YAAW,oBAAIC,KAAAA,GAAOC,YAAW;MACjCN;MACAC;MACAC;MACAX,SAASA,UAAUlB,OAAOkC,QAAQnB,MAAMhB,IAAI+B,OAAOf,MAAMG,OAAAA,CAAAA,IAAYK;IACvE,CAAA;EACF;AACF;AAKO,IAAMY,eAAe,OAAOC,SAAAA;AAEjC,MAAIA,gBAAgBC,QAAQ;AAC1B,WAAOnC,cAAckC,IAAAA;EACvB;AAGA,MAAIA,gBAAgBE,MAAM;AACxB,WAAO,IAAIC,WAAW,MAAOH,KAAcI,YAAW,CAAA;EACxD;AAEA,QAAM,IAAIpB,MAAM,wBAAwBgB,IAAAA,EAAM;AAChD;;;ACrGA,SAASK,UAAAA,eAAc;AACvB,SAASC,oBAAoBC,qBAAqBC,yBAAyB;AAIpE,IAAMC,WAAW,IAAIC,SAAS;EAACC;EAAoBC;EAAqBC;EAAmBC,QAAOC;CAAU;",
|
|
6
|
+
"names": ["invariant", "buf", "bufWkt", "MessageSchema", "bufferToArray", "getTypename", "typeName", "Protocol", "constructor", "types", "_typeRegistry", "createRegistry", "typeRegistry", "toJson", "message", "registry", "err", "type", "getPayloadType", "getPayload", "payload", "payloadTypename", "Error", "anyIs", "anyUnpack", "undefined", "typeUrl", "split", "createMessage", "source", "target", "serviceId", "create", "timestamp", "Date", "toISOString", "anyPack", "toUint8Array", "data", "Buffer", "Blob", "Uint8Array", "arrayBuffer", "bufWkt", "SwarmRequestSchema", "SwarmResponseSchema", "TextMessageSchema", "protocol", "Protocol", "SwarmRequestSchema", "SwarmResponseSchema", "TextMessageSchema", "bufWkt", "AnySchema"]
|
|
7
|
+
}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Protocol,
|
|
3
|
+
getTypename,
|
|
4
|
+
protocol,
|
|
5
|
+
toUint8Array
|
|
6
|
+
} from "./chunk-ZWJXA37R.mjs";
|
|
7
|
+
|
|
1
8
|
// packages/core/mesh/edge-client/src/index.ts
|
|
2
9
|
export * from "@dxos/protocols/buf/dxos/edge/messenger_pb";
|
|
3
10
|
|
|
@@ -5,123 +12,19 @@ export * from "@dxos/protocols/buf/dxos/edge/messenger_pb";
|
|
|
5
12
|
import WebSocket from "isomorphic-ws";
|
|
6
13
|
import { Trigger, Event, scheduleTaskInterval, scheduleTask, TriggerState } from "@dxos/async";
|
|
7
14
|
import { Context, LifecycleState as LifecycleState2, Resource as Resource2 } from "@dxos/context";
|
|
8
|
-
import { invariant as invariant2 } from "@dxos/invariant";
|
|
9
15
|
import { log as log2 } from "@dxos/log";
|
|
10
|
-
import { buf
|
|
11
|
-
import { MessageSchema as MessageSchema2 } from "@dxos/protocols/buf/dxos/edge/messenger_pb";
|
|
12
|
-
|
|
13
|
-
// packages/core/mesh/edge-client/src/defs.ts
|
|
14
|
-
import { AnySchema } from "@bufbuild/protobuf/wkt";
|
|
15
|
-
import { SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema } from "@dxos/protocols/buf/dxos/edge/messenger_pb";
|
|
16
|
-
|
|
17
|
-
// packages/core/mesh/edge-client/src/protocol.ts
|
|
18
|
-
import { invariant } from "@dxos/invariant";
|
|
19
|
-
import { buf, bufWkt } from "@dxos/protocols/buf";
|
|
16
|
+
import { buf } from "@dxos/protocols/buf";
|
|
20
17
|
import { MessageSchema } from "@dxos/protocols/buf/dxos/edge/messenger_pb";
|
|
21
|
-
import { bufferToArray } from "@dxos/util";
|
|
22
|
-
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/protocol.ts";
|
|
23
|
-
var getTypename = (typeName) => `type.googleapis.com/${typeName}`;
|
|
24
|
-
var Protocol = class {
|
|
25
|
-
constructor(types) {
|
|
26
|
-
this._typeRegistry = buf.createRegistry(...types);
|
|
27
|
-
}
|
|
28
|
-
get typeRegistry() {
|
|
29
|
-
return this._typeRegistry;
|
|
30
|
-
}
|
|
31
|
-
toJson(message) {
|
|
32
|
-
try {
|
|
33
|
-
return buf.toJson(MessageSchema, message, {
|
|
34
|
-
registry: this.typeRegistry
|
|
35
|
-
});
|
|
36
|
-
} catch (err) {
|
|
37
|
-
return {
|
|
38
|
-
type: this.getPayloadType(message)
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Return the payload with the given type.
|
|
44
|
-
*/
|
|
45
|
-
getPayload(message, type) {
|
|
46
|
-
invariant(message.payload, void 0, {
|
|
47
|
-
F: __dxlog_file,
|
|
48
|
-
L: 40,
|
|
49
|
-
S: this,
|
|
50
|
-
A: [
|
|
51
|
-
"message.payload",
|
|
52
|
-
""
|
|
53
|
-
]
|
|
54
|
-
});
|
|
55
|
-
const payloadTypename = this.getPayloadType(message);
|
|
56
|
-
if (type && type.typeName !== payloadTypename) {
|
|
57
|
-
throw new Error(`Unexpected payload type: ${payloadTypename}; expected ${type.typeName}`);
|
|
58
|
-
}
|
|
59
|
-
invariant(bufWkt.anyIs(message.payload, type), `Unexpected payload type: ${payloadTypename}}`, {
|
|
60
|
-
F: __dxlog_file,
|
|
61
|
-
L: 46,
|
|
62
|
-
S: this,
|
|
63
|
-
A: [
|
|
64
|
-
"bufWkt.anyIs(message.payload, type)",
|
|
65
|
-
"`Unexpected payload type: ${payloadTypename}}`"
|
|
66
|
-
]
|
|
67
|
-
});
|
|
68
|
-
const payload = bufWkt.anyUnpack(message.payload, this.typeRegistry);
|
|
69
|
-
invariant(payload, `Empty payload: ${payloadTypename}}`, {
|
|
70
|
-
F: __dxlog_file,
|
|
71
|
-
L: 48,
|
|
72
|
-
S: this,
|
|
73
|
-
A: [
|
|
74
|
-
"payload",
|
|
75
|
-
"`Empty payload: ${payloadTypename}}`"
|
|
76
|
-
]
|
|
77
|
-
});
|
|
78
|
-
return payload;
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Get the payload type.
|
|
82
|
-
*/
|
|
83
|
-
getPayloadType(message) {
|
|
84
|
-
if (!message.payload) {
|
|
85
|
-
return void 0;
|
|
86
|
-
}
|
|
87
|
-
const [, type] = message.payload.typeUrl.split("/");
|
|
88
|
-
return type;
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Create a packed message.
|
|
92
|
-
*/
|
|
93
|
-
createMessage(type, { source, target, payload, serviceId }) {
|
|
94
|
-
return buf.create(MessageSchema, {
|
|
95
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
96
|
-
source,
|
|
97
|
-
target,
|
|
98
|
-
serviceId,
|
|
99
|
-
payload: payload ? bufWkt.anyPack(type, buf.create(type, payload)) : void 0
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
var toUint8Array = async (data) => {
|
|
104
|
-
if (data instanceof Buffer) {
|
|
105
|
-
return bufferToArray(data);
|
|
106
|
-
}
|
|
107
|
-
if (data instanceof Blob) {
|
|
108
|
-
return new Uint8Array(await data.arrayBuffer());
|
|
109
|
-
}
|
|
110
|
-
throw new Error(`Unexpected datatype: ${data}`);
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
// packages/core/mesh/edge-client/src/defs.ts
|
|
114
|
-
var protocol = new Protocol([
|
|
115
|
-
SwarmRequestSchema,
|
|
116
|
-
SwarmResponseSchema,
|
|
117
|
-
TextMessageSchema,
|
|
118
|
-
AnySchema
|
|
119
|
-
]);
|
|
120
18
|
|
|
121
19
|
// packages/core/mesh/edge-client/src/errors.ts
|
|
122
|
-
var
|
|
20
|
+
var EdgeConnectionClosedError = class extends Error {
|
|
21
|
+
constructor() {
|
|
22
|
+
super("Edge connection closed.");
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
var EdgeIdentityChangedError = class extends Error {
|
|
123
26
|
constructor() {
|
|
124
|
-
super("
|
|
27
|
+
super("Edge identity changed.");
|
|
125
28
|
}
|
|
126
29
|
};
|
|
127
30
|
|
|
@@ -136,7 +39,7 @@ function _ts_decorate(decorators, target, key, desc) {
|
|
|
136
39
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
137
40
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
138
41
|
}
|
|
139
|
-
var
|
|
42
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/persistent-lifecycle.ts";
|
|
140
43
|
var INIT_RESTART_DELAY = 100;
|
|
141
44
|
var DEFAULT_MAX_RESTART_DELAY = 5e3;
|
|
142
45
|
var PersistentLifecycle = class extends Resource {
|
|
@@ -157,7 +60,7 @@ var PersistentLifecycle = class extends Resource {
|
|
|
157
60
|
log.warn("Restart failed", {
|
|
158
61
|
err
|
|
159
62
|
}, {
|
|
160
|
-
F:
|
|
63
|
+
F: __dxlog_file,
|
|
161
64
|
L: 64,
|
|
162
65
|
S: this,
|
|
163
66
|
C: (f, a) => f(...a)
|
|
@@ -169,7 +72,7 @@ var PersistentLifecycle = class extends Resource {
|
|
|
169
72
|
log.warn("Start failed", {
|
|
170
73
|
err
|
|
171
74
|
}, {
|
|
172
|
-
F:
|
|
75
|
+
F: __dxlog_file,
|
|
173
76
|
L: 69,
|
|
174
77
|
S: this,
|
|
175
78
|
C: (f, a) => f(...a)
|
|
@@ -186,7 +89,7 @@ var PersistentLifecycle = class extends Resource {
|
|
|
186
89
|
log(`restarting in ${this._restartAfter}ms`, {
|
|
187
90
|
state: this._lifecycleState
|
|
188
91
|
}, {
|
|
189
|
-
F:
|
|
92
|
+
F: __dxlog_file,
|
|
190
93
|
L: 81,
|
|
191
94
|
S: this,
|
|
192
95
|
C: (f, a) => f(...a)
|
|
@@ -219,7 +122,7 @@ _ts_decorate([
|
|
|
219
122
|
], PersistentLifecycle.prototype, "scheduleRestart", null);
|
|
220
123
|
|
|
221
124
|
// packages/core/mesh/edge-client/src/edge-client.ts
|
|
222
|
-
var
|
|
125
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-client.ts";
|
|
223
126
|
var DEFAULT_TIMEOUT = 1e4;
|
|
224
127
|
var SIGNAL_KEEPALIVE_INTERVAL = 5e3;
|
|
225
128
|
var EdgeClient = class extends Resource2 {
|
|
@@ -229,6 +132,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
229
132
|
this._peerKey = _peerKey;
|
|
230
133
|
this._config = _config;
|
|
231
134
|
this.reconnect = new Event();
|
|
135
|
+
this.connected = new Event();
|
|
232
136
|
this._persistentLifecycle = new PersistentLifecycle({
|
|
233
137
|
start: async () => this._openWebSocket(),
|
|
234
138
|
stop: async () => this._closeWebSocket(),
|
|
@@ -239,7 +143,6 @@ var EdgeClient = class extends Resource2 {
|
|
|
239
143
|
this._ws = void 0;
|
|
240
144
|
this._keepaliveCtx = void 0;
|
|
241
145
|
this._heartBeatContext = void 0;
|
|
242
|
-
this._protocol = this._config.protocol ?? protocol;
|
|
243
146
|
}
|
|
244
147
|
// TODO(burdon): Attach logging.
|
|
245
148
|
get info() {
|
|
@@ -271,8 +174,8 @@ var EdgeClient = class extends Resource2 {
|
|
|
271
174
|
log2("opening...", {
|
|
272
175
|
info: this.info
|
|
273
176
|
}, {
|
|
274
|
-
F:
|
|
275
|
-
L:
|
|
177
|
+
F: __dxlog_file2,
|
|
178
|
+
L: 100,
|
|
276
179
|
S: this,
|
|
277
180
|
C: (f, a) => f(...a)
|
|
278
181
|
});
|
|
@@ -280,8 +183,8 @@ var EdgeClient = class extends Resource2 {
|
|
|
280
183
|
log2.warn("Error while opening connection", {
|
|
281
184
|
err
|
|
282
185
|
}, {
|
|
283
|
-
F:
|
|
284
|
-
L:
|
|
186
|
+
F: __dxlog_file2,
|
|
187
|
+
L: 102,
|
|
285
188
|
S: this,
|
|
286
189
|
C: (f, a) => f(...a)
|
|
287
190
|
});
|
|
@@ -294,8 +197,8 @@ var EdgeClient = class extends Resource2 {
|
|
|
294
197
|
log2("closing...", {
|
|
295
198
|
peerKey: this._peerKey
|
|
296
199
|
}, {
|
|
297
|
-
F:
|
|
298
|
-
L:
|
|
200
|
+
F: __dxlog_file2,
|
|
201
|
+
L: 110,
|
|
299
202
|
S: this,
|
|
300
203
|
C: (f, a) => f(...a)
|
|
301
204
|
});
|
|
@@ -306,16 +209,17 @@ var EdgeClient = class extends Resource2 {
|
|
|
306
209
|
this._ws = new WebSocket(url);
|
|
307
210
|
this._ws.onopen = () => {
|
|
308
211
|
log2("opened", this.info, {
|
|
309
|
-
F:
|
|
310
|
-
L:
|
|
212
|
+
F: __dxlog_file2,
|
|
213
|
+
L: 119,
|
|
311
214
|
S: this,
|
|
312
215
|
C: (f, a) => f(...a)
|
|
313
216
|
});
|
|
314
217
|
this._ready.wake();
|
|
218
|
+
this.connected.emit();
|
|
315
219
|
};
|
|
316
220
|
this._ws.onclose = () => {
|
|
317
221
|
log2("closed", this.info, {
|
|
318
|
-
F:
|
|
222
|
+
F: __dxlog_file2,
|
|
319
223
|
L: 124,
|
|
320
224
|
S: this,
|
|
321
225
|
C: (f, a) => f(...a)
|
|
@@ -327,7 +231,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
327
231
|
error: event.error,
|
|
328
232
|
info: event.message
|
|
329
233
|
}, {
|
|
330
|
-
F:
|
|
234
|
+
F: __dxlog_file2,
|
|
331
235
|
L: 128,
|
|
332
236
|
S: this,
|
|
333
237
|
C: (f, a) => f(...a)
|
|
@@ -340,12 +244,12 @@ var EdgeClient = class extends Resource2 {
|
|
|
340
244
|
return;
|
|
341
245
|
}
|
|
342
246
|
const data = await toUint8Array(event.data);
|
|
343
|
-
const message =
|
|
247
|
+
const message = buf.fromBinary(MessageSchema, data);
|
|
344
248
|
log2("received", {
|
|
345
249
|
peerKey: this._peerKey,
|
|
346
250
|
payload: protocol.getPayloadType(message)
|
|
347
251
|
}, {
|
|
348
|
-
F:
|
|
252
|
+
F: __dxlog_file2,
|
|
349
253
|
L: 141,
|
|
350
254
|
S: this,
|
|
351
255
|
C: (f, a) => f(...a)
|
|
@@ -359,7 +263,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
359
263
|
err,
|
|
360
264
|
payload: protocol.getPayloadType(message)
|
|
361
265
|
}, {
|
|
362
|
-
F:
|
|
266
|
+
F: __dxlog_file2,
|
|
363
267
|
L: 147,
|
|
364
268
|
S: this,
|
|
365
269
|
C: (f, a) => f(...a)
|
|
@@ -372,7 +276,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
372
276
|
timeout: this._config.timeout ?? DEFAULT_TIMEOUT
|
|
373
277
|
});
|
|
374
278
|
this._keepaliveCtx = new Context(void 0, {
|
|
375
|
-
F:
|
|
279
|
+
F: __dxlog_file2,
|
|
376
280
|
L: 154
|
|
377
281
|
});
|
|
378
282
|
scheduleTaskInterval(this._keepaliveCtx, async () => {
|
|
@@ -386,7 +290,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
386
290
|
return;
|
|
387
291
|
}
|
|
388
292
|
try {
|
|
389
|
-
this._ready.throw(new
|
|
293
|
+
this._ready.throw(this.isOpen ? new EdgeIdentityChangedError() : new EdgeConnectionClosedError());
|
|
390
294
|
this._ready.reset();
|
|
391
295
|
void this._keepaliveCtx?.dispose();
|
|
392
296
|
this._keepaliveCtx = void 0;
|
|
@@ -407,7 +311,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
407
311
|
log2.warn("Error closing websocket", {
|
|
408
312
|
err
|
|
409
313
|
}, {
|
|
410
|
-
F:
|
|
314
|
+
F: __dxlog_file2,
|
|
411
315
|
L: 190,
|
|
412
316
|
S: this,
|
|
413
317
|
C: (f, a) => f(...a)
|
|
@@ -420,38 +324,32 @@ var EdgeClient = class extends Resource2 {
|
|
|
420
324
|
*/
|
|
421
325
|
async send(message) {
|
|
422
326
|
if (this._ready.state !== TriggerState.RESOLVED) {
|
|
327
|
+
log2("waiting for websocket to become ready", void 0, {
|
|
328
|
+
F: __dxlog_file2,
|
|
329
|
+
L: 200,
|
|
330
|
+
S: this,
|
|
331
|
+
C: (f, a) => f(...a)
|
|
332
|
+
});
|
|
423
333
|
await this._ready.wait({
|
|
424
334
|
timeout: this._config.timeout ?? DEFAULT_TIMEOUT
|
|
425
335
|
});
|
|
426
336
|
}
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
""
|
|
434
|
-
]
|
|
435
|
-
});
|
|
436
|
-
invariant2(!message.source || message.source.peerKey === this._peerKey, void 0, {
|
|
437
|
-
F: __dxlog_file3,
|
|
438
|
-
L: 203,
|
|
439
|
-
S: this,
|
|
440
|
-
A: [
|
|
441
|
-
"!message.source || message.source.peerKey === this._peerKey",
|
|
442
|
-
""
|
|
443
|
-
]
|
|
444
|
-
});
|
|
337
|
+
if (!this._ws) {
|
|
338
|
+
throw new EdgeConnectionClosedError();
|
|
339
|
+
}
|
|
340
|
+
if (message.source && (message.source.peerKey !== this._peerKey || message.source.identityKey !== this.identityKey)) {
|
|
341
|
+
throw new EdgeIdentityChangedError();
|
|
342
|
+
}
|
|
445
343
|
log2("sending...", {
|
|
446
344
|
peerKey: this._peerKey,
|
|
447
345
|
payload: protocol.getPayloadType(message)
|
|
448
346
|
}, {
|
|
449
|
-
F:
|
|
450
|
-
L:
|
|
347
|
+
F: __dxlog_file2,
|
|
348
|
+
L: 213,
|
|
451
349
|
S: this,
|
|
452
350
|
C: (f, a) => f(...a)
|
|
453
351
|
});
|
|
454
|
-
this._ws.send(
|
|
352
|
+
this._ws.send(buf.toBinary(MessageSchema, message));
|
|
455
353
|
}
|
|
456
354
|
_onHeartbeat() {
|
|
457
355
|
if (this._lifecycleState !== LifecycleState2.OPEN) {
|
|
@@ -459,8 +357,8 @@ var EdgeClient = class extends Resource2 {
|
|
|
459
357
|
}
|
|
460
358
|
void this._heartBeatContext?.dispose();
|
|
461
359
|
this._heartBeatContext = new Context(void 0, {
|
|
462
|
-
F:
|
|
463
|
-
L:
|
|
360
|
+
F: __dxlog_file2,
|
|
361
|
+
L: 222
|
|
464
362
|
});
|
|
465
363
|
scheduleTask(this._heartBeatContext, () => {
|
|
466
364
|
this._persistentLifecycle.scheduleRestart();
|
|
@@ -469,6 +367,8 @@ var EdgeClient = class extends Resource2 {
|
|
|
469
367
|
};
|
|
470
368
|
export {
|
|
471
369
|
EdgeClient,
|
|
370
|
+
EdgeConnectionClosedError,
|
|
371
|
+
EdgeIdentityChangedError,
|
|
472
372
|
Protocol,
|
|
473
373
|
getTypename,
|
|
474
374
|
protocol,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../../src/index.ts", "../../../src/edge-client.ts", "../../../src/
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nexport * from '@dxos/protocols/buf/dxos/edge/messenger_pb';\n\nexport * from './edge-client';\nexport * from './defs';\nexport * from './protocol';\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport WebSocket from 'isomorphic-ws';\n\nimport { Trigger, Event, scheduleTaskInterval, scheduleTask, TriggerState } from '@dxos/async';\nimport { Context, LifecycleState, Resource, type Lifecycle } from '@dxos/context';\nimport { invariant } from '@dxos/invariant';\nimport { log } from '@dxos/log';\nimport { buf } from '@dxos/protocols/buf';\nimport { type Message, MessageSchema } from '@dxos/protocols/buf/dxos/edge/messenger_pb';\n\nimport { protocol } from './defs';\nimport { WebsocketClosedError } from './errors';\nimport { PersistentLifecycle } from './persistent-lifecycle';\nimport { type Protocol, toUint8Array } from './protocol';\n\nconst DEFAULT_TIMEOUT = 10_000;\nconst SIGNAL_KEEPALIVE_INTERVAL = 5_000;\n\nexport type MessageListener = (message: Message) => void | Promise<void>;\n\nexport interface EdgeConnection extends Required<Lifecycle> {\n reconnect: Event;\n\n get info(): any;\n get identityKey(): string;\n get peerKey(): string;\n get isOpen(): boolean;\n setIdentity(params: { peerKey: string; identityKey: string }): void;\n addListener(listener: MessageListener): () => void;\n send(message: Message): Promise<void>;\n}\n\nexport type MessengerConfig = {\n socketEndpoint: string;\n timeout?: number;\n protocol?: Protocol;\n};\n\n/**\n * Messenger client.\n */\nexport class EdgeClient extends Resource implements EdgeConnection {\n public reconnect = new Event();\n private readonly _persistentLifecycle = new PersistentLifecycle({\n start: async () => this._openWebSocket(),\n stop: async () => this._closeWebSocket(),\n onRestart: async () => this.reconnect.emit(),\n });\n\n private readonly _listeners = new Set<MessageListener>();\n private readonly _protocol: Protocol;\n private _ready = new Trigger();\n private _ws?: WebSocket = undefined;\n private _keepaliveCtx?: Context = undefined;\n private _heartBeatContext?: Context = undefined;\n\n constructor(\n private _identityKey: string,\n private _peerKey: string,\n private readonly _config: MessengerConfig,\n ) {\n super();\n this._protocol = this._config.protocol ?? protocol;\n }\n\n // TODO(burdon): Attach logging.\n public get info() {\n return {\n open: this.isOpen,\n identity: this._identityKey,\n device: this._peerKey,\n };\n }\n\n get identityKey() {\n return this._identityKey;\n }\n\n get peerKey() {\n return this._peerKey;\n }\n\n setIdentity({ peerKey, identityKey }: { peerKey: string; identityKey: string }) {\n this._peerKey = peerKey;\n this._identityKey = identityKey;\n this._persistentLifecycle.scheduleRestart();\n }\n\n public addListener(listener: MessageListener): () => void {\n this._listeners.add(listener);\n return () => this._listeners.delete(listener);\n }\n\n /**\n * Open connection to messaging service.\n */\n protected override async _open() {\n log('opening...', { info: this.info });\n this._persistentLifecycle.open().catch((err) => {\n log.warn('Error while opening connection', { err });\n });\n }\n\n /**\n * Close connection and free resources.\n */\n protected override async _close() {\n log('closing...', { peerKey: this._peerKey });\n await this._persistentLifecycle.close();\n }\n\n private async _openWebSocket() {\n const url = new URL(`/ws/${this._identityKey}/${this._peerKey}`, this._config.socketEndpoint);\n this._ws = new WebSocket(url);\n\n this._ws.onopen = () => {\n log('opened', this.info);\n this._ready.wake();\n };\n this._ws.onclose = () => {\n log('closed', this.info);\n this._persistentLifecycle.scheduleRestart();\n };\n this._ws.onerror = (event) => {\n log.warn('EdgeClient socket error', { error: event.error, info: event.message });\n this._persistentLifecycle.scheduleRestart();\n };\n /**\n * https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent/data\n */\n this._ws.onmessage = async (event) => {\n if (event.data === '__pong__') {\n this._onHeartbeat();\n return;\n }\n const data = await toUint8Array(event.data);\n const message = buf.fromBinary(MessageSchema, data);\n log('received', { peerKey: this._peerKey, payload: protocol.getPayloadType(message) });\n if (message) {\n for (const listener of this._listeners) {\n try {\n await listener(message);\n } catch (err) {\n log.error('processing', { err, payload: protocol.getPayloadType(message) });\n }\n }\n }\n };\n\n await this._ready.wait({ timeout: this._config.timeout ?? DEFAULT_TIMEOUT });\n this._keepaliveCtx = new Context();\n scheduleTaskInterval(\n this._keepaliveCtx,\n async () => {\n // TODO(mykola): use RFC6455 ping/pong once implemented in the browser?\n // Cloudflare's worker responds to this `without interrupting hibernation`. https://developers.cloudflare.com/durable-objects/api/websockets/#setwebsocketautoresponse\n this._ws?.send('__ping__');\n },\n SIGNAL_KEEPALIVE_INTERVAL,\n );\n this._ws.send('__ping__');\n this._onHeartbeat();\n }\n\n private async _closeWebSocket() {\n if (!this._ws) {\n return;\n }\n try {\n this._ready.throw(new WebsocketClosedError());\n this._ready.reset();\n void this._keepaliveCtx?.dispose();\n this._keepaliveCtx = undefined;\n void this._heartBeatContext?.dispose();\n this._heartBeatContext = undefined;\n\n // NOTE: Remove event handlers to avoid scheduling restart.\n this._ws.onopen = () => {};\n this._ws.onclose = () => {};\n this._ws.onerror = () => {};\n this._ws.close();\n this._ws = undefined;\n } catch (err) {\n if (err instanceof Error && err.message.includes('WebSocket is closed before the connection is established.')) {\n return;\n }\n log.warn('Error closing websocket', { err });\n }\n }\n\n /**\n * Send message.\n * NOTE: The message is guaranteed to be delivered but the service must respond with a message to confirm processing.\n */\n public async send(message: Message): Promise<void> {\n if (this._ready.state !== TriggerState.RESOLVED) {\n await this._ready.wait({ timeout: this._config.timeout ?? DEFAULT_TIMEOUT });\n }\n invariant(this._ws);\n invariant(!message.source || message.source.peerKey === this._peerKey);\n log('sending...', { peerKey: this._peerKey, payload: protocol.getPayloadType(message) });\n this._ws.send(buf.toBinary(MessageSchema, message));\n }\n\n private _onHeartbeat() {\n if (this._lifecycleState !== LifecycleState.OPEN) {\n return;\n }\n void this._heartBeatContext?.dispose();\n this._heartBeatContext = new Context();\n scheduleTask(\n this._heartBeatContext,\n () => {\n this._persistentLifecycle.scheduleRestart();\n },\n 2 * SIGNAL_KEEPALIVE_INTERVAL,\n );\n }\n}\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { AnySchema } from '@bufbuild/protobuf/wkt';\n\nimport { SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema } from '@dxos/protocols/buf/dxos/edge/messenger_pb';\n\nimport { Protocol } from './protocol';\n\nexport const protocol = new Protocol([SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema, AnySchema]);\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { invariant } from '@dxos/invariant';\nimport { buf, bufWkt } from '@dxos/protocols/buf';\nimport { type Message, MessageSchema, type Peer as PeerProto } from '@dxos/protocols/buf/dxos/edge/messenger_pb';\nimport { bufferToArray } from '@dxos/util';\n\nexport type PeerData = Partial<PeerProto>;\n\nexport const getTypename = (typeName: string) => `type.googleapis.com/${typeName}`;\n\n/**\n * NOTE: The type registry should be extended with all message types.\n */\nexport class Protocol {\n private readonly _typeRegistry: buf.Registry;\n\n constructor(types: buf.DescMessage[]) {\n this._typeRegistry = buf.createRegistry(...types);\n }\n\n get typeRegistry(): buf.Registry {\n return this._typeRegistry;\n }\n\n toJson(message: Message): any {\n try {\n return buf.toJson(MessageSchema, message, { registry: this.typeRegistry });\n } catch (err) {\n return { type: this.getPayloadType(message) };\n }\n }\n\n /**\n * Return the payload with the given type.\n */\n getPayload<Desc extends buf.DescMessage>(message: Message, type: Desc): buf.MessageShape<Desc> {\n invariant(message.payload);\n const payloadTypename = this.getPayloadType(message);\n if (type && type.typeName !== payloadTypename) {\n throw new Error(`Unexpected payload type: ${payloadTypename}; expected ${type.typeName}`);\n }\n\n invariant(bufWkt.anyIs(message.payload, type), `Unexpected payload type: ${payloadTypename}}`);\n const payload = bufWkt.anyUnpack(message.payload, this.typeRegistry) as buf.MessageShape<Desc>;\n invariant(payload, `Empty payload: ${payloadTypename}}`);\n return payload;\n }\n\n /**\n * Get the payload type.\n */\n getPayloadType(message: Message): string | undefined {\n if (!message.payload) {\n return undefined;\n }\n\n const [, type] = message.payload.typeUrl.split('/');\n return type;\n }\n\n /**\n * Create a packed message.\n */\n createMessage<Desc extends buf.DescMessage>(\n type: Desc,\n {\n source,\n target,\n payload,\n serviceId,\n }: {\n source?: PeerData;\n target?: PeerData[];\n payload?: buf.MessageInitShape<Desc>;\n serviceId?: string;\n },\n ) {\n return buf.create(MessageSchema, {\n timestamp: new Date().toISOString(),\n source,\n target,\n serviceId,\n payload: payload ? bufWkt.anyPack(type, buf.create(type, payload)) : undefined,\n });\n }\n}\n\n/**\n * Convert websocket data to Uint8Array.\n */\nexport const toUint8Array = async (data: any): Promise<Uint8Array> => {\n // Node.\n if (data instanceof Buffer) {\n return bufferToArray(data);\n }\n\n // Browser.\n if (data instanceof Blob) {\n return new Uint8Array(await (data as Blob).arrayBuffer());\n }\n\n throw new Error(`Unexpected datatype: ${data}`);\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nexport class WebsocketClosedError extends Error {\n constructor() {\n super('WebSocket connection closed');\n }\n}\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { DeferredTask, sleep, synchronized } from '@dxos/async';\nimport { cancelWithContext, LifecycleState, Resource } from '@dxos/context';\nimport { warnAfterTimeout } from '@dxos/debug';\nimport { log } from '@dxos/log';\n\nconst INIT_RESTART_DELAY = 100;\nconst DEFAULT_MAX_RESTART_DELAY = 5000;\n\nexport type PersistentLifecycleParams = {\n /**\n * Create connection.\n * If promise resolves successfully, connection is considered established.\n */\n start: () => Promise<void>;\n\n /**\n * Reset connection to initial state.\n */\n stop: () => Promise<void>;\n\n /**\n * Called after successful start.\n */\n onRestart?: () => Promise<void>;\n\n /**\n * Maximum delay between restartion attempts.\n * Default: 5000ms\n */\n maxRestartDelay?: number;\n};\n\n/**\n * Handles restarts (e.g. persists connection).\n * Restarts are scheduled with exponential backoff.\n */\nexport class PersistentLifecycle extends Resource {\n private readonly _start: () => Promise<void>;\n private readonly _stop: () => Promise<void>;\n private readonly _onRestart?: () => Promise<void>;\n private readonly _maxRestartDelay: number;\n\n private _restartTask?: DeferredTask = undefined;\n private _restartAfter = 0;\n\n constructor({ start, stop, onRestart, maxRestartDelay = DEFAULT_MAX_RESTART_DELAY }: PersistentLifecycleParams) {\n super();\n this._start = start;\n this._stop = stop;\n this._onRestart = onRestart;\n this._maxRestartDelay = maxRestartDelay;\n }\n\n @synchronized\n protected override async _open() {\n this._restartTask = new DeferredTask(this._ctx, async () => {\n try {\n await this._restart();\n } catch (err) {\n log.warn('Restart failed', { err });\n this._restartTask?.schedule();\n }\n });\n await this._start().catch((err) => {\n log.warn('Start failed', { err });\n this._restartTask?.schedule();\n });\n }\n\n protected override async _close() {\n await this._restartTask?.join();\n await this._stop();\n this._restartTask = undefined;\n }\n\n private async _restart() {\n log(`restarting in ${this._restartAfter}ms`, { state: this._lifecycleState });\n await this._stop();\n if (this._lifecycleState !== LifecycleState.OPEN) {\n return;\n }\n await cancelWithContext(this._ctx!, sleep(this._restartAfter));\n this._restartAfter = Math.min(Math.max(this._restartAfter * 2, INIT_RESTART_DELAY), this._maxRestartDelay);\n\n // May fail if the connection is not established.\n await warnAfterTimeout(5_000, 'Connection establishment takes too long', () => this._start());\n\n this._restartAfter = 0;\n await this._onRestart?.();\n }\n\n /**\n * Scheduling restart should be done from outside.\n */\n @synchronized\n scheduleRestart() {\n if (this._lifecycleState !== LifecycleState.OPEN) {\n return;\n }\n this._restartTask!.schedule();\n }\n}\n"],
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["WebSocket", "Trigger", "Event", "scheduleTaskInterval", "scheduleTask", "TriggerState", "Context", "LifecycleState", "Resource", "
|
|
3
|
+
"sources": ["../../../src/index.ts", "../../../src/edge-client.ts", "../../../src/errors.ts", "../../../src/persistent-lifecycle.ts"],
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nexport * from '@dxos/protocols/buf/dxos/edge/messenger_pb';\n\nexport * from './edge-client';\nexport * from './defs';\nexport * from './protocol';\nexport * from './errors';\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport WebSocket from 'isomorphic-ws';\n\nimport { Trigger, Event, scheduleTaskInterval, scheduleTask, TriggerState } from '@dxos/async';\nimport { Context, LifecycleState, Resource, type Lifecycle } from '@dxos/context';\nimport { log } from '@dxos/log';\nimport { buf } from '@dxos/protocols/buf';\nimport { type Message, MessageSchema } from '@dxos/protocols/buf/dxos/edge/messenger_pb';\n\nimport { protocol } from './defs';\nimport { EdgeConnectionClosedError, EdgeIdentityChangedError } from './errors';\nimport { PersistentLifecycle } from './persistent-lifecycle';\nimport { type Protocol, toUint8Array } from './protocol';\n\nconst DEFAULT_TIMEOUT = 10_000;\nconst SIGNAL_KEEPALIVE_INTERVAL = 5_000;\n\nexport type MessageListener = (message: Message) => void | Promise<void>;\n\nexport interface EdgeConnection extends Required<Lifecycle> {\n connected: Event;\n reconnect: Event;\n\n get info(): any;\n get identityKey(): string;\n get peerKey(): string;\n get isOpen(): boolean;\n setIdentity(params: { peerKey: string; identityKey: string }): void;\n addListener(listener: MessageListener): () => void;\n send(message: Message): Promise<void>;\n}\n\nexport type MessengerConfig = {\n socketEndpoint: string;\n timeout?: number;\n protocol?: Protocol;\n};\n\n/**\n * Messenger client.\n */\nexport class EdgeClient extends Resource implements EdgeConnection {\n public readonly reconnect = new Event();\n public readonly connected = new Event();\n private readonly _persistentLifecycle = new PersistentLifecycle({\n start: async () => this._openWebSocket(),\n stop: async () => this._closeWebSocket(),\n onRestart: async () => this.reconnect.emit(),\n });\n\n private readonly _listeners = new Set<MessageListener>();\n private _ready = new Trigger();\n private _ws?: WebSocket = undefined;\n private _keepaliveCtx?: Context = undefined;\n private _heartBeatContext?: Context = undefined;\n\n constructor(\n private _identityKey: string,\n private _peerKey: string,\n private readonly _config: MessengerConfig,\n ) {\n super();\n }\n\n // TODO(burdon): Attach logging.\n public get info() {\n return {\n open: this.isOpen,\n identity: this._identityKey,\n device: this._peerKey,\n };\n }\n\n get identityKey() {\n return this._identityKey;\n }\n\n get peerKey() {\n return this._peerKey;\n }\n\n setIdentity({ peerKey, identityKey }: { peerKey: string; identityKey: string }) {\n this._peerKey = peerKey;\n this._identityKey = identityKey;\n this._persistentLifecycle.scheduleRestart();\n }\n\n public addListener(listener: MessageListener): () => void {\n this._listeners.add(listener);\n return () => this._listeners.delete(listener);\n }\n\n /**\n * Open connection to messaging service.\n */\n protected override async _open() {\n log('opening...', { info: this.info });\n this._persistentLifecycle.open().catch((err) => {\n log.warn('Error while opening connection', { err });\n });\n }\n\n /**\n * Close connection and free resources.\n */\n protected override async _close() {\n log('closing...', { peerKey: this._peerKey });\n await this._persistentLifecycle.close();\n }\n\n private async _openWebSocket() {\n const url = new URL(`/ws/${this._identityKey}/${this._peerKey}`, this._config.socketEndpoint);\n this._ws = new WebSocket(url);\n\n this._ws.onopen = () => {\n log('opened', this.info);\n this._ready.wake();\n this.connected.emit();\n };\n this._ws.onclose = () => {\n log('closed', this.info);\n this._persistentLifecycle.scheduleRestart();\n };\n this._ws.onerror = (event) => {\n log.warn('EdgeClient socket error', { error: event.error, info: event.message });\n this._persistentLifecycle.scheduleRestart();\n };\n /**\n * https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent/data\n */\n this._ws.onmessage = async (event) => {\n if (event.data === '__pong__') {\n this._onHeartbeat();\n return;\n }\n const data = await toUint8Array(event.data);\n const message = buf.fromBinary(MessageSchema, data);\n log('received', { peerKey: this._peerKey, payload: protocol.getPayloadType(message) });\n if (message) {\n for (const listener of this._listeners) {\n try {\n await listener(message);\n } catch (err) {\n log.error('processing', { err, payload: protocol.getPayloadType(message) });\n }\n }\n }\n };\n\n await this._ready.wait({ timeout: this._config.timeout ?? DEFAULT_TIMEOUT });\n this._keepaliveCtx = new Context();\n scheduleTaskInterval(\n this._keepaliveCtx,\n async () => {\n // TODO(mykola): use RFC6455 ping/pong once implemented in the browser?\n // Cloudflare's worker responds to this `without interrupting hibernation`. https://developers.cloudflare.com/durable-objects/api/websockets/#setwebsocketautoresponse\n this._ws?.send('__ping__');\n },\n SIGNAL_KEEPALIVE_INTERVAL,\n );\n this._ws.send('__ping__');\n this._onHeartbeat();\n }\n\n private async _closeWebSocket() {\n if (!this._ws) {\n return;\n }\n try {\n this._ready.throw(this.isOpen ? new EdgeIdentityChangedError() : new EdgeConnectionClosedError());\n this._ready.reset();\n void this._keepaliveCtx?.dispose();\n this._keepaliveCtx = undefined;\n void this._heartBeatContext?.dispose();\n this._heartBeatContext = undefined;\n\n // NOTE: Remove event handlers to avoid scheduling restart.\n this._ws.onopen = () => {};\n this._ws.onclose = () => {};\n this._ws.onerror = () => {};\n this._ws.close();\n this._ws = undefined;\n } catch (err) {\n if (err instanceof Error && err.message.includes('WebSocket is closed before the connection is established.')) {\n return;\n }\n log.warn('Error closing websocket', { err });\n }\n }\n\n /**\n * Send message.\n * NOTE: The message is guaranteed to be delivered but the service must respond with a message to confirm processing.\n */\n public async send(message: Message): Promise<void> {\n if (this._ready.state !== TriggerState.RESOLVED) {\n log('waiting for websocket to become ready');\n await this._ready.wait({ timeout: this._config.timeout ?? DEFAULT_TIMEOUT });\n }\n if (!this._ws) {\n throw new EdgeConnectionClosedError();\n }\n if (\n message.source &&\n (message.source.peerKey !== this._peerKey || message.source.identityKey !== this.identityKey)\n ) {\n throw new EdgeIdentityChangedError();\n }\n\n log('sending...', { peerKey: this._peerKey, payload: protocol.getPayloadType(message) });\n this._ws.send(buf.toBinary(MessageSchema, message));\n }\n\n private _onHeartbeat() {\n if (this._lifecycleState !== LifecycleState.OPEN) {\n return;\n }\n void this._heartBeatContext?.dispose();\n this._heartBeatContext = new Context();\n scheduleTask(\n this._heartBeatContext,\n () => {\n this._persistentLifecycle.scheduleRestart();\n },\n 2 * SIGNAL_KEEPALIVE_INTERVAL,\n );\n }\n}\n", "//\n// Copyright 2024 DXOS.org\n//\n\nexport class EdgeConnectionClosedError extends Error {\n constructor() {\n super('Edge connection closed.');\n }\n}\n\nexport class EdgeIdentityChangedError extends Error {\n constructor() {\n super('Edge identity changed.');\n }\n}\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { DeferredTask, sleep, synchronized } from '@dxos/async';\nimport { cancelWithContext, LifecycleState, Resource } from '@dxos/context';\nimport { warnAfterTimeout } from '@dxos/debug';\nimport { log } from '@dxos/log';\n\nconst INIT_RESTART_DELAY = 100;\nconst DEFAULT_MAX_RESTART_DELAY = 5000;\n\nexport type PersistentLifecycleParams = {\n /**\n * Create connection.\n * If promise resolves successfully, connection is considered established.\n */\n start: () => Promise<void>;\n\n /**\n * Reset connection to initial state.\n */\n stop: () => Promise<void>;\n\n /**\n * Called after successful start.\n */\n onRestart?: () => Promise<void>;\n\n /**\n * Maximum delay between restartion attempts.\n * Default: 5000ms\n */\n maxRestartDelay?: number;\n};\n\n/**\n * Handles restarts (e.g. persists connection).\n * Restarts are scheduled with exponential backoff.\n */\nexport class PersistentLifecycle extends Resource {\n private readonly _start: () => Promise<void>;\n private readonly _stop: () => Promise<void>;\n private readonly _onRestart?: () => Promise<void>;\n private readonly _maxRestartDelay: number;\n\n private _restartTask?: DeferredTask = undefined;\n private _restartAfter = 0;\n\n constructor({ start, stop, onRestart, maxRestartDelay = DEFAULT_MAX_RESTART_DELAY }: PersistentLifecycleParams) {\n super();\n this._start = start;\n this._stop = stop;\n this._onRestart = onRestart;\n this._maxRestartDelay = maxRestartDelay;\n }\n\n @synchronized\n protected override async _open() {\n this._restartTask = new DeferredTask(this._ctx, async () => {\n try {\n await this._restart();\n } catch (err) {\n log.warn('Restart failed', { err });\n this._restartTask?.schedule();\n }\n });\n await this._start().catch((err) => {\n log.warn('Start failed', { err });\n this._restartTask?.schedule();\n });\n }\n\n protected override async _close() {\n await this._restartTask?.join();\n await this._stop();\n this._restartTask = undefined;\n }\n\n private async _restart() {\n log(`restarting in ${this._restartAfter}ms`, { state: this._lifecycleState });\n await this._stop();\n if (this._lifecycleState !== LifecycleState.OPEN) {\n return;\n }\n await cancelWithContext(this._ctx!, sleep(this._restartAfter));\n this._restartAfter = Math.min(Math.max(this._restartAfter * 2, INIT_RESTART_DELAY), this._maxRestartDelay);\n\n // May fail if the connection is not established.\n await warnAfterTimeout(5_000, 'Connection establishment takes too long', () => this._start());\n\n this._restartAfter = 0;\n await this._onRestart?.();\n }\n\n /**\n * Scheduling restart should be done from outside.\n */\n @synchronized\n scheduleRestart() {\n if (this._lifecycleState !== LifecycleState.OPEN) {\n return;\n }\n this._restartTask!.schedule();\n }\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;AAIA,cAAc;;;ACAd,OAAOA,eAAe;AAEtB,SAASC,SAASC,OAAOC,sBAAsBC,cAAcC,oBAAoB;AACjF,SAASC,SAASC,kBAAAA,iBAAgBC,YAAAA,iBAAgC;AAClE,SAASC,OAAAA,YAAW;AACpB,SAASC,WAAW;AACpB,SAAuBC,qBAAqB;;;ACNrC,IAAMC,4BAAN,cAAwCC,MAAAA;EAC7CC,cAAc;AACZ,UAAM,yBAAA;EACR;AACF;AAEO,IAAMC,2BAAN,cAAuCF,MAAAA;EAC5CC,cAAc;AACZ,UAAM,wBAAA;EACR;AACF;;;ACVA,SAASE,cAAcC,OAAOC,oBAAoB;AAClD,SAASC,mBAAmBC,gBAAgBC,gBAAgB;AAC5D,SAASC,wBAAwB;AACjC,SAASC,WAAW;;;;;;;;AAEpB,IAAMC,qBAAqB;AAC3B,IAAMC,4BAA4B;AA8B3B,IAAMC,sBAAN,cAAkCL,SAAAA;EASvCM,YAAY,EAAEC,OAAOC,MAAMC,WAAWC,kBAAkBN,0BAAyB,GAA+B;AAC9G,UAAK;AAJCO,wBAA8BC;AAC9BC,yBAAgB;AAItB,SAAKC,SAASP;AACd,SAAKQ,QAAQP;AACb,SAAKQ,aAAaP;AAClB,SAAKQ,mBAAmBP;EAC1B;EAEA,MACyBQ,QAAQ;AAC/B,SAAKP,eAAe,IAAIhB,aAAa,KAAKwB,MAAM,YAAA;AAC9C,UAAI;AACF,cAAM,KAAKC,SAAQ;MACrB,SAASC,KAAK;AACZnB,YAAIoB,KAAK,kBAAkB;UAAED;QAAI,GAAA;;;;;;AACjC,aAAKV,cAAcY,SAAAA;MACrB;IACF,CAAA;AACA,UAAM,KAAKT,OAAM,EAAGU,MAAM,CAACH,QAAAA;AACzBnB,UAAIoB,KAAK,gBAAgB;QAAED;MAAI,GAAA;;;;;;AAC/B,WAAKV,cAAcY,SAAAA;IACrB,CAAA;EACF;EAEA,MAAyBE,SAAS;AAChC,UAAM,KAAKd,cAAce,KAAAA;AACzB,UAAM,KAAKX,MAAK;AAChB,SAAKJ,eAAeC;EACtB;EAEA,MAAcQ,WAAW;AACvBlB,QAAI,iBAAiB,KAAKW,aAAa,MAAM;MAAEc,OAAO,KAAKC;IAAgB,GAAA;;;;;;AAC3E,UAAM,KAAKb,MAAK;AAChB,QAAI,KAAKa,oBAAoB7B,eAAe8B,MAAM;AAChD;IACF;AACA,UAAM/B,kBAAkB,KAAKqB,MAAOvB,MAAM,KAAKiB,aAAa,CAAA;AAC5D,SAAKA,gBAAgBiB,KAAKC,IAAID,KAAKE,IAAI,KAAKnB,gBAAgB,GAAGV,kBAAAA,GAAqB,KAAKc,gBAAgB;AAGzG,UAAMhB,iBAAiB,KAAO,2CAA2C,MAAM,KAAKa,OAAM,CAAA;AAE1F,SAAKD,gBAAgB;AACrB,UAAM,KAAKG,aAAU;EACvB;;;;EAMAiB,kBAAkB;AAChB,QAAI,KAAKL,oBAAoB7B,eAAe8B,MAAM;AAChD;IACF;AACA,SAAKlB,aAAcY,SAAQ;EAC7B;AACF;;EAhDG1B;GAjBUQ,oBAAAA,WAAAA,SAAAA,IAAAA;;EA0DVR;GA1DUQ,oBAAAA,WAAAA,mBAAAA,IAAAA;;;;AFvBb,IAAM6B,kBAAkB;AACxB,IAAMC,4BAA4B;AA0B3B,IAAMC,aAAN,cAAyBC,UAAAA;EAe9BC,YACUC,cACAC,UACSC,SACjB;AACA,UAAK;SAJGF,eAAAA;SACAC,WAAAA;SACSC,UAAAA;SAjBHC,YAAY,IAAIC,MAAAA;SAChBC,YAAY,IAAID,MAAAA;SACfE,uBAAuB,IAAIC,oBAAoB;MAC9DC,OAAO,YAAY,KAAKC,eAAc;MACtCC,MAAM,YAAY,KAAKC,gBAAe;MACtCC,WAAW,YAAY,KAAKT,UAAUU,KAAI;IAC5C,CAAA;SAEiBC,aAAa,oBAAIC,IAAAA;SAC1BC,SAAS,IAAIC,QAAAA;SACbC,MAAkBC;SAClBC,gBAA0BD;SAC1BE,oBAA8BF;EAQtC;;EAGA,IAAWG,OAAO;AAChB,WAAO;MACLC,MAAM,KAAKC;MACXC,UAAU,KAAKzB;MACf0B,QAAQ,KAAKzB;IACf;EACF;EAEA,IAAI0B,cAAc;AAChB,WAAO,KAAK3B;EACd;EAEA,IAAI4B,UAAU;AACZ,WAAO,KAAK3B;EACd;EAEA4B,YAAY,EAAED,SAASD,YAAW,GAA8C;AAC9E,SAAK1B,WAAW2B;AAChB,SAAK5B,eAAe2B;AACpB,SAAKrB,qBAAqBwB,gBAAe;EAC3C;EAEOC,YAAYC,UAAuC;AACxD,SAAKlB,WAAWmB,IAAID,QAAAA;AACpB,WAAO,MAAM,KAAKlB,WAAWoB,OAAOF,QAAAA;EACtC;;;;EAKA,MAAyBG,QAAQ;AAC/BC,IAAAA,KAAI,cAAc;MAAEd,MAAM,KAAKA;IAAK,GAAA;;;;;;AACpC,SAAKhB,qBAAqBiB,KAAI,EAAGc,MAAM,CAACC,QAAAA;AACtCF,MAAAA,KAAIG,KAAK,kCAAkC;QAAED;MAAI,GAAA;;;;;;IACnD,CAAA;EACF;;;;EAKA,MAAyBE,SAAS;AAChCJ,IAAAA,KAAI,cAAc;MAAER,SAAS,KAAK3B;IAAS,GAAA;;;;;;AAC3C,UAAM,KAAKK,qBAAqBmC,MAAK;EACvC;EAEA,MAAchC,iBAAiB;AAC7B,UAAMiC,MAAM,IAAIC,IAAI,OAAO,KAAK3C,YAAY,IAAI,KAAKC,QAAQ,IAAI,KAAKC,QAAQ0C,cAAc;AAC5F,SAAK1B,MAAM,IAAI2B,UAAUH,GAAAA;AAEzB,SAAKxB,IAAI4B,SAAS,MAAA;AAChBV,MAAAA,KAAI,UAAU,KAAKd,MAAI;;;;;;AACvB,WAAKN,OAAO+B,KAAI;AAChB,WAAK1C,UAAUQ,KAAI;IACrB;AACA,SAAKK,IAAI8B,UAAU,MAAA;AACjBZ,MAAAA,KAAI,UAAU,KAAKd,MAAI;;;;;;AACvB,WAAKhB,qBAAqBwB,gBAAe;IAC3C;AACA,SAAKZ,IAAI+B,UAAU,CAACC,UAAAA;AAClBd,MAAAA,KAAIG,KAAK,2BAA2B;QAAEY,OAAOD,MAAMC;QAAO7B,MAAM4B,MAAME;MAAQ,GAAA;;;;;;AAC9E,WAAK9C,qBAAqBwB,gBAAe;IAC3C;AAIA,SAAKZ,IAAImC,YAAY,OAAOH,UAAAA;AAC1B,UAAIA,MAAMI,SAAS,YAAY;AAC7B,aAAKC,aAAY;AACjB;MACF;AACA,YAAMD,OAAO,MAAME,aAAaN,MAAMI,IAAI;AAC1C,YAAMF,UAAUK,IAAIC,WAAWC,eAAeL,IAAAA;AAC9ClB,MAAAA,KAAI,YAAY;QAAER,SAAS,KAAK3B;QAAU2D,SAASC,SAASC,eAAeV,OAAAA;MAAS,GAAA;;;;;;AACpF,UAAIA,SAAS;AACX,mBAAWpB,YAAY,KAAKlB,YAAY;AACtC,cAAI;AACF,kBAAMkB,SAASoB,OAAAA;UACjB,SAASd,KAAK;AACZF,YAAAA,KAAIe,MAAM,cAAc;cAAEb;cAAKsB,SAASC,SAASC,eAAeV,OAAAA;YAAS,GAAA;;;;;;UAC3E;QACF;MACF;IACF;AAEA,UAAM,KAAKpC,OAAO+C,KAAK;MAAEC,SAAS,KAAK9D,QAAQ8D,WAAWrE;IAAgB,CAAA;AAC1E,SAAKyB,gBAAgB,IAAI6C,QAAAA,QAAAA;;;;AACzBC,yBACE,KAAK9C,eACL,YAAA;AAGE,WAAKF,KAAKiD,KAAK,UAAA;IACjB,GACAvE,yBAAAA;AAEF,SAAKsB,IAAIiD,KAAK,UAAA;AACd,SAAKZ,aAAY;EACnB;EAEA,MAAc5C,kBAAkB;AAC9B,QAAI,CAAC,KAAKO,KAAK;AACb;IACF;AACA,QAAI;AACF,WAAKF,OAAOoD,MAAM,KAAK5C,SAAS,IAAI6C,yBAAAA,IAA6B,IAAIC,0BAAAA,CAAAA;AACrE,WAAKtD,OAAOuD,MAAK;AACjB,WAAK,KAAKnD,eAAeoD,QAAAA;AACzB,WAAKpD,gBAAgBD;AACrB,WAAK,KAAKE,mBAAmBmD,QAAAA;AAC7B,WAAKnD,oBAAoBF;AAGzB,WAAKD,IAAI4B,SAAS,MAAA;MAAO;AACzB,WAAK5B,IAAI8B,UAAU,MAAA;MAAO;AAC1B,WAAK9B,IAAI+B,UAAU,MAAA;MAAO;AAC1B,WAAK/B,IAAIuB,MAAK;AACd,WAAKvB,MAAMC;IACb,SAASmB,KAAK;AACZ,UAAIA,eAAemC,SAASnC,IAAIc,QAAQsB,SAAS,2DAAA,GAA8D;AAC7G;MACF;AACAtC,MAAAA,KAAIG,KAAK,2BAA2B;QAAED;MAAI,GAAA;;;;;;IAC5C;EACF;;;;;EAMA,MAAa6B,KAAKf,SAAiC;AACjD,QAAI,KAAKpC,OAAO2D,UAAUC,aAAaC,UAAU;AAC/CzC,MAAAA,KAAI,yCAAA,QAAA;;;;;;AACJ,YAAM,KAAKpB,OAAO+C,KAAK;QAAEC,SAAS,KAAK9D,QAAQ8D,WAAWrE;MAAgB,CAAA;IAC5E;AACA,QAAI,CAAC,KAAKuB,KAAK;AACb,YAAM,IAAIoD,0BAAAA;IACZ;AACA,QACElB,QAAQ0B,WACP1B,QAAQ0B,OAAOlD,YAAY,KAAK3B,YAAYmD,QAAQ0B,OAAOnD,gBAAgB,KAAKA,cACjF;AACA,YAAM,IAAI0C,yBAAAA;IACZ;AAEAjC,IAAAA,KAAI,cAAc;MAAER,SAAS,KAAK3B;MAAU2D,SAASC,SAASC,eAAeV,OAAAA;IAAS,GAAA;;;;;;AACtF,SAAKlC,IAAIiD,KAAKV,IAAIsB,SAASpB,eAAeP,OAAAA,CAAAA;EAC5C;EAEQG,eAAe;AACrB,QAAI,KAAKyB,oBAAoBC,gBAAeC,MAAM;AAChD;IACF;AACA,SAAK,KAAK7D,mBAAmBmD,QAAAA;AAC7B,SAAKnD,oBAAoB,IAAI4C,QAAAA,QAAAA;;;;AAC7BkB,iBACE,KAAK9D,mBACL,MAAA;AACE,WAAKf,qBAAqBwB,gBAAe;IAC3C,GACA,IAAIlC,yBAAAA;EAER;AACF;",
|
|
6
|
+
"names": ["WebSocket", "Trigger", "Event", "scheduleTaskInterval", "scheduleTask", "TriggerState", "Context", "LifecycleState", "Resource", "log", "buf", "MessageSchema", "EdgeConnectionClosedError", "Error", "constructor", "EdgeIdentityChangedError", "DeferredTask", "sleep", "synchronized", "cancelWithContext", "LifecycleState", "Resource", "warnAfterTimeout", "log", "INIT_RESTART_DELAY", "DEFAULT_MAX_RESTART_DELAY", "PersistentLifecycle", "constructor", "start", "stop", "onRestart", "maxRestartDelay", "_restartTask", "undefined", "_restartAfter", "_start", "_stop", "_onRestart", "_maxRestartDelay", "_open", "_ctx", "_restart", "err", "warn", "schedule", "catch", "_close", "join", "state", "_lifecycleState", "OPEN", "Math", "min", "max", "scheduleRestart", "DEFAULT_TIMEOUT", "SIGNAL_KEEPALIVE_INTERVAL", "EdgeClient", "Resource", "constructor", "_identityKey", "_peerKey", "_config", "reconnect", "Event", "connected", "_persistentLifecycle", "PersistentLifecycle", "start", "_openWebSocket", "stop", "_closeWebSocket", "onRestart", "emit", "_listeners", "Set", "_ready", "Trigger", "_ws", "undefined", "_keepaliveCtx", "_heartBeatContext", "info", "open", "isOpen", "identity", "device", "identityKey", "peerKey", "setIdentity", "scheduleRestart", "addListener", "listener", "add", "delete", "_open", "log", "catch", "err", "warn", "_close", "close", "url", "URL", "socketEndpoint", "WebSocket", "onopen", "wake", "onclose", "onerror", "event", "error", "message", "onmessage", "data", "_onHeartbeat", "toUint8Array", "buf", "fromBinary", "MessageSchema", "payload", "protocol", "getPayloadType", "wait", "timeout", "Context", "scheduleTaskInterval", "send", "throw", "EdgeIdentityChangedError", "EdgeConnectionClosedError", "reset", "dispose", "Error", "includes", "state", "TriggerState", "RESOLVED", "source", "toBinary", "_lifecycleState", "LifecycleState", "OPEN", "scheduleTask"]
|
|
7
7
|
}
|