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