@dxos/edge-client 0.6.13 → 0.6.14-main.1366248
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 +802 -286
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +128 -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 +798 -283
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +158 -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 +994 -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 +129 -0
- package/dist/lib/node-esm/testing/index.mjs.map +7 -0
- package/dist/types/src/auth.d.ts +22 -0
- package/dist/types/src/auth.d.ts.map +1 -0
- package/dist/types/src/defs.d.ts.map +1 -1
- package/dist/types/src/edge-client.d.ts +30 -26
- package/dist/types/src/edge-client.d.ts.map +1 -1
- package/dist/types/src/edge-http-client.d.ts +48 -0
- package/dist/types/src/edge-http-client.d.ts.map +1 -0
- package/dist/types/src/edge-identity.d.ts +15 -0
- package/dist/types/src/edge-identity.d.ts.map +1 -0
- package/dist/types/src/edge-ws-connection.d.ts +30 -0
- package/dist/types/src/edge-ws-connection.d.ts.map +1 -0
- 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 +4 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/persistent-lifecycle.d.ts +7 -5
- package/dist/types/src/persistent-lifecycle.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 +22 -0
- package/dist/types/src/testing/test-utils.d.ts.map +1 -0
- package/dist/types/src/utils.d.ts +2 -0
- package/dist/types/src/utils.d.ts.map +1 -0
- package/package.json +27 -17
- package/src/auth.ts +135 -0
- package/src/defs.ts +2 -3
- package/src/edge-client.test.ts +144 -25
- package/src/edge-client.ts +181 -127
- package/src/edge-http-client.ts +213 -0
- package/src/edge-identity.ts +31 -0
- package/src/edge-ws-connection.ts +148 -0
- package/src/errors.ts +8 -2
- package/src/index.ts +4 -0
- package/src/persistent-lifecycle.test.ts +2 -2
- package/src/persistent-lifecycle.ts +26 -11
- 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 +117 -0
- package/src/utils.ts +10 -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
package/dist/lib/node/index.cjs
CHANGED
|
@@ -30,143 +30,294 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
var node_exports = {};
|
|
31
31
|
__export(node_exports, {
|
|
32
32
|
EdgeClient: () => EdgeClient,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
EdgeConnectionClosedError: () => EdgeConnectionClosedError,
|
|
34
|
+
EdgeHttpClient: () => EdgeHttpClient,
|
|
35
|
+
EdgeIdentityChangedError: () => EdgeIdentityChangedError,
|
|
36
|
+
Protocol: () => import_chunk_ANV2HBEH.Protocol,
|
|
37
|
+
createChainEdgeIdentity: () => createChainEdgeIdentity,
|
|
38
|
+
createDeviceEdgeIdentity: () => createDeviceEdgeIdentity,
|
|
39
|
+
createEphemeralEdgeIdentity: () => createEphemeralEdgeIdentity,
|
|
40
|
+
createStubEdgeIdentity: () => createStubEdgeIdentity,
|
|
41
|
+
createTestHaloEdgeIdentity: () => createTestHaloEdgeIdentity,
|
|
42
|
+
getTypename: () => import_chunk_ANV2HBEH.getTypename,
|
|
43
|
+
handleAuthChallenge: () => handleAuthChallenge,
|
|
44
|
+
protocol: () => import_chunk_ANV2HBEH.protocol,
|
|
45
|
+
toUint8Array: () => import_chunk_ANV2HBEH.toUint8Array
|
|
37
46
|
});
|
|
38
47
|
module.exports = __toCommonJS(node_exports);
|
|
48
|
+
var import_chunk_ANV2HBEH = require("./chunk-ANV2HBEH.cjs");
|
|
39
49
|
__reExport(node_exports, require("@dxos/protocols/buf/dxos/edge/messenger_pb"), module.exports);
|
|
40
|
-
var import_isomorphic_ws = __toESM(require("isomorphic-ws"));
|
|
41
50
|
var import_async = require("@dxos/async");
|
|
42
51
|
var import_context = require("@dxos/context");
|
|
43
|
-
var import_invariant = require("@dxos/invariant");
|
|
44
52
|
var import_log = require("@dxos/log");
|
|
45
|
-
var
|
|
46
|
-
var
|
|
47
|
-
var
|
|
48
|
-
var import_messenger_pb2 = require("@dxos/protocols/buf/dxos/edge/messenger_pb");
|
|
49
|
-
var import_invariant2 = require("@dxos/invariant");
|
|
50
|
-
var import_buf2 = require("@dxos/protocols/buf");
|
|
51
|
-
var import_messenger_pb3 = require("@dxos/protocols/buf/dxos/edge/messenger_pb");
|
|
52
|
-
var import_util = require("@dxos/util");
|
|
53
|
+
var import_invariant = require("@dxos/invariant");
|
|
54
|
+
var import_proto = require("@dxos/protocols/proto");
|
|
55
|
+
var import_isomorphic_ws = __toESM(require("isomorphic-ws"));
|
|
53
56
|
var import_async2 = require("@dxos/async");
|
|
54
57
|
var import_context2 = require("@dxos/context");
|
|
55
|
-
var
|
|
58
|
+
var import_invariant2 = require("@dxos/invariant");
|
|
56
59
|
var import_log2 = require("@dxos/log");
|
|
57
|
-
var
|
|
58
|
-
var
|
|
59
|
-
var
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
var import_buf = require("@dxos/protocols/buf");
|
|
61
|
+
var import_messenger_pb = require("@dxos/protocols/buf/dxos/edge/messenger_pb");
|
|
62
|
+
var import_async3 = require("@dxos/async");
|
|
63
|
+
var import_context3 = require("@dxos/context");
|
|
64
|
+
var import_debug = require("@dxos/debug");
|
|
65
|
+
var import_log3 = require("@dxos/log");
|
|
66
|
+
var import_credentials = require("@dxos/credentials");
|
|
67
|
+
var import_keyring = require("@dxos/keyring");
|
|
68
|
+
var import_keys = require("@dxos/keys");
|
|
69
|
+
var import_async4 = require("@dxos/async");
|
|
70
|
+
var import_context4 = require("@dxos/context");
|
|
71
|
+
var import_log4 = require("@dxos/log");
|
|
72
|
+
var import_protocols = require("@dxos/protocols");
|
|
73
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-identity.ts";
|
|
74
|
+
var handleAuthChallenge = async (failedResponse, identity) => {
|
|
75
|
+
(0, import_invariant.invariant)(failedResponse.status === 401, void 0, {
|
|
76
|
+
F: __dxlog_file,
|
|
77
|
+
L: 21,
|
|
78
|
+
S: void 0,
|
|
79
|
+
A: [
|
|
80
|
+
"failedResponse.status === 401",
|
|
81
|
+
""
|
|
82
|
+
]
|
|
83
|
+
});
|
|
84
|
+
const headerValue = failedResponse.headers.get("Www-Authenticate");
|
|
85
|
+
(0, import_invariant.invariant)(headerValue?.startsWith("VerifiablePresentation challenge="), void 0, {
|
|
86
|
+
F: __dxlog_file,
|
|
87
|
+
L: 24,
|
|
88
|
+
S: void 0,
|
|
89
|
+
A: [
|
|
90
|
+
"headerValue?.startsWith('VerifiablePresentation challenge=')",
|
|
91
|
+
""
|
|
92
|
+
]
|
|
93
|
+
});
|
|
94
|
+
const challenge = headerValue?.slice("VerifiablePresentation challenge=".length);
|
|
95
|
+
(0, import_invariant.invariant)(challenge, void 0, {
|
|
96
|
+
F: __dxlog_file,
|
|
97
|
+
L: 27,
|
|
98
|
+
S: void 0,
|
|
99
|
+
A: [
|
|
100
|
+
"challenge",
|
|
101
|
+
""
|
|
102
|
+
]
|
|
103
|
+
});
|
|
104
|
+
const presentation = await identity.presentCredentials({
|
|
105
|
+
challenge: Buffer.from(challenge, "base64")
|
|
106
|
+
});
|
|
107
|
+
return import_proto.schema.getCodecForType("dxos.halo.credentials.Presentation").encode(presentation);
|
|
108
|
+
};
|
|
109
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
110
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
111
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
112
|
+
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;
|
|
113
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
114
|
+
}
|
|
115
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-ws-connection.ts";
|
|
116
|
+
var SIGNAL_KEEPALIVE_INTERVAL = 5e3;
|
|
117
|
+
var EdgeWsConnection = class extends import_context2.Resource {
|
|
118
|
+
constructor(_identity, _connectionInfo, _callbacks) {
|
|
119
|
+
super();
|
|
120
|
+
this._identity = _identity;
|
|
121
|
+
this._connectionInfo = _connectionInfo;
|
|
122
|
+
this._callbacks = _callbacks;
|
|
65
123
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
return {
|
|
73
|
-
type: this.getPayloadType(message)
|
|
74
|
-
};
|
|
75
|
-
}
|
|
124
|
+
get info() {
|
|
125
|
+
return {
|
|
126
|
+
open: this.isOpen,
|
|
127
|
+
identity: this._identity.identityKey,
|
|
128
|
+
device: this._identity.peerKey
|
|
129
|
+
};
|
|
76
130
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
(0, import_invariant2.invariant)(message.payload, void 0, {
|
|
82
|
-
F: __dxlog_file,
|
|
83
|
-
L: 40,
|
|
131
|
+
send(message) {
|
|
132
|
+
(0, import_invariant2.invariant)(this._ws, void 0, {
|
|
133
|
+
F: __dxlog_file2,
|
|
134
|
+
L: 48,
|
|
84
135
|
S: this,
|
|
85
136
|
A: [
|
|
86
|
-
"
|
|
137
|
+
"this._ws",
|
|
87
138
|
""
|
|
88
139
|
]
|
|
89
140
|
});
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
L: 46,
|
|
141
|
+
(0, import_log2.log)("sending...", {
|
|
142
|
+
peerKey: this._identity.peerKey,
|
|
143
|
+
payload: import_chunk_ANV2HBEH.protocol.getPayloadType(message)
|
|
144
|
+
}, {
|
|
145
|
+
F: __dxlog_file2,
|
|
146
|
+
L: 49,
|
|
97
147
|
S: this,
|
|
98
|
-
|
|
99
|
-
"bufWkt.anyIs(message.payload, type)",
|
|
100
|
-
"`Unexpected payload type: ${payloadTypename}}`"
|
|
101
|
-
]
|
|
148
|
+
C: (f, a) => f(...a)
|
|
102
149
|
});
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
150
|
+
this._ws.send(import_buf.buf.toBinary(import_messenger_pb.MessageSchema, message));
|
|
151
|
+
}
|
|
152
|
+
async _open() {
|
|
153
|
+
this._ws = new import_isomorphic_ws.default(this._connectionInfo.url, this._connectionInfo.protocolHeader ? [
|
|
154
|
+
this._connectionInfo.protocolHeader
|
|
155
|
+
] : []);
|
|
156
|
+
this._ws.onopen = () => {
|
|
157
|
+
if (this.isOpen) {
|
|
158
|
+
(0, import_log2.log)("connected", void 0, {
|
|
159
|
+
F: __dxlog_file2,
|
|
160
|
+
L: 61,
|
|
161
|
+
S: this,
|
|
162
|
+
C: (f, a) => f(...a)
|
|
163
|
+
});
|
|
164
|
+
this._callbacks.onConnected();
|
|
165
|
+
this._scheduleHeartbeats();
|
|
166
|
+
} else {
|
|
167
|
+
import_log2.log.verbose("connected after becoming inactive", {
|
|
168
|
+
currentIdentity: this._identity
|
|
169
|
+
}, {
|
|
170
|
+
F: __dxlog_file2,
|
|
171
|
+
L: 65,
|
|
172
|
+
S: this,
|
|
173
|
+
C: (f, a) => f(...a)
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
this._ws.onclose = () => {
|
|
178
|
+
if (this.isOpen) {
|
|
179
|
+
(0, import_log2.log)("disconnected while being open", void 0, {
|
|
180
|
+
F: __dxlog_file2,
|
|
181
|
+
L: 70,
|
|
182
|
+
S: this,
|
|
183
|
+
C: (f, a) => f(...a)
|
|
184
|
+
});
|
|
185
|
+
this._callbacks.onRestartRequired();
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
this._ws.onerror = (event) => {
|
|
189
|
+
if (this.isOpen) {
|
|
190
|
+
import_log2.log.warn("edge connection socket error", {
|
|
191
|
+
error: event.error,
|
|
192
|
+
info: event.message
|
|
193
|
+
}, {
|
|
194
|
+
F: __dxlog_file2,
|
|
195
|
+
L: 76,
|
|
196
|
+
S: this,
|
|
197
|
+
C: (f, a) => f(...a)
|
|
198
|
+
});
|
|
199
|
+
this._callbacks.onRestartRequired();
|
|
200
|
+
} else {
|
|
201
|
+
import_log2.log.verbose("error ignored on closed connection", {
|
|
202
|
+
error: event.error
|
|
203
|
+
}, {
|
|
204
|
+
F: __dxlog_file2,
|
|
205
|
+
L: 79,
|
|
206
|
+
S: this,
|
|
207
|
+
C: (f, a) => f(...a)
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
this._ws.onmessage = async (event) => {
|
|
212
|
+
if (!this.isOpen) {
|
|
213
|
+
import_log2.log.verbose("message ignored on closed connection", {
|
|
214
|
+
event: event.type
|
|
215
|
+
}, {
|
|
216
|
+
F: __dxlog_file2,
|
|
217
|
+
L: 87,
|
|
218
|
+
S: this,
|
|
219
|
+
C: (f, a) => f(...a)
|
|
220
|
+
});
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
if (event.data === "__pong__") {
|
|
224
|
+
this._rescheduleHeartbeatTimeout();
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
const data = await (0, import_chunk_ANV2HBEH.toUint8Array)(event.data);
|
|
228
|
+
if (this.isOpen) {
|
|
229
|
+
const message = import_buf.buf.fromBinary(import_messenger_pb.MessageSchema, data);
|
|
230
|
+
(0, import_log2.log)("received", {
|
|
231
|
+
from: message.source,
|
|
232
|
+
payload: import_chunk_ANV2HBEH.protocol.getPayloadType(message)
|
|
233
|
+
}, {
|
|
234
|
+
F: __dxlog_file2,
|
|
235
|
+
L: 97,
|
|
236
|
+
S: this,
|
|
237
|
+
C: (f, a) => f(...a)
|
|
238
|
+
});
|
|
239
|
+
this._callbacks.onMessage(message);
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
async _close() {
|
|
244
|
+
void this._inactivityTimeoutCtx?.dispose().catch(() => {
|
|
245
|
+
});
|
|
246
|
+
try {
|
|
247
|
+
this._ws?.close();
|
|
248
|
+
this._ws = void 0;
|
|
249
|
+
} catch (err) {
|
|
250
|
+
if (err instanceof Error && err.message.includes("WebSocket is closed before the connection is established.")) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
import_log2.log.warn("Error closing websocket", {
|
|
254
|
+
err
|
|
255
|
+
}, {
|
|
256
|
+
F: __dxlog_file2,
|
|
257
|
+
L: 113,
|
|
258
|
+
S: this,
|
|
259
|
+
C: (f, a) => f(...a)
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
_scheduleHeartbeats() {
|
|
264
|
+
(0, import_invariant2.invariant)(this._ws, void 0, {
|
|
265
|
+
F: __dxlog_file2,
|
|
266
|
+
L: 118,
|
|
107
267
|
S: this,
|
|
108
268
|
A: [
|
|
109
|
-
"
|
|
110
|
-
"
|
|
269
|
+
"this._ws",
|
|
270
|
+
""
|
|
111
271
|
]
|
|
112
272
|
});
|
|
113
|
-
|
|
273
|
+
(0, import_async2.scheduleTaskInterval)(this._ctx, async () => {
|
|
274
|
+
this._ws?.send("__ping__");
|
|
275
|
+
}, SIGNAL_KEEPALIVE_INTERVAL);
|
|
276
|
+
this._ws.send("__ping__");
|
|
277
|
+
this._rescheduleHeartbeatTimeout();
|
|
114
278
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
getPayloadType(message) {
|
|
119
|
-
if (!message.payload) {
|
|
120
|
-
return void 0;
|
|
279
|
+
_rescheduleHeartbeatTimeout() {
|
|
280
|
+
if (!this.isOpen) {
|
|
281
|
+
return;
|
|
121
282
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
* Create a packed message.
|
|
127
|
-
*/
|
|
128
|
-
createMessage(type, { source, target, payload, serviceId }) {
|
|
129
|
-
return import_buf2.buf.create(import_messenger_pb3.MessageSchema, {
|
|
130
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
131
|
-
source,
|
|
132
|
-
target,
|
|
133
|
-
serviceId,
|
|
134
|
-
payload: payload ? import_buf2.bufWkt.anyPack(type, import_buf2.buf.create(type, payload)) : void 0
|
|
283
|
+
void this._inactivityTimeoutCtx?.dispose();
|
|
284
|
+
this._inactivityTimeoutCtx = new import_context2.Context(void 0, {
|
|
285
|
+
F: __dxlog_file2,
|
|
286
|
+
L: 137
|
|
135
287
|
});
|
|
288
|
+
(0, import_async2.scheduleTask)(this._inactivityTimeoutCtx, () => {
|
|
289
|
+
if (this.isOpen) {
|
|
290
|
+
this._callbacks.onRestartRequired();
|
|
291
|
+
}
|
|
292
|
+
}, 2 * SIGNAL_KEEPALIVE_INTERVAL);
|
|
136
293
|
}
|
|
137
294
|
};
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
295
|
+
_ts_decorate([
|
|
296
|
+
import_log2.logInfo
|
|
297
|
+
], EdgeWsConnection.prototype, "info", null);
|
|
298
|
+
var EdgeConnectionClosedError = class extends Error {
|
|
299
|
+
constructor() {
|
|
300
|
+
super("Edge connection closed.");
|
|
144
301
|
}
|
|
145
|
-
throw new Error(`Unexpected datatype: ${data}`);
|
|
146
302
|
};
|
|
147
|
-
var
|
|
148
|
-
import_messenger_pb2.SwarmRequestSchema,
|
|
149
|
-
import_messenger_pb2.SwarmResponseSchema,
|
|
150
|
-
import_messenger_pb2.TextMessageSchema,
|
|
151
|
-
import_wkt.AnySchema
|
|
152
|
-
]);
|
|
153
|
-
var WebsocketClosedError = class extends Error {
|
|
303
|
+
var EdgeIdentityChangedError = class extends Error {
|
|
154
304
|
constructor() {
|
|
155
|
-
super("
|
|
305
|
+
super("Edge identity changed.");
|
|
156
306
|
}
|
|
157
307
|
};
|
|
158
|
-
function
|
|
308
|
+
function _ts_decorate2(decorators, target, key, desc) {
|
|
159
309
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
160
310
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
161
311
|
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;
|
|
162
312
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
163
313
|
}
|
|
164
|
-
var
|
|
314
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/persistent-lifecycle.ts";
|
|
165
315
|
var INIT_RESTART_DELAY = 100;
|
|
166
316
|
var DEFAULT_MAX_RESTART_DELAY = 5e3;
|
|
167
|
-
var PersistentLifecycle = class extends
|
|
317
|
+
var PersistentLifecycle = class extends import_context3.Resource {
|
|
168
318
|
constructor({ start, stop, onRestart, maxRestartDelay = DEFAULT_MAX_RESTART_DELAY }) {
|
|
169
319
|
super();
|
|
320
|
+
this._currentContext = void 0;
|
|
170
321
|
this._restartTask = void 0;
|
|
171
322
|
this._restartAfter = 0;
|
|
172
323
|
this._start = start;
|
|
@@ -175,117 +326,177 @@ var PersistentLifecycle = class extends import_context2.Resource {
|
|
|
175
326
|
this._maxRestartDelay = maxRestartDelay;
|
|
176
327
|
}
|
|
177
328
|
async _open() {
|
|
178
|
-
this._restartTask = new
|
|
329
|
+
this._restartTask = new import_async3.DeferredTask(this._ctx, async () => {
|
|
179
330
|
try {
|
|
180
331
|
await this._restart();
|
|
181
332
|
} catch (err) {
|
|
182
|
-
|
|
333
|
+
import_log3.log.warn("Restart failed", {
|
|
183
334
|
err
|
|
184
335
|
}, {
|
|
185
|
-
F:
|
|
186
|
-
L:
|
|
336
|
+
F: __dxlog_file3,
|
|
337
|
+
L: 65,
|
|
187
338
|
S: this,
|
|
188
339
|
C: (f, a) => f(...a)
|
|
189
340
|
});
|
|
190
341
|
this._restartTask?.schedule();
|
|
191
342
|
}
|
|
192
343
|
});
|
|
193
|
-
await this._start().catch((err) => {
|
|
194
|
-
|
|
344
|
+
this._currentContext = await this._start().catch((err) => {
|
|
345
|
+
import_log3.log.warn("Start failed", {
|
|
195
346
|
err
|
|
196
347
|
}, {
|
|
197
|
-
F:
|
|
198
|
-
L:
|
|
348
|
+
F: __dxlog_file3,
|
|
349
|
+
L: 70,
|
|
199
350
|
S: this,
|
|
200
351
|
C: (f, a) => f(...a)
|
|
201
352
|
});
|
|
202
353
|
this._restartTask?.schedule();
|
|
354
|
+
return void 0;
|
|
203
355
|
});
|
|
204
356
|
}
|
|
205
357
|
async _close() {
|
|
206
358
|
await this._restartTask?.join();
|
|
207
|
-
await this.
|
|
359
|
+
await this._stopCurrentContext();
|
|
208
360
|
this._restartTask = void 0;
|
|
209
361
|
}
|
|
210
362
|
async _restart() {
|
|
211
|
-
(0,
|
|
363
|
+
(0, import_log3.log)(`restarting in ${this._restartAfter}ms`, {
|
|
212
364
|
state: this._lifecycleState
|
|
213
365
|
}, {
|
|
214
|
-
F:
|
|
215
|
-
L:
|
|
366
|
+
F: __dxlog_file3,
|
|
367
|
+
L: 83,
|
|
216
368
|
S: this,
|
|
217
369
|
C: (f, a) => f(...a)
|
|
218
370
|
});
|
|
219
|
-
await this.
|
|
220
|
-
if (this._lifecycleState !==
|
|
371
|
+
await this._stopCurrentContext();
|
|
372
|
+
if (this._lifecycleState !== import_context3.LifecycleState.OPEN) {
|
|
221
373
|
return;
|
|
222
374
|
}
|
|
223
|
-
await (0,
|
|
375
|
+
await (0, import_context3.cancelWithContext)(this._ctx, (0, import_async3.sleep)(this._restartAfter));
|
|
224
376
|
this._restartAfter = Math.min(Math.max(this._restartAfter * 2, INIT_RESTART_DELAY), this._maxRestartDelay);
|
|
225
|
-
await (0, import_debug.warnAfterTimeout)(5e3, "Connection establishment takes too long", () =>
|
|
377
|
+
await (0, import_debug.warnAfterTimeout)(5e3, "Connection establishment takes too long", async () => {
|
|
378
|
+
this._currentContext = await this._start();
|
|
379
|
+
});
|
|
226
380
|
this._restartAfter = 0;
|
|
227
381
|
await this._onRestart?.();
|
|
228
382
|
}
|
|
383
|
+
async _stopCurrentContext() {
|
|
384
|
+
if (this._currentContext) {
|
|
385
|
+
try {
|
|
386
|
+
await this._stop(this._currentContext);
|
|
387
|
+
} catch (err) {
|
|
388
|
+
import_log3.log.catch(err, void 0, {
|
|
389
|
+
F: __dxlog_file3,
|
|
390
|
+
L: 105,
|
|
391
|
+
S: this,
|
|
392
|
+
C: (f, a) => f(...a)
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
this._currentContext = void 0;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
229
398
|
/**
|
|
230
399
|
* Scheduling restart should be done from outside.
|
|
231
400
|
*/
|
|
232
401
|
scheduleRestart() {
|
|
233
|
-
if (this._lifecycleState !==
|
|
402
|
+
if (this._lifecycleState !== import_context3.LifecycleState.OPEN) {
|
|
234
403
|
return;
|
|
235
404
|
}
|
|
236
405
|
this._restartTask.schedule();
|
|
237
406
|
}
|
|
238
407
|
};
|
|
239
|
-
|
|
240
|
-
|
|
408
|
+
_ts_decorate2([
|
|
409
|
+
import_async3.synchronized
|
|
241
410
|
], PersistentLifecycle.prototype, "_open", null);
|
|
242
|
-
|
|
243
|
-
|
|
411
|
+
_ts_decorate2([
|
|
412
|
+
import_async3.synchronized
|
|
244
413
|
], PersistentLifecycle.prototype, "scheduleRestart", null);
|
|
245
|
-
var
|
|
414
|
+
var getEdgeUrlWithProtocol = (baseUrl, protocol2) => {
|
|
415
|
+
const isSecure = baseUrl.startsWith("https") || baseUrl.startsWith("wss");
|
|
416
|
+
const url = new URL(baseUrl);
|
|
417
|
+
url.protocol = protocol2 + (isSecure ? "s" : "");
|
|
418
|
+
return url.toString();
|
|
419
|
+
};
|
|
420
|
+
function _ts_decorate3(decorators, target, key, desc) {
|
|
421
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
422
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
423
|
+
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;
|
|
424
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
425
|
+
}
|
|
426
|
+
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-client.ts";
|
|
246
427
|
var DEFAULT_TIMEOUT = 1e4;
|
|
247
|
-
var SIGNAL_KEEPALIVE_INTERVAL = 5e3;
|
|
248
428
|
var EdgeClient = class extends import_context.Resource {
|
|
249
|
-
constructor(
|
|
429
|
+
constructor(_identity, _config) {
|
|
250
430
|
super();
|
|
251
|
-
this.
|
|
252
|
-
this._peerKey = _peerKey;
|
|
431
|
+
this._identity = _identity;
|
|
253
432
|
this._config = _config;
|
|
254
|
-
this.reconnect = new import_async.Event();
|
|
255
433
|
this._persistentLifecycle = new PersistentLifecycle({
|
|
256
|
-
start: async () => this.
|
|
257
|
-
stop: async () => this.
|
|
258
|
-
onRestart: async () => this.reconnect.emit()
|
|
434
|
+
start: async () => this._connect(),
|
|
435
|
+
stop: async (state) => this._disconnect(state)
|
|
259
436
|
});
|
|
260
|
-
this.
|
|
437
|
+
this._messageListeners = /* @__PURE__ */ new Set();
|
|
438
|
+
this._reconnectListeners = /* @__PURE__ */ new Set();
|
|
439
|
+
this._currentConnection = void 0;
|
|
261
440
|
this._ready = new import_async.Trigger();
|
|
262
|
-
this.
|
|
263
|
-
this.
|
|
264
|
-
this.
|
|
265
|
-
this._protocol = this._config.protocol ?? protocol;
|
|
441
|
+
this._isActive = (connection) => connection === this._currentConnection;
|
|
442
|
+
this._baseWsUrl = getEdgeUrlWithProtocol(_config.socketEndpoint, "ws");
|
|
443
|
+
this._baseHttpUrl = getEdgeUrlWithProtocol(_config.socketEndpoint, "http");
|
|
266
444
|
}
|
|
267
|
-
// TODO(burdon): Attach logging.
|
|
268
445
|
get info() {
|
|
269
446
|
return {
|
|
270
447
|
open: this.isOpen,
|
|
271
|
-
identity: this.
|
|
272
|
-
device: this.
|
|
448
|
+
identity: this._identity.identityKey,
|
|
449
|
+
device: this._identity.peerKey
|
|
273
450
|
};
|
|
274
451
|
}
|
|
452
|
+
get isConnected() {
|
|
453
|
+
return Boolean(this._currentConnection) && this._ready.state === import_async.TriggerState.RESOLVED;
|
|
454
|
+
}
|
|
275
455
|
get identityKey() {
|
|
276
|
-
return this.
|
|
456
|
+
return this._identity.identityKey;
|
|
277
457
|
}
|
|
278
458
|
get peerKey() {
|
|
279
|
-
return this.
|
|
459
|
+
return this._identity.peerKey;
|
|
280
460
|
}
|
|
281
|
-
setIdentity(
|
|
282
|
-
this.
|
|
283
|
-
|
|
284
|
-
|
|
461
|
+
setIdentity(identity) {
|
|
462
|
+
if (identity.identityKey !== this._identity.identityKey || identity.peerKey !== this._identity.peerKey) {
|
|
463
|
+
(0, import_log.log)("Edge identity changed", {
|
|
464
|
+
identity,
|
|
465
|
+
oldIdentity: this._identity
|
|
466
|
+
}, {
|
|
467
|
+
F: __dxlog_file4,
|
|
468
|
+
L: 95,
|
|
469
|
+
S: this,
|
|
470
|
+
C: (f, a) => f(...a)
|
|
471
|
+
});
|
|
472
|
+
this._identity = identity;
|
|
473
|
+
this._closeCurrentConnection(new EdgeIdentityChangedError());
|
|
474
|
+
this._persistentLifecycle.scheduleRestart();
|
|
475
|
+
}
|
|
285
476
|
}
|
|
286
|
-
|
|
287
|
-
this.
|
|
288
|
-
return () => this.
|
|
477
|
+
onMessage(listener) {
|
|
478
|
+
this._messageListeners.add(listener);
|
|
479
|
+
return () => this._messageListeners.delete(listener);
|
|
480
|
+
}
|
|
481
|
+
onReconnected(listener) {
|
|
482
|
+
this._reconnectListeners.add(listener);
|
|
483
|
+
if (this._ready.state === import_async.TriggerState.RESOLVED) {
|
|
484
|
+
(0, import_async.scheduleMicroTask)(this._ctx, () => {
|
|
485
|
+
if (this._reconnectListeners.has(listener)) {
|
|
486
|
+
try {
|
|
487
|
+
listener();
|
|
488
|
+
} catch (error) {
|
|
489
|
+
import_log.log.catch(error, void 0, {
|
|
490
|
+
F: __dxlog_file4,
|
|
491
|
+
L: 117,
|
|
492
|
+
S: this,
|
|
493
|
+
C: (f, a) => f(...a)
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
return () => this._reconnectListeners.delete(listener);
|
|
289
500
|
}
|
|
290
501
|
/**
|
|
291
502
|
* Open connection to messaging service.
|
|
@@ -294,8 +505,8 @@ var EdgeClient = class extends import_context.Resource {
|
|
|
294
505
|
(0, import_log.log)("opening...", {
|
|
295
506
|
info: this.info
|
|
296
507
|
}, {
|
|
297
|
-
F:
|
|
298
|
-
L:
|
|
508
|
+
F: __dxlog_file4,
|
|
509
|
+
L: 129,
|
|
299
510
|
S: this,
|
|
300
511
|
C: (f, a) => f(...a)
|
|
301
512
|
});
|
|
@@ -303,8 +514,8 @@ var EdgeClient = class extends import_context.Resource {
|
|
|
303
514
|
import_log.log.warn("Error while opening connection", {
|
|
304
515
|
err
|
|
305
516
|
}, {
|
|
306
|
-
F:
|
|
307
|
-
L:
|
|
517
|
+
F: __dxlog_file4,
|
|
518
|
+
L: 131,
|
|
308
519
|
S: this,
|
|
309
520
|
C: (f, a) => f(...a)
|
|
310
521
|
});
|
|
@@ -315,126 +526,139 @@ var EdgeClient = class extends import_context.Resource {
|
|
|
315
526
|
*/
|
|
316
527
|
async _close() {
|
|
317
528
|
(0, import_log.log)("closing...", {
|
|
318
|
-
peerKey: this.
|
|
529
|
+
peerKey: this._identity.peerKey
|
|
319
530
|
}, {
|
|
320
|
-
F:
|
|
321
|
-
L:
|
|
531
|
+
F: __dxlog_file4,
|
|
532
|
+
L: 139,
|
|
322
533
|
S: this,
|
|
323
534
|
C: (f, a) => f(...a)
|
|
324
535
|
});
|
|
536
|
+
this._closeCurrentConnection();
|
|
325
537
|
await this._persistentLifecycle.close();
|
|
326
538
|
}
|
|
327
|
-
async
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
};
|
|
339
|
-
this._ws.onclose = () => {
|
|
340
|
-
(0, import_log.log)("closed", this.info, {
|
|
341
|
-
F: __dxlog_file3,
|
|
342
|
-
L: 124,
|
|
343
|
-
S: this,
|
|
344
|
-
C: (f, a) => f(...a)
|
|
345
|
-
});
|
|
346
|
-
this._persistentLifecycle.scheduleRestart();
|
|
347
|
-
};
|
|
348
|
-
this._ws.onerror = (event) => {
|
|
349
|
-
import_log.log.warn("EdgeClient socket error", {
|
|
350
|
-
error: event.error,
|
|
351
|
-
info: event.message
|
|
352
|
-
}, {
|
|
353
|
-
F: __dxlog_file3,
|
|
354
|
-
L: 128,
|
|
355
|
-
S: this,
|
|
356
|
-
C: (f, a) => f(...a)
|
|
357
|
-
});
|
|
358
|
-
this._persistentLifecycle.scheduleRestart();
|
|
359
|
-
};
|
|
360
|
-
this._ws.onmessage = async (event) => {
|
|
361
|
-
if (event.data === "__pong__") {
|
|
362
|
-
this._onHeartbeat();
|
|
363
|
-
return;
|
|
364
|
-
}
|
|
365
|
-
const data = await toUint8Array(event.data);
|
|
366
|
-
const message = import_buf.buf.fromBinary(import_messenger_pb.MessageSchema, data);
|
|
367
|
-
(0, import_log.log)("received", {
|
|
368
|
-
peerKey: this._peerKey,
|
|
369
|
-
payload: protocol.getPayloadType(message)
|
|
370
|
-
}, {
|
|
371
|
-
F: __dxlog_file3,
|
|
372
|
-
L: 141,
|
|
539
|
+
async _connect() {
|
|
540
|
+
if (this._ctx.disposed) {
|
|
541
|
+
return void 0;
|
|
542
|
+
}
|
|
543
|
+
const identity = this._identity;
|
|
544
|
+
const path = `/ws/${identity.identityKey}/${identity.peerKey}`;
|
|
545
|
+
const protocolHeader = this._config.disableAuth ? void 0 : await this._createAuthHeader(path);
|
|
546
|
+
if (this._identity !== identity) {
|
|
547
|
+
(0, import_log.log)("identity changed during auth header request", void 0, {
|
|
548
|
+
F: __dxlog_file4,
|
|
549
|
+
L: 153,
|
|
373
550
|
S: this,
|
|
374
551
|
C: (f, a) => f(...a)
|
|
375
552
|
});
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
553
|
+
return void 0;
|
|
554
|
+
}
|
|
555
|
+
const restartRequired = new import_async.Trigger();
|
|
556
|
+
const url = new URL(path, this._baseWsUrl);
|
|
557
|
+
(0, import_log.log)("Opening websocket", {
|
|
558
|
+
url: url.toString(),
|
|
559
|
+
protocolHeader
|
|
560
|
+
}, {
|
|
561
|
+
F: __dxlog_file4,
|
|
562
|
+
L: 159,
|
|
563
|
+
S: this,
|
|
564
|
+
C: (f, a) => f(...a)
|
|
565
|
+
});
|
|
566
|
+
const connection = new EdgeWsConnection(identity, {
|
|
567
|
+
url,
|
|
568
|
+
protocolHeader
|
|
569
|
+
}, {
|
|
570
|
+
onConnected: () => {
|
|
571
|
+
if (this._isActive(connection)) {
|
|
572
|
+
this._ready.wake();
|
|
573
|
+
this._notifyReconnected();
|
|
574
|
+
} else {
|
|
575
|
+
import_log.log.verbose("connected callback ignored, because connection is not active", void 0, {
|
|
576
|
+
F: __dxlog_file4,
|
|
577
|
+
L: 169,
|
|
578
|
+
S: this,
|
|
579
|
+
C: (f, a) => f(...a)
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
},
|
|
583
|
+
onRestartRequired: () => {
|
|
584
|
+
if (this._isActive(connection)) {
|
|
585
|
+
this._closeCurrentConnection();
|
|
586
|
+
this._persistentLifecycle.scheduleRestart();
|
|
587
|
+
} else {
|
|
588
|
+
import_log.log.verbose("restart requested by inactive connection", void 0, {
|
|
589
|
+
F: __dxlog_file4,
|
|
590
|
+
L: 177,
|
|
591
|
+
S: this,
|
|
592
|
+
C: (f, a) => f(...a)
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
restartRequired.wake();
|
|
596
|
+
},
|
|
597
|
+
onMessage: (message) => {
|
|
598
|
+
if (this._isActive(connection)) {
|
|
599
|
+
this._notifyMessageReceived(message);
|
|
600
|
+
} else {
|
|
601
|
+
import_log.log.verbose("ignored a message on inactive connection", {
|
|
602
|
+
from: message.source,
|
|
603
|
+
type: message.payload?.typeUrl
|
|
604
|
+
}, {
|
|
605
|
+
F: __dxlog_file4,
|
|
606
|
+
L: 185,
|
|
607
|
+
S: this,
|
|
608
|
+
C: (f, a) => f(...a)
|
|
609
|
+
});
|
|
391
610
|
}
|
|
392
611
|
}
|
|
393
|
-
};
|
|
394
|
-
await this._ready.wait({
|
|
395
|
-
timeout: this._config.timeout ?? DEFAULT_TIMEOUT
|
|
396
|
-
});
|
|
397
|
-
this._keepaliveCtx = new import_context.Context(void 0, {
|
|
398
|
-
F: __dxlog_file3,
|
|
399
|
-
L: 154
|
|
400
612
|
});
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
613
|
+
this._currentConnection = connection;
|
|
614
|
+
await connection.open();
|
|
615
|
+
await Promise.race([
|
|
616
|
+
this._ready.wait({
|
|
617
|
+
timeout: this._config.timeout ?? DEFAULT_TIMEOUT
|
|
618
|
+
}),
|
|
619
|
+
restartRequired
|
|
620
|
+
]);
|
|
621
|
+
return connection;
|
|
406
622
|
}
|
|
407
|
-
async
|
|
408
|
-
|
|
409
|
-
|
|
623
|
+
async _disconnect(state) {
|
|
624
|
+
await state.close();
|
|
625
|
+
}
|
|
626
|
+
_closeCurrentConnection(error = new EdgeConnectionClosedError()) {
|
|
627
|
+
this._currentConnection = void 0;
|
|
628
|
+
this._ready.throw(error);
|
|
629
|
+
this._ready.reset();
|
|
630
|
+
}
|
|
631
|
+
_notifyReconnected() {
|
|
632
|
+
for (const listener of this._reconnectListeners) {
|
|
633
|
+
try {
|
|
634
|
+
listener();
|
|
635
|
+
} catch (err) {
|
|
636
|
+
import_log.log.error("ws reconnect listener failed", {
|
|
637
|
+
err
|
|
638
|
+
}, {
|
|
639
|
+
F: __dxlog_file4,
|
|
640
|
+
L: 218,
|
|
641
|
+
S: this,
|
|
642
|
+
C: (f, a) => f(...a)
|
|
643
|
+
});
|
|
644
|
+
}
|
|
410
645
|
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
} catch (err) {
|
|
427
|
-
if (err instanceof Error && err.message.includes("WebSocket is closed before the connection is established.")) {
|
|
428
|
-
return;
|
|
646
|
+
}
|
|
647
|
+
_notifyMessageReceived(message) {
|
|
648
|
+
for (const listener of this._messageListeners) {
|
|
649
|
+
try {
|
|
650
|
+
listener(message);
|
|
651
|
+
} catch (err) {
|
|
652
|
+
import_log.log.error("ws incoming message processing failed", {
|
|
653
|
+
err,
|
|
654
|
+
payload: import_chunk_ANV2HBEH.protocol.getPayloadType(message)
|
|
655
|
+
}, {
|
|
656
|
+
F: __dxlog_file4,
|
|
657
|
+
L: 228,
|
|
658
|
+
S: this,
|
|
659
|
+
C: (f, a) => f(...a)
|
|
660
|
+
});
|
|
429
661
|
}
|
|
430
|
-
import_log.log.warn("Error closing websocket", {
|
|
431
|
-
err
|
|
432
|
-
}, {
|
|
433
|
-
F: __dxlog_file3,
|
|
434
|
-
L: 190,
|
|
435
|
-
S: this,
|
|
436
|
-
C: (f, a) => f(...a)
|
|
437
|
-
});
|
|
438
662
|
}
|
|
439
663
|
}
|
|
440
664
|
/**
|
|
@@ -443,58 +667,349 @@ var EdgeClient = class extends import_context.Resource {
|
|
|
443
667
|
*/
|
|
444
668
|
async send(message) {
|
|
445
669
|
if (this._ready.state !== import_async.TriggerState.RESOLVED) {
|
|
670
|
+
(0, import_log.log)("waiting for websocket to become ready", void 0, {
|
|
671
|
+
F: __dxlog_file4,
|
|
672
|
+
L: 239,
|
|
673
|
+
S: this,
|
|
674
|
+
C: (f, a) => f(...a)
|
|
675
|
+
});
|
|
446
676
|
await this._ready.wait({
|
|
447
677
|
timeout: this._config.timeout ?? DEFAULT_TIMEOUT
|
|
448
678
|
});
|
|
449
679
|
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
680
|
+
if (!this._currentConnection) {
|
|
681
|
+
throw new EdgeConnectionClosedError();
|
|
682
|
+
}
|
|
683
|
+
if (message.source && (message.source.peerKey !== this._identity.peerKey || message.source.identityKey !== this.identityKey)) {
|
|
684
|
+
throw new EdgeIdentityChangedError();
|
|
685
|
+
}
|
|
686
|
+
this._currentConnection.send(message);
|
|
687
|
+
}
|
|
688
|
+
async _createAuthHeader(path) {
|
|
689
|
+
const httpUrl = new URL(path, this._baseHttpUrl);
|
|
690
|
+
httpUrl.protocol = getEdgeUrlWithProtocol(this._baseWsUrl.toString(), "http");
|
|
691
|
+
const response = await fetch(httpUrl, {
|
|
692
|
+
method: "GET"
|
|
458
693
|
});
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
694
|
+
if (response.status === 401) {
|
|
695
|
+
return encodePresentationWsAuthHeader(await handleAuthChallenge(response, this._identity));
|
|
696
|
+
} else {
|
|
697
|
+
import_log.log.warn("no auth challenge from edge", {
|
|
698
|
+
status: response.status,
|
|
699
|
+
statusText: response.statusText
|
|
700
|
+
}, {
|
|
701
|
+
F: __dxlog_file4,
|
|
702
|
+
L: 264,
|
|
703
|
+
S: this,
|
|
704
|
+
C: (f, a) => f(...a)
|
|
705
|
+
});
|
|
706
|
+
return void 0;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
};
|
|
710
|
+
_ts_decorate3([
|
|
711
|
+
import_log.logInfo
|
|
712
|
+
], EdgeClient.prototype, "info", null);
|
|
713
|
+
var encodePresentationWsAuthHeader = (encodedPresentation) => {
|
|
714
|
+
const encodedToken = Buffer.from(encodedPresentation).toString("base64").replace(/=*$/, "").replaceAll("/", "|");
|
|
715
|
+
return `base64url.bearer.authorization.dxos.org.${encodedToken}`;
|
|
716
|
+
};
|
|
717
|
+
var createDeviceEdgeIdentity = async (signer, key) => {
|
|
718
|
+
return {
|
|
719
|
+
identityKey: key.toHex(),
|
|
720
|
+
peerKey: key.toHex(),
|
|
721
|
+
presentCredentials: async ({ challenge }) => {
|
|
722
|
+
return (0, import_credentials.signPresentation)({
|
|
723
|
+
presentation: {
|
|
724
|
+
credentials: [
|
|
725
|
+
// Verifier requires at least one credential in the presentation to establish the subject.
|
|
726
|
+
await (0, import_credentials.createCredential)({
|
|
727
|
+
assertion: {
|
|
728
|
+
"@type": "dxos.halo.credentials.Auth"
|
|
729
|
+
},
|
|
730
|
+
issuer: key,
|
|
731
|
+
subject: key,
|
|
732
|
+
signer
|
|
733
|
+
})
|
|
734
|
+
]
|
|
735
|
+
},
|
|
736
|
+
signer,
|
|
737
|
+
signerKey: key,
|
|
738
|
+
nonce: challenge
|
|
739
|
+
});
|
|
740
|
+
}
|
|
741
|
+
};
|
|
742
|
+
};
|
|
743
|
+
var createChainEdgeIdentity = async (signer, identityKey, peerKey, chain, credentials) => {
|
|
744
|
+
const credentialsToSign = credentials.length > 0 ? credentials : [
|
|
745
|
+
await (0, import_credentials.createCredential)({
|
|
746
|
+
assertion: {
|
|
747
|
+
"@type": "dxos.halo.credentials.Auth"
|
|
748
|
+
},
|
|
749
|
+
issuer: identityKey,
|
|
750
|
+
subject: identityKey,
|
|
751
|
+
signer,
|
|
752
|
+
chain,
|
|
753
|
+
signingKey: peerKey
|
|
754
|
+
})
|
|
755
|
+
];
|
|
756
|
+
return {
|
|
757
|
+
identityKey: identityKey.toHex(),
|
|
758
|
+
peerKey: peerKey.toHex(),
|
|
759
|
+
presentCredentials: async ({ challenge }) => {
|
|
760
|
+
return (0, import_credentials.signPresentation)({
|
|
761
|
+
presentation: {
|
|
762
|
+
credentials: credentialsToSign
|
|
763
|
+
},
|
|
764
|
+
signer,
|
|
765
|
+
nonce: challenge,
|
|
766
|
+
signerKey: peerKey,
|
|
767
|
+
chain
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
};
|
|
771
|
+
};
|
|
772
|
+
var createEphemeralEdgeIdentity = async () => {
|
|
773
|
+
const keyring = new import_keyring.Keyring();
|
|
774
|
+
const key = await keyring.createKey();
|
|
775
|
+
return createDeviceEdgeIdentity(keyring, key);
|
|
776
|
+
};
|
|
777
|
+
var createTestHaloEdgeIdentity = async (signer, identityKey, deviceKey) => {
|
|
778
|
+
const deviceAdmission = await (0, import_credentials.createCredential)({
|
|
779
|
+
assertion: {
|
|
780
|
+
"@type": "dxos.halo.credentials.AuthorizedDevice",
|
|
781
|
+
deviceKey,
|
|
782
|
+
identityKey
|
|
783
|
+
},
|
|
784
|
+
issuer: identityKey,
|
|
785
|
+
subject: deviceKey,
|
|
786
|
+
signer
|
|
787
|
+
});
|
|
788
|
+
return createChainEdgeIdentity(signer, identityKey, deviceKey, {
|
|
789
|
+
credential: deviceAdmission
|
|
790
|
+
}, [
|
|
791
|
+
await (0, import_credentials.createCredential)({
|
|
792
|
+
assertion: {
|
|
793
|
+
"@type": "dxos.halo.credentials.Auth"
|
|
794
|
+
},
|
|
795
|
+
issuer: identityKey,
|
|
796
|
+
subject: identityKey,
|
|
797
|
+
signer
|
|
798
|
+
})
|
|
799
|
+
]);
|
|
800
|
+
};
|
|
801
|
+
var createStubEdgeIdentity = () => {
|
|
802
|
+
const identityKey = import_keys.PublicKey.random();
|
|
803
|
+
const deviceKey = import_keys.PublicKey.random();
|
|
804
|
+
return {
|
|
805
|
+
identityKey: identityKey.toHex(),
|
|
806
|
+
peerKey: deviceKey.toHex(),
|
|
807
|
+
presentCredentials: async () => {
|
|
808
|
+
throw new Error("Stub identity does not support authentication.");
|
|
809
|
+
}
|
|
810
|
+
};
|
|
811
|
+
};
|
|
812
|
+
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-http-client.ts";
|
|
813
|
+
var DEFAULT_RETRY_TIMEOUT = 1500;
|
|
814
|
+
var DEFAULT_RETRY_JITTER = 500;
|
|
815
|
+
var DEFAULT_MAX_RETRIES_COUNT = 3;
|
|
816
|
+
var EdgeHttpClient = class {
|
|
817
|
+
constructor(baseUrl) {
|
|
818
|
+
this._baseUrl = getEdgeUrlWithProtocol(baseUrl, "http");
|
|
819
|
+
(0, import_log4.log)("created", {
|
|
820
|
+
url: this._baseUrl
|
|
821
|
+
}, {
|
|
822
|
+
F: __dxlog_file5,
|
|
823
|
+
L: 42,
|
|
462
824
|
S: this,
|
|
463
|
-
|
|
464
|
-
"!message.source || message.source.peerKey === this._peerKey",
|
|
465
|
-
""
|
|
466
|
-
]
|
|
825
|
+
C: (f, a) => f(...a)
|
|
467
826
|
});
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
827
|
+
}
|
|
828
|
+
setIdentity(identity) {
|
|
829
|
+
if (this._edgeIdentity?.identityKey !== identity.identityKey || this._edgeIdentity?.peerKey !== identity.peerKey) {
|
|
830
|
+
this._edgeIdentity = identity;
|
|
831
|
+
this._authHeader = void 0;
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
createAgent(body, args) {
|
|
835
|
+
return this._call("/agents/create", {
|
|
836
|
+
...args,
|
|
837
|
+
method: "POST",
|
|
838
|
+
body
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
getAgentStatus(request, args) {
|
|
842
|
+
return this._call(`/users/${request.ownerIdentityKey.toHex()}/agent/status`, {
|
|
843
|
+
...args,
|
|
844
|
+
method: "GET"
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
getCredentialsForNotarization(spaceId, args) {
|
|
848
|
+
return this._call(`/spaces/${spaceId}/notarization`, {
|
|
849
|
+
...args,
|
|
850
|
+
method: "GET"
|
|
851
|
+
});
|
|
852
|
+
}
|
|
853
|
+
async notarizeCredentials(spaceId, body, args) {
|
|
854
|
+
await this._call(`/spaces/${spaceId}/notarization`, {
|
|
855
|
+
...args,
|
|
856
|
+
body,
|
|
857
|
+
method: "POST"
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
async joinSpaceByInvitation(spaceId, body, args) {
|
|
861
|
+
return this._call(`/spaces/${spaceId}/join`, {
|
|
862
|
+
...args,
|
|
863
|
+
body,
|
|
864
|
+
method: "POST"
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
async recoverIdentity(body, args) {
|
|
868
|
+
return this._call("/identity/recover", {
|
|
869
|
+
...args,
|
|
870
|
+
body,
|
|
871
|
+
method: "POST"
|
|
872
|
+
});
|
|
873
|
+
}
|
|
874
|
+
async _call(path, args) {
|
|
875
|
+
const requestContext = args.context ?? new import_context4.Context(void 0, {
|
|
876
|
+
F: __dxlog_file5,
|
|
877
|
+
L: 91
|
|
878
|
+
});
|
|
879
|
+
const shouldRetry = createRetryHandler(args);
|
|
880
|
+
const url = `${this._baseUrl}${path.startsWith("/") ? path.slice(1) : path}`;
|
|
881
|
+
import_log4.log.info("call", {
|
|
882
|
+
method: args.method,
|
|
883
|
+
path,
|
|
884
|
+
request: args.body
|
|
471
885
|
}, {
|
|
472
|
-
F:
|
|
473
|
-
L:
|
|
886
|
+
F: __dxlog_file5,
|
|
887
|
+
L: 95,
|
|
474
888
|
S: this,
|
|
475
889
|
C: (f, a) => f(...a)
|
|
476
890
|
});
|
|
477
|
-
|
|
891
|
+
let handledAuth = false;
|
|
892
|
+
let authHeader = this._authHeader;
|
|
893
|
+
while (true) {
|
|
894
|
+
let processingError;
|
|
895
|
+
let retryAfterHeaderValue = Number.NaN;
|
|
896
|
+
try {
|
|
897
|
+
const request = createRequest(args, authHeader);
|
|
898
|
+
const response = await fetch(url, request);
|
|
899
|
+
retryAfterHeaderValue = Number(response.headers.get("Retry-After"));
|
|
900
|
+
if (response.ok) {
|
|
901
|
+
const body = await response.json();
|
|
902
|
+
if (body.success) {
|
|
903
|
+
return body.data;
|
|
904
|
+
}
|
|
905
|
+
import_log4.log.info("unsuccessful edge response", {
|
|
906
|
+
path,
|
|
907
|
+
body
|
|
908
|
+
}, {
|
|
909
|
+
F: __dxlog_file5,
|
|
910
|
+
L: 114,
|
|
911
|
+
S: this,
|
|
912
|
+
C: (f, a) => f(...a)
|
|
913
|
+
});
|
|
914
|
+
if (body.errorData?.type === "auth_challenge" && typeof body.errorData?.challenge === "string") {
|
|
915
|
+
processingError = new import_protocols.EdgeAuthChallengeError(body.errorData.challenge, body.errorData);
|
|
916
|
+
} else {
|
|
917
|
+
processingError = import_protocols.EdgeCallFailedError.fromUnsuccessfulResponse(response, body);
|
|
918
|
+
}
|
|
919
|
+
} else if (response.status === 401 && !handledAuth) {
|
|
920
|
+
authHeader = await this._handleUnauthorized(response);
|
|
921
|
+
handledAuth = true;
|
|
922
|
+
continue;
|
|
923
|
+
} else {
|
|
924
|
+
processingError = import_protocols.EdgeCallFailedError.fromHttpFailure(response);
|
|
925
|
+
}
|
|
926
|
+
} catch (error) {
|
|
927
|
+
processingError = import_protocols.EdgeCallFailedError.fromProcessingFailureCause(error);
|
|
928
|
+
}
|
|
929
|
+
if (processingError.isRetryable && await shouldRetry(requestContext, retryAfterHeaderValue)) {
|
|
930
|
+
import_log4.log.info("retrying edge request", {
|
|
931
|
+
path,
|
|
932
|
+
processingError
|
|
933
|
+
}, {
|
|
934
|
+
F: __dxlog_file5,
|
|
935
|
+
L: 133,
|
|
936
|
+
S: this,
|
|
937
|
+
C: (f, a) => f(...a)
|
|
938
|
+
});
|
|
939
|
+
} else {
|
|
940
|
+
throw processingError;
|
|
941
|
+
}
|
|
942
|
+
}
|
|
478
943
|
}
|
|
479
|
-
|
|
480
|
-
if (this.
|
|
481
|
-
|
|
944
|
+
async _handleUnauthorized(response) {
|
|
945
|
+
if (!this._edgeIdentity) {
|
|
946
|
+
import_log4.log.warn("edge unauthorized response received before identity was set", void 0, {
|
|
947
|
+
F: __dxlog_file5,
|
|
948
|
+
L: 142,
|
|
949
|
+
S: this,
|
|
950
|
+
C: (f, a) => f(...a)
|
|
951
|
+
});
|
|
952
|
+
throw import_protocols.EdgeCallFailedError.fromHttpFailure(response);
|
|
482
953
|
}
|
|
483
|
-
|
|
484
|
-
this.
|
|
485
|
-
|
|
486
|
-
|
|
954
|
+
const challenge = await handleAuthChallenge(response, this._edgeIdentity);
|
|
955
|
+
this._authHeader = encodeAuthHeader(challenge);
|
|
956
|
+
(0, import_log4.log)("auth header updated", void 0, {
|
|
957
|
+
F: __dxlog_file5,
|
|
958
|
+
L: 147,
|
|
959
|
+
S: this,
|
|
960
|
+
C: (f, a) => f(...a)
|
|
487
961
|
});
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
962
|
+
return this._authHeader;
|
|
963
|
+
}
|
|
964
|
+
};
|
|
965
|
+
var createRetryHandler = (args) => {
|
|
966
|
+
if (!args.retry || args.retry.count < 1) {
|
|
967
|
+
return async () => false;
|
|
491
968
|
}
|
|
969
|
+
let retries = 0;
|
|
970
|
+
const maxRetries = args.retry.count ?? DEFAULT_MAX_RETRIES_COUNT;
|
|
971
|
+
const baseTimeout = args.retry.timeout ?? DEFAULT_RETRY_TIMEOUT;
|
|
972
|
+
const jitter = args.retry.jitter ?? DEFAULT_RETRY_JITTER;
|
|
973
|
+
return async (ctx, retryAfter) => {
|
|
974
|
+
if (++retries > maxRetries || ctx.disposed) {
|
|
975
|
+
return false;
|
|
976
|
+
}
|
|
977
|
+
if (retryAfter) {
|
|
978
|
+
await (0, import_async4.sleep)(retryAfter);
|
|
979
|
+
} else {
|
|
980
|
+
const timeout = baseTimeout + Math.random() * jitter;
|
|
981
|
+
await (0, import_async4.sleep)(timeout);
|
|
982
|
+
}
|
|
983
|
+
return true;
|
|
984
|
+
};
|
|
985
|
+
};
|
|
986
|
+
var createRequest = (args, authHeader) => {
|
|
987
|
+
return {
|
|
988
|
+
method: args.method,
|
|
989
|
+
body: args.body && JSON.stringify(args.body),
|
|
990
|
+
headers: authHeader ? {
|
|
991
|
+
Authorization: authHeader
|
|
992
|
+
} : void 0
|
|
993
|
+
};
|
|
994
|
+
};
|
|
995
|
+
var encodeAuthHeader = (challenge) => {
|
|
996
|
+
const encodedChallenge = Buffer.from(challenge).toString("base64");
|
|
997
|
+
return `VerifiablePresentation pb;base64,${encodedChallenge}`;
|
|
492
998
|
};
|
|
493
999
|
// Annotate the CommonJS export names for ESM import in node:
|
|
494
1000
|
0 && (module.exports = {
|
|
495
1001
|
EdgeClient,
|
|
1002
|
+
EdgeConnectionClosedError,
|
|
1003
|
+
EdgeHttpClient,
|
|
1004
|
+
EdgeIdentityChangedError,
|
|
496
1005
|
Protocol,
|
|
1006
|
+
createChainEdgeIdentity,
|
|
1007
|
+
createDeviceEdgeIdentity,
|
|
1008
|
+
createEphemeralEdgeIdentity,
|
|
1009
|
+
createStubEdgeIdentity,
|
|
1010
|
+
createTestHaloEdgeIdentity,
|
|
497
1011
|
getTypename,
|
|
1012
|
+
handleAuthChallenge,
|
|
498
1013
|
protocol,
|
|
499
1014
|
toUint8Array,
|
|
500
1015
|
...require("@dxos/protocols/buf/dxos/edge/messenger_pb")
|