@dxos/edge-client 0.8.4-main.fd6878d → 0.8.4-main.fffef41
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-SUXH7FH6.mjs → chunk-VESGVCLQ.mjs} +4 -7
- package/dist/lib/browser/{chunk-SUXH7FH6.mjs.map → chunk-VESGVCLQ.mjs.map} +2 -2
- package/dist/lib/browser/edge-ws-muxer.mjs +1 -1
- package/dist/lib/browser/index.mjs +525 -287
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +1 -1
- package/dist/lib/browser/testing/index.mjs.map +2 -2
- package/dist/lib/node-esm/{chunk-R6K4IIBW.mjs → chunk-JTBFRYNM.mjs} +4 -7
- package/dist/lib/node-esm/{chunk-R6K4IIBW.mjs.map → chunk-JTBFRYNM.mjs.map} +2 -2
- package/dist/lib/node-esm/edge-ws-muxer.mjs +1 -1
- package/dist/lib/node-esm/index.mjs +525 -287
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +1 -1
- package/dist/lib/node-esm/testing/index.mjs.map +2 -2
- package/dist/types/src/edge-client.d.ts +14 -14
- package/dist/types/src/edge-client.d.ts.map +1 -1
- package/dist/types/src/edge-http-client.d.ts +30 -4
- package/dist/types/src/edge-http-client.d.ts.map +1 -1
- package/dist/types/src/edge-ws-connection.d.ts +19 -0
- package/dist/types/src/edge-ws-connection.d.ts.map +1 -1
- package/dist/types/src/http-client.d.ts +10 -7
- package/dist/types/src/http-client.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +4 -3
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/testing/test-utils.d.ts +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +15 -15
- package/src/edge-client.test.ts +4 -4
- package/src/edge-client.ts +72 -41
- package/src/edge-http-client.test.ts +1 -1
- package/src/edge-http-client.ts +188 -33
- package/src/edge-ws-connection.ts +118 -5
- package/src/http-client.test.ts +8 -5
- package/src/http-client.ts +18 -8
- package/src/index.ts +4 -3
- package/src/testing/test-utils.ts +3 -3
|
@@ -6,24 +6,135 @@ import {
|
|
|
6
6
|
getTypename,
|
|
7
7
|
protocol,
|
|
8
8
|
toUint8Array
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-VESGVCLQ.mjs";
|
|
10
10
|
|
|
11
11
|
// src/index.ts
|
|
12
12
|
export * from "@dxos/protocols/buf/dxos/edge/messenger_pb";
|
|
13
13
|
|
|
14
|
+
// src/auth.ts
|
|
15
|
+
import { createCredential, signPresentation } from "@dxos/credentials";
|
|
16
|
+
import { invariant } from "@dxos/invariant";
|
|
17
|
+
import { Keyring } from "@dxos/keyring";
|
|
18
|
+
import { PublicKey } from "@dxos/keys";
|
|
19
|
+
var __dxlog_file = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/auth.ts";
|
|
20
|
+
var createDeviceEdgeIdentity = async (signer, key) => {
|
|
21
|
+
return {
|
|
22
|
+
identityKey: key.toHex(),
|
|
23
|
+
peerKey: key.toHex(),
|
|
24
|
+
presentCredentials: async ({ challenge }) => {
|
|
25
|
+
return signPresentation({
|
|
26
|
+
presentation: {
|
|
27
|
+
credentials: [
|
|
28
|
+
// Verifier requires at least one credential in the presentation to establish the subject.
|
|
29
|
+
await createCredential({
|
|
30
|
+
assertion: {
|
|
31
|
+
"@type": "dxos.halo.credentials.Auth"
|
|
32
|
+
},
|
|
33
|
+
issuer: key,
|
|
34
|
+
subject: key,
|
|
35
|
+
signer
|
|
36
|
+
})
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
signer,
|
|
40
|
+
signerKey: key,
|
|
41
|
+
nonce: challenge
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
var createChainEdgeIdentity = async (signer, identityKey, peerKey, chain, credentials) => {
|
|
47
|
+
const credentialsToSign = credentials.length > 0 ? credentials : [
|
|
48
|
+
await createCredential({
|
|
49
|
+
assertion: {
|
|
50
|
+
"@type": "dxos.halo.credentials.Auth"
|
|
51
|
+
},
|
|
52
|
+
issuer: identityKey,
|
|
53
|
+
subject: identityKey,
|
|
54
|
+
signer,
|
|
55
|
+
chain,
|
|
56
|
+
signingKey: peerKey
|
|
57
|
+
})
|
|
58
|
+
];
|
|
59
|
+
return {
|
|
60
|
+
identityKey: identityKey.toHex(),
|
|
61
|
+
peerKey: peerKey.toHex(),
|
|
62
|
+
presentCredentials: async ({ challenge }) => {
|
|
63
|
+
invariant(chain, void 0, {
|
|
64
|
+
F: __dxlog_file,
|
|
65
|
+
L: 75,
|
|
66
|
+
S: void 0,
|
|
67
|
+
A: [
|
|
68
|
+
"chain",
|
|
69
|
+
""
|
|
70
|
+
]
|
|
71
|
+
});
|
|
72
|
+
return signPresentation({
|
|
73
|
+
presentation: {
|
|
74
|
+
credentials: credentialsToSign
|
|
75
|
+
},
|
|
76
|
+
signer,
|
|
77
|
+
nonce: challenge,
|
|
78
|
+
signerKey: peerKey,
|
|
79
|
+
chain
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
var createEphemeralEdgeIdentity = async () => {
|
|
85
|
+
const keyring = new Keyring();
|
|
86
|
+
const key = await keyring.createKey();
|
|
87
|
+
return createDeviceEdgeIdentity(keyring, key);
|
|
88
|
+
};
|
|
89
|
+
var createTestHaloEdgeIdentity = async (signer, identityKey, deviceKey) => {
|
|
90
|
+
const deviceAdmission = await createCredential({
|
|
91
|
+
assertion: {
|
|
92
|
+
"@type": "dxos.halo.credentials.AuthorizedDevice",
|
|
93
|
+
deviceKey,
|
|
94
|
+
identityKey
|
|
95
|
+
},
|
|
96
|
+
issuer: identityKey,
|
|
97
|
+
subject: deviceKey,
|
|
98
|
+
signer
|
|
99
|
+
});
|
|
100
|
+
return createChainEdgeIdentity(signer, identityKey, deviceKey, {
|
|
101
|
+
credential: deviceAdmission
|
|
102
|
+
}, [
|
|
103
|
+
await createCredential({
|
|
104
|
+
assertion: {
|
|
105
|
+
"@type": "dxos.halo.credentials.Auth"
|
|
106
|
+
},
|
|
107
|
+
issuer: identityKey,
|
|
108
|
+
subject: identityKey,
|
|
109
|
+
signer
|
|
110
|
+
})
|
|
111
|
+
]);
|
|
112
|
+
};
|
|
113
|
+
var createStubEdgeIdentity = () => {
|
|
114
|
+
const identityKey = PublicKey.random();
|
|
115
|
+
const deviceKey = PublicKey.random();
|
|
116
|
+
return {
|
|
117
|
+
identityKey: identityKey.toHex(),
|
|
118
|
+
peerKey: deviceKey.toHex(),
|
|
119
|
+
presentCredentials: async () => {
|
|
120
|
+
throw new Error("Stub identity does not support authentication.");
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
|
|
14
125
|
// src/edge-client.ts
|
|
15
|
-
import { Event, PersistentLifecycle, Trigger, TriggerState, scheduleMicroTask } from "@dxos/async";
|
|
126
|
+
import { Event, PersistentLifecycle, Trigger, TriggerState, scheduleMicroTask, scheduleTaskInterval as scheduleTaskInterval2 } from "@dxos/async";
|
|
16
127
|
import { Resource as Resource2 } from "@dxos/context";
|
|
17
128
|
import { log as log2, logInfo as logInfo2 } from "@dxos/log";
|
|
18
129
|
import { EdgeStatus } from "@dxos/protocols/proto/dxos/client/services";
|
|
19
130
|
|
|
20
131
|
// src/edge-identity.ts
|
|
21
|
-
import { invariant } from "@dxos/invariant";
|
|
132
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
22
133
|
import { schema } from "@dxos/protocols/proto";
|
|
23
|
-
var
|
|
134
|
+
var __dxlog_file2 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/edge-identity.ts";
|
|
24
135
|
var handleAuthChallenge = async (failedResponse, identity) => {
|
|
25
|
-
|
|
26
|
-
F:
|
|
136
|
+
invariant2(failedResponse.status === 401, void 0, {
|
|
137
|
+
F: __dxlog_file2,
|
|
27
138
|
L: 21,
|
|
28
139
|
S: void 0,
|
|
29
140
|
A: [
|
|
@@ -32,8 +143,8 @@ var handleAuthChallenge = async (failedResponse, identity) => {
|
|
|
32
143
|
]
|
|
33
144
|
});
|
|
34
145
|
const headerValue = failedResponse.headers.get("Www-Authenticate");
|
|
35
|
-
|
|
36
|
-
F:
|
|
146
|
+
invariant2(headerValue?.startsWith("VerifiablePresentation challenge="), void 0, {
|
|
147
|
+
F: __dxlog_file2,
|
|
37
148
|
L: 24,
|
|
38
149
|
S: void 0,
|
|
39
150
|
A: [
|
|
@@ -42,8 +153,8 @@ var handleAuthChallenge = async (failedResponse, identity) => {
|
|
|
42
153
|
]
|
|
43
154
|
});
|
|
44
155
|
const challenge = headerValue?.slice("VerifiablePresentation challenge=".length);
|
|
45
|
-
|
|
46
|
-
F:
|
|
156
|
+
invariant2(challenge, void 0, {
|
|
157
|
+
F: __dxlog_file2,
|
|
47
158
|
L: 27,
|
|
48
159
|
S: void 0,
|
|
49
160
|
A: [
|
|
@@ -61,7 +172,7 @@ var handleAuthChallenge = async (failedResponse, identity) => {
|
|
|
61
172
|
import WebSocket from "isomorphic-ws";
|
|
62
173
|
import { scheduleTask, scheduleTaskInterval } from "@dxos/async";
|
|
63
174
|
import { Context, Resource } from "@dxos/context";
|
|
64
|
-
import { invariant as
|
|
175
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
65
176
|
import { log, logInfo } from "@dxos/log";
|
|
66
177
|
import { EdgeWebsocketProtocol } from "@dxos/protocols";
|
|
67
178
|
import { buf } from "@dxos/protocols/buf";
|
|
@@ -72,7 +183,7 @@ function _ts_decorate(decorators, target, key, desc) {
|
|
|
72
183
|
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;
|
|
73
184
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
74
185
|
}
|
|
75
|
-
var
|
|
186
|
+
var __dxlog_file3 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/edge-ws-connection.ts";
|
|
76
187
|
var SIGNAL_KEEPALIVE_INTERVAL = 4e3;
|
|
77
188
|
var SIGNAL_KEEPALIVE_TIMEOUT = 12e3;
|
|
78
189
|
var EdgeWsConnection = class extends Resource {
|
|
@@ -82,9 +193,21 @@ var EdgeWsConnection = class extends Resource {
|
|
|
82
193
|
_inactivityTimeoutCtx;
|
|
83
194
|
_ws;
|
|
84
195
|
_wsMuxer;
|
|
85
|
-
_lastReceivedMessageTimestamp;
|
|
196
|
+
_lastReceivedMessageTimestamp = Date.now();
|
|
197
|
+
_openTimestamp;
|
|
198
|
+
// Latency tracking.
|
|
199
|
+
_pingTimestamp;
|
|
200
|
+
_rtt = 0;
|
|
201
|
+
// Rate tracking with sliding window.
|
|
202
|
+
_uploadRate = 0;
|
|
203
|
+
_downloadRate = 0;
|
|
204
|
+
_rateWindow = 1e4;
|
|
205
|
+
_rateUpdateInterval = 1e3;
|
|
206
|
+
_bytesSamples = [];
|
|
207
|
+
_messagesSent = 0;
|
|
208
|
+
_messagesReceived = 0;
|
|
86
209
|
constructor(_identity, _connectionInfo, _callbacks) {
|
|
87
|
-
super(), this._identity = _identity, this._connectionInfo = _connectionInfo, this._callbacks = _callbacks
|
|
210
|
+
super(), this._identity = _identity, this._connectionInfo = _connectionInfo, this._callbacks = _callbacks;
|
|
88
211
|
}
|
|
89
212
|
get info() {
|
|
90
213
|
return {
|
|
@@ -93,19 +216,37 @@ var EdgeWsConnection = class extends Resource {
|
|
|
93
216
|
device: this._identity.peerKey
|
|
94
217
|
};
|
|
95
218
|
}
|
|
219
|
+
get rtt() {
|
|
220
|
+
return this._rtt;
|
|
221
|
+
}
|
|
222
|
+
get uptime() {
|
|
223
|
+
return this._openTimestamp ? (Date.now() - this._openTimestamp) / 1e3 : 0;
|
|
224
|
+
}
|
|
225
|
+
get uploadRate() {
|
|
226
|
+
return this._uploadRate;
|
|
227
|
+
}
|
|
228
|
+
get downloadRate() {
|
|
229
|
+
return this._downloadRate;
|
|
230
|
+
}
|
|
231
|
+
get messagesSent() {
|
|
232
|
+
return this._messagesSent;
|
|
233
|
+
}
|
|
234
|
+
get messagesReceived() {
|
|
235
|
+
return this._messagesReceived;
|
|
236
|
+
}
|
|
96
237
|
send(message) {
|
|
97
|
-
|
|
98
|
-
F:
|
|
99
|
-
L:
|
|
238
|
+
invariant3(this._ws, void 0, {
|
|
239
|
+
F: __dxlog_file3,
|
|
240
|
+
L: 93,
|
|
100
241
|
S: this,
|
|
101
242
|
A: [
|
|
102
243
|
"this._ws",
|
|
103
244
|
""
|
|
104
245
|
]
|
|
105
246
|
});
|
|
106
|
-
|
|
107
|
-
F:
|
|
108
|
-
L:
|
|
247
|
+
invariant3(this._wsMuxer, void 0, {
|
|
248
|
+
F: __dxlog_file3,
|
|
249
|
+
L: 94,
|
|
109
250
|
S: this,
|
|
110
251
|
A: [
|
|
111
252
|
"this._wsMuxer",
|
|
@@ -116,11 +257,12 @@ var EdgeWsConnection = class extends Resource {
|
|
|
116
257
|
peerKey: this._identity.peerKey,
|
|
117
258
|
payload: protocol.getPayloadType(message)
|
|
118
259
|
}, {
|
|
119
|
-
F:
|
|
120
|
-
L:
|
|
260
|
+
F: __dxlog_file3,
|
|
261
|
+
L: 95,
|
|
121
262
|
S: this,
|
|
122
263
|
C: (f, a) => f(...a)
|
|
123
264
|
});
|
|
265
|
+
this._messagesSent++;
|
|
124
266
|
if (this._ws?.protocol.includes(EdgeWebsocketProtocol.V0)) {
|
|
125
267
|
const binary = buf.toBinary(MessageSchema, message);
|
|
126
268
|
if (binary.length > CLOUDFLARE_MESSAGE_MAX_BYTES) {
|
|
@@ -129,18 +271,21 @@ var EdgeWsConnection = class extends Resource {
|
|
|
129
271
|
serviceId: message.serviceId,
|
|
130
272
|
payload: protocol.getPayloadType(message)
|
|
131
273
|
}, {
|
|
132
|
-
F:
|
|
133
|
-
L:
|
|
274
|
+
F: __dxlog_file3,
|
|
275
|
+
L: 100,
|
|
134
276
|
S: this,
|
|
135
277
|
C: (f, a) => f(...a)
|
|
136
278
|
});
|
|
137
279
|
return;
|
|
138
280
|
}
|
|
281
|
+
this._recordBytes(binary.byteLength, 0);
|
|
139
282
|
this._ws.send(binary);
|
|
140
283
|
} else {
|
|
284
|
+
const binary = buf.toBinary(MessageSchema, message);
|
|
285
|
+
this._recordBytes(binary.byteLength, 0);
|
|
141
286
|
this._wsMuxer.send(message).catch((e) => log.catch(e, void 0, {
|
|
142
|
-
F:
|
|
143
|
-
L:
|
|
287
|
+
F: __dxlog_file3,
|
|
288
|
+
L: 113,
|
|
144
289
|
S: this,
|
|
145
290
|
C: (f, a) => f(...a)
|
|
146
291
|
}));
|
|
@@ -161,19 +306,21 @@ var EdgeWsConnection = class extends Resource {
|
|
|
161
306
|
this._ws.onopen = () => {
|
|
162
307
|
if (this.isOpen) {
|
|
163
308
|
log("connected", void 0, {
|
|
164
|
-
F:
|
|
165
|
-
L:
|
|
309
|
+
F: __dxlog_file3,
|
|
310
|
+
L: 130,
|
|
166
311
|
S: this,
|
|
167
312
|
C: (f, a) => f(...a)
|
|
168
313
|
});
|
|
314
|
+
this._openTimestamp = Date.now();
|
|
169
315
|
this._callbacks.onConnected();
|
|
170
316
|
this._scheduleHeartbeats();
|
|
317
|
+
this._scheduleRateCalculation();
|
|
171
318
|
} else {
|
|
172
319
|
log.verbose("connected after becoming inactive", {
|
|
173
320
|
currentIdentity: this._identity
|
|
174
321
|
}, {
|
|
175
|
-
F:
|
|
176
|
-
L:
|
|
322
|
+
F: __dxlog_file3,
|
|
323
|
+
L: 136,
|
|
177
324
|
S: this,
|
|
178
325
|
C: (f, a) => f(...a)
|
|
179
326
|
});
|
|
@@ -181,12 +328,12 @@ var EdgeWsConnection = class extends Resource {
|
|
|
181
328
|
};
|
|
182
329
|
this._ws.onclose = (event) => {
|
|
183
330
|
if (this.isOpen) {
|
|
184
|
-
log.warn("disconnected
|
|
331
|
+
log.warn("server disconnected", {
|
|
185
332
|
code: event.code,
|
|
186
333
|
reason: event.reason
|
|
187
334
|
}, {
|
|
188
|
-
F:
|
|
189
|
-
L:
|
|
335
|
+
F: __dxlog_file3,
|
|
336
|
+
L: 141,
|
|
190
337
|
S: this,
|
|
191
338
|
C: (f, a) => f(...a)
|
|
192
339
|
});
|
|
@@ -200,8 +347,8 @@ var EdgeWsConnection = class extends Resource {
|
|
|
200
347
|
error: event.error,
|
|
201
348
|
info: event.message
|
|
202
349
|
}, {
|
|
203
|
-
F:
|
|
204
|
-
L:
|
|
350
|
+
F: __dxlog_file3,
|
|
351
|
+
L: 148,
|
|
205
352
|
S: this,
|
|
206
353
|
C: (f, a) => f(...a)
|
|
207
354
|
});
|
|
@@ -210,8 +357,8 @@ var EdgeWsConnection = class extends Resource {
|
|
|
210
357
|
log.verbose("error ignored on closed connection", {
|
|
211
358
|
error: event.error
|
|
212
359
|
}, {
|
|
213
|
-
F:
|
|
214
|
-
L:
|
|
360
|
+
F: __dxlog_file3,
|
|
361
|
+
L: 151,
|
|
215
362
|
S: this,
|
|
216
363
|
C: (f, a) => f(...a)
|
|
217
364
|
});
|
|
@@ -222,8 +369,8 @@ var EdgeWsConnection = class extends Resource {
|
|
|
222
369
|
log.verbose("message ignored on closed connection", {
|
|
223
370
|
event: event.type
|
|
224
371
|
}, {
|
|
225
|
-
F:
|
|
226
|
-
L:
|
|
372
|
+
F: __dxlog_file3,
|
|
373
|
+
L: 159,
|
|
227
374
|
S: this,
|
|
228
375
|
C: (f, a) => f(...a)
|
|
229
376
|
});
|
|
@@ -231,21 +378,27 @@ var EdgeWsConnection = class extends Resource {
|
|
|
231
378
|
}
|
|
232
379
|
this._lastReceivedMessageTimestamp = Date.now();
|
|
233
380
|
if (event.data === "__pong__") {
|
|
381
|
+
if (this._pingTimestamp) {
|
|
382
|
+
this._rtt = Date.now() - this._pingTimestamp;
|
|
383
|
+
this._pingTimestamp = void 0;
|
|
384
|
+
}
|
|
234
385
|
this._rescheduleHeartbeatTimeout();
|
|
235
386
|
return;
|
|
236
387
|
}
|
|
237
388
|
const bytes = await toUint8Array(event.data);
|
|
389
|
+
this._recordBytes(0, bytes.byteLength);
|
|
238
390
|
if (!this.isOpen) {
|
|
239
391
|
return;
|
|
240
392
|
}
|
|
393
|
+
this._messagesReceived++;
|
|
241
394
|
const message = this._ws?.protocol?.includes(EdgeWebsocketProtocol.V0) ? buf.fromBinary(MessageSchema, bytes) : muxer.receiveData(bytes);
|
|
242
395
|
if (message) {
|
|
243
396
|
log("received", {
|
|
244
397
|
from: message.source,
|
|
245
398
|
payload: protocol.getPayloadType(message)
|
|
246
399
|
}, {
|
|
247
|
-
F:
|
|
248
|
-
L:
|
|
400
|
+
F: __dxlog_file3,
|
|
401
|
+
L: 185,
|
|
249
402
|
S: this,
|
|
250
403
|
C: (f, a) => f(...a)
|
|
251
404
|
});
|
|
@@ -265,20 +418,20 @@ var EdgeWsConnection = class extends Resource {
|
|
|
265
418
|
if (err instanceof Error && err.message.includes("WebSocket is closed before the connection is established.")) {
|
|
266
419
|
return;
|
|
267
420
|
}
|
|
268
|
-
log.warn("
|
|
421
|
+
log.warn("error closing websocket", {
|
|
269
422
|
err
|
|
270
423
|
}, {
|
|
271
|
-
F:
|
|
272
|
-
L:
|
|
424
|
+
F: __dxlog_file3,
|
|
425
|
+
L: 203,
|
|
273
426
|
S: this,
|
|
274
427
|
C: (f, a) => f(...a)
|
|
275
428
|
});
|
|
276
429
|
}
|
|
277
430
|
}
|
|
278
431
|
_scheduleHeartbeats() {
|
|
279
|
-
|
|
280
|
-
F:
|
|
281
|
-
L:
|
|
432
|
+
invariant3(this._ws, void 0, {
|
|
433
|
+
F: __dxlog_file3,
|
|
434
|
+
L: 208,
|
|
282
435
|
S: this,
|
|
283
436
|
A: [
|
|
284
437
|
"this._ws",
|
|
@@ -286,8 +439,10 @@ var EdgeWsConnection = class extends Resource {
|
|
|
286
439
|
]
|
|
287
440
|
});
|
|
288
441
|
scheduleTaskInterval(this._ctx, async () => {
|
|
442
|
+
this._pingTimestamp = Date.now();
|
|
289
443
|
this._ws?.send("__ping__");
|
|
290
444
|
}, SIGNAL_KEEPALIVE_INTERVAL);
|
|
445
|
+
this._pingTimestamp = Date.now();
|
|
291
446
|
this._ws.send("__ping__");
|
|
292
447
|
this._rescheduleHeartbeatTimeout();
|
|
293
448
|
}
|
|
@@ -297,8 +452,8 @@ var EdgeWsConnection = class extends Resource {
|
|
|
297
452
|
}
|
|
298
453
|
void this._inactivityTimeoutCtx?.dispose();
|
|
299
454
|
this._inactivityTimeoutCtx = new Context(void 0, {
|
|
300
|
-
F:
|
|
301
|
-
L:
|
|
455
|
+
F: __dxlog_file3,
|
|
456
|
+
L: 229
|
|
302
457
|
});
|
|
303
458
|
scheduleTask(this._inactivityTimeoutCtx, () => {
|
|
304
459
|
if (this.isOpen) {
|
|
@@ -306,8 +461,8 @@ var EdgeWsConnection = class extends Resource {
|
|
|
306
461
|
log.warn("restart due to inactivity timeout", {
|
|
307
462
|
lastReceivedMessageTimestamp: this._lastReceivedMessageTimestamp
|
|
308
463
|
}, {
|
|
309
|
-
F:
|
|
310
|
-
L:
|
|
464
|
+
F: __dxlog_file3,
|
|
465
|
+
L: 235,
|
|
311
466
|
S: this,
|
|
312
467
|
C: (f, a) => f(...a)
|
|
313
468
|
});
|
|
@@ -318,6 +473,47 @@ var EdgeWsConnection = class extends Resource {
|
|
|
318
473
|
}
|
|
319
474
|
}, SIGNAL_KEEPALIVE_TIMEOUT);
|
|
320
475
|
}
|
|
476
|
+
_recordBytes(sent, received) {
|
|
477
|
+
const now = Date.now();
|
|
478
|
+
const currentSecond = Math.floor(now / 1e3) * 1e3;
|
|
479
|
+
const existingSample = this._bytesSamples.find((s) => Math.floor(s.timestamp / 1e3) * 1e3 === currentSecond);
|
|
480
|
+
if (existingSample) {
|
|
481
|
+
existingSample.sent += sent;
|
|
482
|
+
existingSample.received += received;
|
|
483
|
+
} else {
|
|
484
|
+
this._bytesSamples.push({
|
|
485
|
+
timestamp: now,
|
|
486
|
+
sent,
|
|
487
|
+
received
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
_scheduleRateCalculation() {
|
|
492
|
+
scheduleTaskInterval(this._ctx, async () => {
|
|
493
|
+
this._calculateRates();
|
|
494
|
+
}, this._rateUpdateInterval);
|
|
495
|
+
this._calculateRates();
|
|
496
|
+
}
|
|
497
|
+
_calculateRates() {
|
|
498
|
+
const now = Date.now();
|
|
499
|
+
const cutoff = now - this._rateWindow;
|
|
500
|
+
this._bytesSamples = this._bytesSamples.filter((s) => s.timestamp > cutoff);
|
|
501
|
+
if (this._bytesSamples.length === 0) {
|
|
502
|
+
this._uploadRate = 0;
|
|
503
|
+
this._downloadRate = 0;
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
let totalSent = 0;
|
|
507
|
+
let totalReceived = 0;
|
|
508
|
+
const oldestTimestamp = Math.min(...this._bytesSamples.map((s) => s.timestamp));
|
|
509
|
+
const timeSpan = (now - oldestTimestamp) / 1e3;
|
|
510
|
+
for (const sample of this._bytesSamples) {
|
|
511
|
+
totalSent += sample.sent;
|
|
512
|
+
totalReceived += sample.received;
|
|
513
|
+
}
|
|
514
|
+
this._uploadRate = timeSpan > 0 ? Math.round(totalSent / timeSpan) : 0;
|
|
515
|
+
this._downloadRate = timeSpan > 0 ? Math.round(totalReceived / timeSpan) : 0;
|
|
516
|
+
}
|
|
321
517
|
};
|
|
322
518
|
_ts_decorate([
|
|
323
519
|
logInfo
|
|
@@ -350,24 +546,25 @@ function _ts_decorate2(decorators, target, key, desc) {
|
|
|
350
546
|
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;
|
|
351
547
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
352
548
|
}
|
|
353
|
-
var
|
|
549
|
+
var __dxlog_file4 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/edge-client.ts";
|
|
354
550
|
var DEFAULT_TIMEOUT = 1e4;
|
|
551
|
+
var STATUS_REFRESH_INTERVAL = 1e3;
|
|
355
552
|
var EdgeClient = class extends Resource2 {
|
|
356
553
|
_identity;
|
|
357
554
|
_config;
|
|
358
|
-
statusChanged;
|
|
359
|
-
_persistentLifecycle
|
|
360
|
-
|
|
361
|
-
|
|
555
|
+
statusChanged = new Event();
|
|
556
|
+
_persistentLifecycle = new PersistentLifecycle({
|
|
557
|
+
start: async () => this._connect(),
|
|
558
|
+
stop: async (state) => this._disconnect(state)
|
|
559
|
+
});
|
|
560
|
+
_messageListeners = /* @__PURE__ */ new Set();
|
|
561
|
+
_reconnectListeners = /* @__PURE__ */ new Set();
|
|
362
562
|
_baseWsUrl;
|
|
363
563
|
_baseHttpUrl;
|
|
364
|
-
_currentConnection;
|
|
365
|
-
_ready;
|
|
564
|
+
_currentConnection = void 0;
|
|
565
|
+
_ready = new Trigger();
|
|
366
566
|
constructor(_identity, _config) {
|
|
367
|
-
super(), this._identity = _identity, this._config = _config
|
|
368
|
-
start: async () => this._connect(),
|
|
369
|
-
stop: async (state) => this._disconnect(state)
|
|
370
|
-
}), this._messageListeners = /* @__PURE__ */ new Set(), this._reconnectListeners = /* @__PURE__ */ new Set(), this._currentConnection = void 0, this._ready = new Trigger(), this._isActive = (connection) => connection === this._currentConnection;
|
|
567
|
+
super(), this._identity = _identity, this._config = _config;
|
|
371
568
|
this._baseWsUrl = getEdgeUrlWithProtocol(_config.socketEndpoint, "ws");
|
|
372
569
|
this._baseHttpUrl = getEdgeUrlWithProtocol(_config.socketEndpoint, "http");
|
|
373
570
|
}
|
|
@@ -380,7 +577,15 @@ var EdgeClient = class extends Resource2 {
|
|
|
380
577
|
};
|
|
381
578
|
}
|
|
382
579
|
get status() {
|
|
383
|
-
return
|
|
580
|
+
return {
|
|
581
|
+
state: Boolean(this._currentConnection) && this._ready.state === TriggerState.RESOLVED ? EdgeStatus.ConnectionState.CONNECTED : EdgeStatus.ConnectionState.NOT_CONNECTED,
|
|
582
|
+
uptime: this._currentConnection?.uptime ?? 0,
|
|
583
|
+
rtt: this._currentConnection?.rtt ?? 0,
|
|
584
|
+
rateBytesUp: this._currentConnection?.uploadRate ?? 0,
|
|
585
|
+
rateBytesDown: this._currentConnection?.downloadRate ?? 0,
|
|
586
|
+
messagesSent: this._currentConnection?.messagesSent ?? 0,
|
|
587
|
+
messagesReceived: this._currentConnection?.messagesReceived ?? 0
|
|
588
|
+
};
|
|
384
589
|
}
|
|
385
590
|
get identityKey() {
|
|
386
591
|
return this._identity.identityKey;
|
|
@@ -394,8 +599,8 @@ var EdgeClient = class extends Resource2 {
|
|
|
394
599
|
identity,
|
|
395
600
|
oldIdentity: this._identity
|
|
396
601
|
}, {
|
|
397
|
-
F:
|
|
398
|
-
L:
|
|
602
|
+
F: __dxlog_file4,
|
|
603
|
+
L: 118,
|
|
399
604
|
S: this,
|
|
400
605
|
C: (f, a) => f(...a)
|
|
401
606
|
});
|
|
@@ -404,6 +609,30 @@ var EdgeClient = class extends Resource2 {
|
|
|
404
609
|
void this._persistentLifecycle.scheduleRestart();
|
|
405
610
|
}
|
|
406
611
|
}
|
|
612
|
+
/**
|
|
613
|
+
* Send message.
|
|
614
|
+
* NOTE: The message is guaranteed to be delivered but the service must respond with a message to confirm processing.
|
|
615
|
+
*/
|
|
616
|
+
async send(message) {
|
|
617
|
+
if (this._ready.state !== TriggerState.RESOLVED) {
|
|
618
|
+
log2("waiting for websocket", void 0, {
|
|
619
|
+
F: __dxlog_file4,
|
|
620
|
+
L: 131,
|
|
621
|
+
S: this,
|
|
622
|
+
C: (f, a) => f(...a)
|
|
623
|
+
});
|
|
624
|
+
await this._ready.wait({
|
|
625
|
+
timeout: this._config.timeout ?? DEFAULT_TIMEOUT
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
if (!this._currentConnection) {
|
|
629
|
+
throw new EdgeConnectionClosedError();
|
|
630
|
+
}
|
|
631
|
+
if (message.source && (message.source.peerKey !== this._identity.peerKey || message.source.identityKey !== this.identityKey)) {
|
|
632
|
+
throw new EdgeIdentityChangedError();
|
|
633
|
+
}
|
|
634
|
+
this._currentConnection.send(message);
|
|
635
|
+
}
|
|
407
636
|
onMessage(listener) {
|
|
408
637
|
this._messageListeners.add(listener);
|
|
409
638
|
return () => this._messageListeners.delete(listener);
|
|
@@ -417,8 +646,8 @@ var EdgeClient = class extends Resource2 {
|
|
|
417
646
|
listener();
|
|
418
647
|
} catch (error) {
|
|
419
648
|
log2.catch(error, void 0, {
|
|
420
|
-
F:
|
|
421
|
-
L:
|
|
649
|
+
F: __dxlog_file4,
|
|
650
|
+
L: 164,
|
|
422
651
|
S: this,
|
|
423
652
|
C: (f, a) => f(...a)
|
|
424
653
|
});
|
|
@@ -435,8 +664,8 @@ var EdgeClient = class extends Resource2 {
|
|
|
435
664
|
log2("opening...", {
|
|
436
665
|
info: this.info
|
|
437
666
|
}, {
|
|
438
|
-
F:
|
|
439
|
-
L:
|
|
667
|
+
F: __dxlog_file4,
|
|
668
|
+
L: 177,
|
|
440
669
|
S: this,
|
|
441
670
|
C: (f, a) => f(...a)
|
|
442
671
|
});
|
|
@@ -444,12 +673,18 @@ var EdgeClient = class extends Resource2 {
|
|
|
444
673
|
log2.warn("Error while opening connection", {
|
|
445
674
|
err
|
|
446
675
|
}, {
|
|
447
|
-
F:
|
|
448
|
-
L:
|
|
676
|
+
F: __dxlog_file4,
|
|
677
|
+
L: 179,
|
|
449
678
|
S: this,
|
|
450
679
|
C: (f, a) => f(...a)
|
|
451
680
|
});
|
|
452
681
|
});
|
|
682
|
+
scheduleTaskInterval2(this._ctx, async () => {
|
|
683
|
+
if (!this._currentConnection) {
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
this.statusChanged.emit(this.status);
|
|
687
|
+
}, STATUS_REFRESH_INTERVAL);
|
|
453
688
|
}
|
|
454
689
|
/**
|
|
455
690
|
* Close connection and free resources.
|
|
@@ -458,8 +693,8 @@ var EdgeClient = class extends Resource2 {
|
|
|
458
693
|
log2("closing...", {
|
|
459
694
|
peerKey: this._identity.peerKey
|
|
460
695
|
}, {
|
|
461
|
-
F:
|
|
462
|
-
L:
|
|
696
|
+
F: __dxlog_file4,
|
|
697
|
+
L: 199,
|
|
463
698
|
S: this,
|
|
464
699
|
C: (f, a) => f(...a)
|
|
465
700
|
});
|
|
@@ -475,8 +710,8 @@ var EdgeClient = class extends Resource2 {
|
|
|
475
710
|
const protocolHeader = this._config.disableAuth ? void 0 : await this._createAuthHeader(path);
|
|
476
711
|
if (this._identity !== identity) {
|
|
477
712
|
log2("identity changed during auth header request", void 0, {
|
|
478
|
-
F:
|
|
479
|
-
L:
|
|
713
|
+
F: __dxlog_file4,
|
|
714
|
+
L: 213,
|
|
480
715
|
S: this,
|
|
481
716
|
C: (f, a) => f(...a)
|
|
482
717
|
});
|
|
@@ -488,8 +723,8 @@ var EdgeClient = class extends Resource2 {
|
|
|
488
723
|
url: url.toString(),
|
|
489
724
|
protocolHeader
|
|
490
725
|
}, {
|
|
491
|
-
F:
|
|
492
|
-
L:
|
|
726
|
+
F: __dxlog_file4,
|
|
727
|
+
L: 219,
|
|
493
728
|
S: this,
|
|
494
729
|
C: (f, a) => f(...a)
|
|
495
730
|
});
|
|
@@ -503,8 +738,8 @@ var EdgeClient = class extends Resource2 {
|
|
|
503
738
|
this._notifyReconnected();
|
|
504
739
|
} else {
|
|
505
740
|
log2.verbose("connected callback ignored, because connection is not active", void 0, {
|
|
506
|
-
F:
|
|
507
|
-
L:
|
|
741
|
+
F: __dxlog_file4,
|
|
742
|
+
L: 229,
|
|
508
743
|
S: this,
|
|
509
744
|
C: (f, a) => f(...a)
|
|
510
745
|
});
|
|
@@ -516,8 +751,8 @@ var EdgeClient = class extends Resource2 {
|
|
|
516
751
|
void this._persistentLifecycle.scheduleRestart();
|
|
517
752
|
} else {
|
|
518
753
|
log2.verbose("restart requested by inactive connection", void 0, {
|
|
519
|
-
F:
|
|
520
|
-
L:
|
|
754
|
+
F: __dxlog_file4,
|
|
755
|
+
L: 237,
|
|
521
756
|
S: this,
|
|
522
757
|
C: (f, a) => f(...a)
|
|
523
758
|
});
|
|
@@ -532,8 +767,8 @@ var EdgeClient = class extends Resource2 {
|
|
|
532
767
|
from: message.source,
|
|
533
768
|
type: message.payload?.typeUrl
|
|
534
769
|
}, {
|
|
535
|
-
F:
|
|
536
|
-
L:
|
|
770
|
+
F: __dxlog_file4,
|
|
771
|
+
L: 245,
|
|
537
772
|
S: this,
|
|
538
773
|
C: (f, a) => f(...a)
|
|
539
774
|
});
|
|
@@ -569,8 +804,8 @@ var EdgeClient = class extends Resource2 {
|
|
|
569
804
|
log2.error("ws reconnect listener failed", {
|
|
570
805
|
err
|
|
571
806
|
}, {
|
|
572
|
-
F:
|
|
573
|
-
L:
|
|
807
|
+
F: __dxlog_file4,
|
|
808
|
+
L: 280,
|
|
574
809
|
S: this,
|
|
575
810
|
C: (f, a) => f(...a)
|
|
576
811
|
});
|
|
@@ -586,38 +821,14 @@ var EdgeClient = class extends Resource2 {
|
|
|
586
821
|
err,
|
|
587
822
|
payload: protocol.getPayloadType(message)
|
|
588
823
|
}, {
|
|
589
|
-
F:
|
|
590
|
-
L:
|
|
824
|
+
F: __dxlog_file4,
|
|
825
|
+
L: 290,
|
|
591
826
|
S: this,
|
|
592
827
|
C: (f, a) => f(...a)
|
|
593
828
|
});
|
|
594
829
|
}
|
|
595
830
|
}
|
|
596
831
|
}
|
|
597
|
-
/**
|
|
598
|
-
* Send message.
|
|
599
|
-
* NOTE: The message is guaranteed to be delivered but the service must respond with a message to confirm processing.
|
|
600
|
-
*/
|
|
601
|
-
async send(message) {
|
|
602
|
-
if (this._ready.state !== TriggerState.RESOLVED) {
|
|
603
|
-
log2("waiting for websocket to become ready", void 0, {
|
|
604
|
-
F: __dxlog_file3,
|
|
605
|
-
L: 246,
|
|
606
|
-
S: this,
|
|
607
|
-
C: (f, a) => f(...a)
|
|
608
|
-
});
|
|
609
|
-
await this._ready.wait({
|
|
610
|
-
timeout: this._config.timeout ?? DEFAULT_TIMEOUT
|
|
611
|
-
});
|
|
612
|
-
}
|
|
613
|
-
if (!this._currentConnection) {
|
|
614
|
-
throw new EdgeConnectionClosedError();
|
|
615
|
-
}
|
|
616
|
-
if (message.source && (message.source.peerKey !== this._identity.peerKey || message.source.identityKey !== this.identityKey)) {
|
|
617
|
-
throw new EdgeIdentityChangedError();
|
|
618
|
-
}
|
|
619
|
-
this._currentConnection.send(message);
|
|
620
|
-
}
|
|
621
832
|
async _createAuthHeader(path) {
|
|
622
833
|
const httpUrl = new URL(path, this._baseHttpUrl);
|
|
623
834
|
httpUrl.protocol = getEdgeUrlWithProtocol(this._baseWsUrl.toString(), "http");
|
|
@@ -631,15 +842,15 @@ var EdgeClient = class extends Resource2 {
|
|
|
631
842
|
status: response.status,
|
|
632
843
|
statusText: response.statusText
|
|
633
844
|
}, {
|
|
634
|
-
F:
|
|
635
|
-
L:
|
|
845
|
+
F: __dxlog_file4,
|
|
846
|
+
L: 302,
|
|
636
847
|
S: this,
|
|
637
848
|
C: (f, a) => f(...a)
|
|
638
849
|
});
|
|
639
850
|
return void 0;
|
|
640
851
|
}
|
|
641
852
|
}
|
|
642
|
-
_isActive;
|
|
853
|
+
_isActive = (connection) => connection === this._currentConnection;
|
|
643
854
|
};
|
|
644
855
|
_ts_decorate2([
|
|
645
856
|
logInfo2
|
|
@@ -649,128 +860,24 @@ var encodePresentationWsAuthHeader = (encodedPresentation) => {
|
|
|
649
860
|
return `base64url.bearer.authorization.dxos.org.${encodedToken}`;
|
|
650
861
|
};
|
|
651
862
|
|
|
652
|
-
// src/auth.ts
|
|
653
|
-
import { createCredential, signPresentation } from "@dxos/credentials";
|
|
654
|
-
import { invariant as invariant3 } from "@dxos/invariant";
|
|
655
|
-
import { Keyring } from "@dxos/keyring";
|
|
656
|
-
import { PublicKey } from "@dxos/keys";
|
|
657
|
-
var __dxlog_file4 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/auth.ts";
|
|
658
|
-
var createDeviceEdgeIdentity = async (signer, key) => {
|
|
659
|
-
return {
|
|
660
|
-
identityKey: key.toHex(),
|
|
661
|
-
peerKey: key.toHex(),
|
|
662
|
-
presentCredentials: async ({ challenge }) => {
|
|
663
|
-
return signPresentation({
|
|
664
|
-
presentation: {
|
|
665
|
-
credentials: [
|
|
666
|
-
// Verifier requires at least one credential in the presentation to establish the subject.
|
|
667
|
-
await createCredential({
|
|
668
|
-
assertion: {
|
|
669
|
-
"@type": "dxos.halo.credentials.Auth"
|
|
670
|
-
},
|
|
671
|
-
issuer: key,
|
|
672
|
-
subject: key,
|
|
673
|
-
signer
|
|
674
|
-
})
|
|
675
|
-
]
|
|
676
|
-
},
|
|
677
|
-
signer,
|
|
678
|
-
signerKey: key,
|
|
679
|
-
nonce: challenge
|
|
680
|
-
});
|
|
681
|
-
}
|
|
682
|
-
};
|
|
683
|
-
};
|
|
684
|
-
var createChainEdgeIdentity = async (signer, identityKey, peerKey, chain, credentials) => {
|
|
685
|
-
const credentialsToSign = credentials.length > 0 ? credentials : [
|
|
686
|
-
await createCredential({
|
|
687
|
-
assertion: {
|
|
688
|
-
"@type": "dxos.halo.credentials.Auth"
|
|
689
|
-
},
|
|
690
|
-
issuer: identityKey,
|
|
691
|
-
subject: identityKey,
|
|
692
|
-
signer,
|
|
693
|
-
chain,
|
|
694
|
-
signingKey: peerKey
|
|
695
|
-
})
|
|
696
|
-
];
|
|
697
|
-
return {
|
|
698
|
-
identityKey: identityKey.toHex(),
|
|
699
|
-
peerKey: peerKey.toHex(),
|
|
700
|
-
presentCredentials: async ({ challenge }) => {
|
|
701
|
-
invariant3(chain, void 0, {
|
|
702
|
-
F: __dxlog_file4,
|
|
703
|
-
L: 75,
|
|
704
|
-
S: void 0,
|
|
705
|
-
A: [
|
|
706
|
-
"chain",
|
|
707
|
-
""
|
|
708
|
-
]
|
|
709
|
-
});
|
|
710
|
-
return signPresentation({
|
|
711
|
-
presentation: {
|
|
712
|
-
credentials: credentialsToSign
|
|
713
|
-
},
|
|
714
|
-
signer,
|
|
715
|
-
nonce: challenge,
|
|
716
|
-
signerKey: peerKey,
|
|
717
|
-
chain
|
|
718
|
-
});
|
|
719
|
-
}
|
|
720
|
-
};
|
|
721
|
-
};
|
|
722
|
-
var createEphemeralEdgeIdentity = async () => {
|
|
723
|
-
const keyring = new Keyring();
|
|
724
|
-
const key = await keyring.createKey();
|
|
725
|
-
return createDeviceEdgeIdentity(keyring, key);
|
|
726
|
-
};
|
|
727
|
-
var createTestHaloEdgeIdentity = async (signer, identityKey, deviceKey) => {
|
|
728
|
-
const deviceAdmission = await createCredential({
|
|
729
|
-
assertion: {
|
|
730
|
-
"@type": "dxos.halo.credentials.AuthorizedDevice",
|
|
731
|
-
deviceKey,
|
|
732
|
-
identityKey
|
|
733
|
-
},
|
|
734
|
-
issuer: identityKey,
|
|
735
|
-
subject: deviceKey,
|
|
736
|
-
signer
|
|
737
|
-
});
|
|
738
|
-
return createChainEdgeIdentity(signer, identityKey, deviceKey, {
|
|
739
|
-
credential: deviceAdmission
|
|
740
|
-
}, [
|
|
741
|
-
await createCredential({
|
|
742
|
-
assertion: {
|
|
743
|
-
"@type": "dxos.halo.credentials.Auth"
|
|
744
|
-
},
|
|
745
|
-
issuer: identityKey,
|
|
746
|
-
subject: identityKey,
|
|
747
|
-
signer
|
|
748
|
-
})
|
|
749
|
-
]);
|
|
750
|
-
};
|
|
751
|
-
var createStubEdgeIdentity = () => {
|
|
752
|
-
const identityKey = PublicKey.random();
|
|
753
|
-
const deviceKey = PublicKey.random();
|
|
754
|
-
return {
|
|
755
|
-
identityKey: identityKey.toHex(),
|
|
756
|
-
peerKey: deviceKey.toHex(),
|
|
757
|
-
presentCredentials: async () => {
|
|
758
|
-
throw new Error("Stub identity does not support authentication.");
|
|
759
|
-
}
|
|
760
|
-
};
|
|
761
|
-
};
|
|
762
|
-
|
|
763
863
|
// src/edge-http-client.ts
|
|
764
|
-
import
|
|
765
|
-
import
|
|
864
|
+
import * as FetchHttpClient from "@effect/platform/FetchHttpClient";
|
|
865
|
+
import * as HttpClient from "@effect/platform/HttpClient";
|
|
866
|
+
import * as Effect2 from "effect/Effect";
|
|
867
|
+
import * as Function from "effect/Function";
|
|
766
868
|
import { sleep } from "@dxos/async";
|
|
767
869
|
import { Context as Context3 } from "@dxos/context";
|
|
870
|
+
import { invariant as invariant4 } from "@dxos/invariant";
|
|
768
871
|
import { log as log4 } from "@dxos/log";
|
|
769
872
|
import { EdgeAuthChallengeError, EdgeCallFailedError } from "@dxos/protocols";
|
|
770
873
|
import { createUrl } from "@dxos/util";
|
|
771
874
|
|
|
772
875
|
// src/http-client.ts
|
|
773
|
-
import
|
|
876
|
+
import * as Context2 from "effect/Context";
|
|
877
|
+
import * as Duration from "effect/Duration";
|
|
878
|
+
import * as Effect from "effect/Effect";
|
|
879
|
+
import * as Layer from "effect/Layer";
|
|
880
|
+
import * as Schedule from "effect/Schedule";
|
|
774
881
|
import { log as log3 } from "@dxos/log";
|
|
775
882
|
var __dxlog_file5 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/http-client.ts";
|
|
776
883
|
var HttpConfig = class _HttpConfig extends Context2.Tag("HttpConfig")() {
|
|
@@ -780,11 +887,11 @@ var HttpConfig = class _HttpConfig extends Context2.Tag("HttpConfig")() {
|
|
|
780
887
|
retryBaseDelay: Duration.millis(1e3)
|
|
781
888
|
});
|
|
782
889
|
};
|
|
783
|
-
var withRetry = (effect, { timeout = Duration.millis(1e3), retryBaseDelay = Duration.millis(1e3), retryTimes = 3 } = {}) => {
|
|
890
|
+
var withRetry = (effect, { timeout: timeout2 = Duration.millis(1e3), retryBaseDelay = Duration.millis(1e3), retryTimes = 3 } = {}) => {
|
|
784
891
|
return effect.pipe(Effect.flatMap((res) => (
|
|
785
892
|
// Treat 500 errors as retryable?
|
|
786
893
|
res.status === 500 ? Effect.fail(new Error(res.status.toString())) : res.json
|
|
787
|
-
)), Effect.timeout(
|
|
894
|
+
)), Effect.timeout(timeout2), Effect.retry({
|
|
788
895
|
schedule: Schedule.exponential(retryBaseDelay).pipe(Schedule.jittered),
|
|
789
896
|
times: retryTimes
|
|
790
897
|
}));
|
|
@@ -793,14 +900,16 @@ var withRetryConfig = (effect) => Effect.gen(function* () {
|
|
|
793
900
|
const config = yield* HttpConfig;
|
|
794
901
|
return yield* withRetry(effect, config);
|
|
795
902
|
});
|
|
796
|
-
var withLogging = (effect) => effect.pipe(Effect.tap((res) =>
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
903
|
+
var withLogging = (effect) => effect.pipe(Effect.tap((res) => {
|
|
904
|
+
log3.info("response", {
|
|
905
|
+
status: res.status
|
|
906
|
+
}, {
|
|
907
|
+
F: __dxlog_file5,
|
|
908
|
+
L: 66,
|
|
909
|
+
S: void 0,
|
|
910
|
+
C: (f, a) => f(...a)
|
|
911
|
+
});
|
|
912
|
+
}));
|
|
804
913
|
var encodeAuthHeader = (challenge) => {
|
|
805
914
|
const encodedChallenge = Buffer.from(challenge).toString("base64");
|
|
806
915
|
return `VerifiablePresentation pb;base64,${encodedChallenge}`;
|
|
@@ -811,6 +920,7 @@ var __dxlog_file6 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/edge-http
|
|
|
811
920
|
var DEFAULT_RETRY_TIMEOUT = 1500;
|
|
812
921
|
var DEFAULT_RETRY_JITTER = 500;
|
|
813
922
|
var DEFAULT_MAX_RETRIES_COUNT = 3;
|
|
923
|
+
var WARNING_BODY_SIZE = 10 * 1024 * 1024;
|
|
814
924
|
var EdgeHttpClient = class {
|
|
815
925
|
_baseUrl;
|
|
816
926
|
_edgeIdentity;
|
|
@@ -824,7 +934,7 @@ var EdgeHttpClient = class {
|
|
|
824
934
|
url: this._baseUrl
|
|
825
935
|
}, {
|
|
826
936
|
F: __dxlog_file6,
|
|
827
|
-
L:
|
|
937
|
+
L: 107,
|
|
828
938
|
S: this,
|
|
829
939
|
C: (f, a) => f(...a)
|
|
830
940
|
});
|
|
@@ -902,12 +1012,6 @@ var EdgeHttpClient = class {
|
|
|
902
1012
|
//
|
|
903
1013
|
// OAuth and credentials
|
|
904
1014
|
//
|
|
905
|
-
async listFunctions(args) {
|
|
906
|
-
return this._call(new URL("/functions", this.baseUrl), {
|
|
907
|
-
...args,
|
|
908
|
-
method: "GET"
|
|
909
|
-
});
|
|
910
|
-
}
|
|
911
1015
|
async initiateOAuthFlow(body, args) {
|
|
912
1016
|
return this._call(new URL("/oauth/initiate", this.baseUrl), {
|
|
913
1017
|
...args,
|
|
@@ -962,6 +1066,19 @@ var EdgeHttpClient = class {
|
|
|
962
1066
|
// Functions
|
|
963
1067
|
//
|
|
964
1068
|
async uploadFunction(pathParts, body, args) {
|
|
1069
|
+
const formData = new FormData();
|
|
1070
|
+
formData.append("name", body.name ?? "");
|
|
1071
|
+
formData.append("version", body.version);
|
|
1072
|
+
formData.append("ownerPublicKey", body.ownerPublicKey);
|
|
1073
|
+
formData.append("entryPoint", body.entryPoint);
|
|
1074
|
+
body.runtime && formData.append("runtime", body.runtime);
|
|
1075
|
+
for (const [filename, content] of Object.entries(body.assets)) {
|
|
1076
|
+
formData.append("assets", new Blob([
|
|
1077
|
+
content
|
|
1078
|
+
], {
|
|
1079
|
+
type: getFileMimeType(filename)
|
|
1080
|
+
}), filename);
|
|
1081
|
+
}
|
|
965
1082
|
const path = [
|
|
966
1083
|
"functions",
|
|
967
1084
|
...pathParts.functionId ? [
|
|
@@ -970,8 +1087,36 @@ var EdgeHttpClient = class {
|
|
|
970
1087
|
].join("/");
|
|
971
1088
|
return this._call(new URL(path, this.baseUrl), {
|
|
972
1089
|
...args,
|
|
973
|
-
body,
|
|
974
|
-
method: "PUT"
|
|
1090
|
+
body: formData,
|
|
1091
|
+
method: "PUT",
|
|
1092
|
+
json: false
|
|
1093
|
+
});
|
|
1094
|
+
}
|
|
1095
|
+
async listFunctions(args) {
|
|
1096
|
+
return this._call(new URL("/functions", this.baseUrl), {
|
|
1097
|
+
...args,
|
|
1098
|
+
method: "GET"
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
1101
|
+
async invokeFunction(params, input, args) {
|
|
1102
|
+
const url = new URL(`/functions/${params.functionId}`, this.baseUrl);
|
|
1103
|
+
if (params.version) {
|
|
1104
|
+
url.searchParams.set("version", params.version);
|
|
1105
|
+
}
|
|
1106
|
+
if (params.spaceId) {
|
|
1107
|
+
url.searchParams.set("spaceId", params.spaceId.toString());
|
|
1108
|
+
}
|
|
1109
|
+
if (params.cpuTimeLimit) {
|
|
1110
|
+
url.searchParams.set("cpuTimeLimit", params.cpuTimeLimit.toString());
|
|
1111
|
+
}
|
|
1112
|
+
if (params.subrequestsLimit) {
|
|
1113
|
+
url.searchParams.set("subrequestsLimit", params.subrequestsLimit.toString());
|
|
1114
|
+
}
|
|
1115
|
+
return this._call(url, {
|
|
1116
|
+
...args,
|
|
1117
|
+
body: input,
|
|
1118
|
+
method: "POST",
|
|
1119
|
+
rawResponse: true
|
|
975
1120
|
});
|
|
976
1121
|
}
|
|
977
1122
|
//
|
|
@@ -985,71 +1130,136 @@ var EdgeHttpClient = class {
|
|
|
985
1130
|
});
|
|
986
1131
|
}
|
|
987
1132
|
//
|
|
1133
|
+
// Triggers
|
|
1134
|
+
//
|
|
1135
|
+
async getCronTriggers(spaceId) {
|
|
1136
|
+
return this._call(new URL(`/test/functions/${spaceId}/triggers/crons`, this.baseUrl), {
|
|
1137
|
+
method: "GET"
|
|
1138
|
+
});
|
|
1139
|
+
}
|
|
1140
|
+
//
|
|
1141
|
+
// Import/Export space.
|
|
1142
|
+
//
|
|
1143
|
+
async importBundle(spaceId, body, args) {
|
|
1144
|
+
return this._call(new URL(`/spaces/${spaceId}/import`, this.baseUrl), {
|
|
1145
|
+
...args,
|
|
1146
|
+
body,
|
|
1147
|
+
method: "PUT"
|
|
1148
|
+
});
|
|
1149
|
+
}
|
|
1150
|
+
async exportBundle(spaceId, body, args) {
|
|
1151
|
+
return this._call(new URL(`/spaces/${spaceId}/export`, this.baseUrl), {
|
|
1152
|
+
...args,
|
|
1153
|
+
body,
|
|
1154
|
+
method: "POST"
|
|
1155
|
+
});
|
|
1156
|
+
}
|
|
1157
|
+
//
|
|
988
1158
|
// Internal
|
|
989
1159
|
//
|
|
990
|
-
async _fetch(url,
|
|
991
|
-
return pipe(HttpClient.get(url), withLogging, withRetryConfig, Effect2.provide(FetchHttpClient.layer), Effect2.provide(HttpConfig.default), Effect2.withSpan("EdgeHttpClient"), Effect2.runPromise);
|
|
1160
|
+
async _fetch(url, _args) {
|
|
1161
|
+
return Function.pipe(HttpClient.get(url), withLogging, withRetryConfig, Effect2.provide(FetchHttpClient.layer), Effect2.provide(HttpConfig.default), Effect2.withSpan("EdgeHttpClient"), Effect2.runPromise);
|
|
992
1162
|
}
|
|
993
1163
|
// TODO(burdon): Refactor with effect (see edge-http-client.test.ts).
|
|
994
1164
|
async _call(url, args) {
|
|
995
1165
|
const shouldRetry = createRetryHandler(args);
|
|
996
|
-
const requestContext = args.context ??
|
|
1166
|
+
const requestContext = args.context ?? Context3.default(void 0, {
|
|
997
1167
|
F: __dxlog_file6,
|
|
998
|
-
L:
|
|
1168
|
+
L: 400
|
|
999
1169
|
});
|
|
1000
1170
|
log4("fetch", {
|
|
1001
1171
|
url,
|
|
1002
1172
|
request: args.body
|
|
1003
1173
|
}, {
|
|
1004
1174
|
F: __dxlog_file6,
|
|
1005
|
-
L:
|
|
1175
|
+
L: 401,
|
|
1006
1176
|
S: this,
|
|
1007
1177
|
C: (f, a) => f(...a)
|
|
1008
1178
|
});
|
|
1009
1179
|
let handledAuth = false;
|
|
1180
|
+
const tryCount = 1;
|
|
1010
1181
|
while (true) {
|
|
1011
|
-
let processingError;
|
|
1012
|
-
let retryAfterHeaderValue = Number.NaN;
|
|
1182
|
+
let processingError = void 0;
|
|
1013
1183
|
try {
|
|
1184
|
+
if (!this._authHeader && args.auth) {
|
|
1185
|
+
const response2 = await fetch(new URL(`/auth`, this.baseUrl));
|
|
1186
|
+
if (response2.status === 401) {
|
|
1187
|
+
this._authHeader = await this._handleUnauthorized(response2);
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1014
1190
|
const request = createRequest(args, this._authHeader);
|
|
1191
|
+
log4("call edge", {
|
|
1192
|
+
url,
|
|
1193
|
+
tryCount,
|
|
1194
|
+
authHeader: !!this._authHeader
|
|
1195
|
+
}, {
|
|
1196
|
+
F: __dxlog_file6,
|
|
1197
|
+
L: 416,
|
|
1198
|
+
S: this,
|
|
1199
|
+
C: (f, a) => f(...a)
|
|
1200
|
+
});
|
|
1015
1201
|
const response = await fetch(url, request);
|
|
1016
|
-
retryAfterHeaderValue = Number(response.headers.get("Retry-After"));
|
|
1017
1202
|
if (response.ok) {
|
|
1018
|
-
const
|
|
1019
|
-
if (
|
|
1020
|
-
return
|
|
1203
|
+
const body2 = await response.clone().json();
|
|
1204
|
+
if (args.rawResponse) {
|
|
1205
|
+
return body2;
|
|
1021
1206
|
}
|
|
1022
|
-
|
|
1023
|
-
url,
|
|
1024
|
-
body
|
|
1025
|
-
}, {
|
|
1207
|
+
invariant4(body2, "Expected body to be present", {
|
|
1026
1208
|
F: __dxlog_file6,
|
|
1027
|
-
L:
|
|
1209
|
+
L: 424,
|
|
1028
1210
|
S: this,
|
|
1029
|
-
|
|
1211
|
+
A: [
|
|
1212
|
+
"body",
|
|
1213
|
+
"'Expected body to be present'"
|
|
1214
|
+
]
|
|
1030
1215
|
});
|
|
1031
|
-
if (
|
|
1032
|
-
|
|
1033
|
-
}
|
|
1034
|
-
|
|
1216
|
+
if (!("success" in body2)) {
|
|
1217
|
+
return body2;
|
|
1218
|
+
}
|
|
1219
|
+
if (body2.success) {
|
|
1220
|
+
return body2.data;
|
|
1035
1221
|
}
|
|
1036
1222
|
} else if (response.status === 401 && !handledAuth) {
|
|
1037
1223
|
this._authHeader = await this._handleUnauthorized(response);
|
|
1038
1224
|
handledAuth = true;
|
|
1039
1225
|
continue;
|
|
1226
|
+
}
|
|
1227
|
+
const body = response.headers.get("Content-Type") === "application/json" ? await response.clone().json() : void 0;
|
|
1228
|
+
invariant4(!body?.success, "Expected body to not be a failure response or undefined.", {
|
|
1229
|
+
F: __dxlog_file6,
|
|
1230
|
+
L: 440,
|
|
1231
|
+
S: this,
|
|
1232
|
+
A: [
|
|
1233
|
+
"!body?.success",
|
|
1234
|
+
"'Expected body to not be a failure response or undefined.'"
|
|
1235
|
+
]
|
|
1236
|
+
});
|
|
1237
|
+
if (body?.errorData?.type === "auth_challenge" && typeof body?.errorData?.challenge === "string") {
|
|
1238
|
+
processingError = new EdgeAuthChallengeError(body.errorData.challenge, body.errorData);
|
|
1239
|
+
} else if (body?.success === false) {
|
|
1240
|
+
processingError = EdgeCallFailedError.fromUnsuccessfulResponse(response, body);
|
|
1040
1241
|
} else {
|
|
1041
|
-
|
|
1242
|
+
invariant4(!response.ok, "Expected response to not be ok.", {
|
|
1243
|
+
F: __dxlog_file6,
|
|
1244
|
+
L: 447,
|
|
1245
|
+
S: this,
|
|
1246
|
+
A: [
|
|
1247
|
+
"!response.ok",
|
|
1248
|
+
"'Expected response to not be ok.'"
|
|
1249
|
+
]
|
|
1250
|
+
});
|
|
1251
|
+
processingError = await EdgeCallFailedError.fromHttpFailure(response);
|
|
1042
1252
|
}
|
|
1043
1253
|
} catch (error) {
|
|
1044
1254
|
processingError = EdgeCallFailedError.fromProcessingFailureCause(error);
|
|
1045
1255
|
}
|
|
1046
|
-
if (processingError
|
|
1047
|
-
log4("retrying edge request", {
|
|
1256
|
+
if (processingError?.isRetryable && await shouldRetry(requestContext, processingError.retryAfterMs)) {
|
|
1257
|
+
log4.verbose("retrying edge request", {
|
|
1048
1258
|
url,
|
|
1049
1259
|
processingError
|
|
1050
1260
|
}, {
|
|
1051
1261
|
F: __dxlog_file6,
|
|
1052
|
-
L:
|
|
1262
|
+
L: 455,
|
|
1053
1263
|
S: this,
|
|
1054
1264
|
C: (f, a) => f(...a)
|
|
1055
1265
|
});
|
|
@@ -1062,33 +1272,52 @@ var EdgeHttpClient = class {
|
|
|
1062
1272
|
if (!this._edgeIdentity) {
|
|
1063
1273
|
log4.warn("unauthorized response received before identity was set", void 0, {
|
|
1064
1274
|
F: __dxlog_file6,
|
|
1065
|
-
L:
|
|
1275
|
+
L: 464,
|
|
1066
1276
|
S: this,
|
|
1067
1277
|
C: (f, a) => f(...a)
|
|
1068
1278
|
});
|
|
1069
|
-
throw EdgeCallFailedError.fromHttpFailure(response);
|
|
1279
|
+
throw await EdgeCallFailedError.fromHttpFailure(response);
|
|
1070
1280
|
}
|
|
1071
1281
|
const challenge = await handleAuthChallenge(response, this._edgeIdentity);
|
|
1072
1282
|
return encodeAuthHeader(challenge);
|
|
1073
1283
|
}
|
|
1074
1284
|
};
|
|
1075
|
-
var createRequest = ({ method, body }, authHeader) => {
|
|
1285
|
+
var createRequest = ({ method, body, json = true }, authHeader) => {
|
|
1286
|
+
let requestBody;
|
|
1287
|
+
const headers = {};
|
|
1288
|
+
if (json) {
|
|
1289
|
+
requestBody = body && JSON.stringify(body);
|
|
1290
|
+
headers["Content-Type"] = "application/json";
|
|
1291
|
+
} else {
|
|
1292
|
+
requestBody = body;
|
|
1293
|
+
}
|
|
1294
|
+
if (typeof requestBody === "string" && requestBody.length > WARNING_BODY_SIZE) {
|
|
1295
|
+
log4.warn("Request with large body", {
|
|
1296
|
+
bodySize: requestBody.length
|
|
1297
|
+
}, {
|
|
1298
|
+
F: __dxlog_file6,
|
|
1299
|
+
L: 488,
|
|
1300
|
+
S: void 0,
|
|
1301
|
+
C: (f, a) => f(...a)
|
|
1302
|
+
});
|
|
1303
|
+
}
|
|
1304
|
+
if (authHeader) {
|
|
1305
|
+
headers["Authorization"] = authHeader;
|
|
1306
|
+
}
|
|
1076
1307
|
return {
|
|
1077
1308
|
method,
|
|
1078
|
-
body:
|
|
1079
|
-
headers
|
|
1080
|
-
Authorization: authHeader
|
|
1081
|
-
} : void 0
|
|
1309
|
+
body: requestBody,
|
|
1310
|
+
headers
|
|
1082
1311
|
};
|
|
1083
1312
|
};
|
|
1084
|
-
var createRetryHandler = ({ retry }) => {
|
|
1085
|
-
if (!
|
|
1313
|
+
var createRetryHandler = ({ retry: retry2 }) => {
|
|
1314
|
+
if (!retry2 || retry2.count < 1) {
|
|
1086
1315
|
return async () => false;
|
|
1087
1316
|
}
|
|
1088
1317
|
let retries = 0;
|
|
1089
|
-
const maxRetries =
|
|
1090
|
-
const baseTimeout =
|
|
1091
|
-
const jitter =
|
|
1318
|
+
const maxRetries = retry2.count ?? DEFAULT_MAX_RETRIES_COUNT;
|
|
1319
|
+
const baseTimeout = retry2.timeout ?? DEFAULT_RETRY_TIMEOUT;
|
|
1320
|
+
const jitter = retry2.jitter ?? DEFAULT_RETRY_JITTER;
|
|
1092
1321
|
return async (ctx, retryAfter) => {
|
|
1093
1322
|
if (++retries > maxRetries || ctx.disposed) {
|
|
1094
1323
|
return false;
|
|
@@ -1096,12 +1325,16 @@ var createRetryHandler = ({ retry }) => {
|
|
|
1096
1325
|
if (retryAfter) {
|
|
1097
1326
|
await sleep(retryAfter);
|
|
1098
1327
|
} else {
|
|
1099
|
-
const
|
|
1100
|
-
await sleep(
|
|
1328
|
+
const timeout2 = baseTimeout + Math.random() * jitter;
|
|
1329
|
+
await sleep(timeout2);
|
|
1101
1330
|
}
|
|
1102
1331
|
return true;
|
|
1103
1332
|
};
|
|
1104
1333
|
};
|
|
1334
|
+
var getFileMimeType = (filename) => [
|
|
1335
|
+
".js",
|
|
1336
|
+
".mjs"
|
|
1337
|
+
].some((codeExtension) => filename.endsWith(codeExtension)) ? "application/javascript+module" : filename.endsWith(".wasm") ? "application/wasm" : "application/octet-stream";
|
|
1105
1338
|
export {
|
|
1106
1339
|
CLOUDFLARE_MESSAGE_MAX_BYTES,
|
|
1107
1340
|
CLOUDFLARE_RPC_MAX_BYTES,
|
|
@@ -1109,6 +1342,7 @@ export {
|
|
|
1109
1342
|
EdgeConnectionClosedError,
|
|
1110
1343
|
EdgeHttpClient,
|
|
1111
1344
|
EdgeIdentityChangedError,
|
|
1345
|
+
HttpConfig,
|
|
1112
1346
|
Protocol,
|
|
1113
1347
|
WebSocketMuxer,
|
|
1114
1348
|
createChainEdgeIdentity,
|
|
@@ -1116,9 +1350,13 @@ export {
|
|
|
1116
1350
|
createEphemeralEdgeIdentity,
|
|
1117
1351
|
createStubEdgeIdentity,
|
|
1118
1352
|
createTestHaloEdgeIdentity,
|
|
1353
|
+
encodeAuthHeader,
|
|
1119
1354
|
getTypename,
|
|
1120
1355
|
handleAuthChallenge,
|
|
1121
1356
|
protocol,
|
|
1122
|
-
toUint8Array
|
|
1357
|
+
toUint8Array,
|
|
1358
|
+
withLogging,
|
|
1359
|
+
withRetry,
|
|
1360
|
+
withRetryConfig
|
|
1123
1361
|
};
|
|
1124
1362
|
//# sourceMappingURL=index.mjs.map
|