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