@dxos/edge-client 0.8.4-main.b97322e → 0.8.4-main.bc2380dfbc
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/LICENSE +102 -5
- package/dist/lib/{browser/chunk-LMP5TVOP.mjs → neutral/chunk-ZIQ5T3A7.mjs} +13 -43
- package/dist/lib/{browser/chunk-LMP5TVOP.mjs.map → neutral/chunk-ZIQ5T3A7.mjs.map} +3 -3
- package/dist/lib/{browser → neutral}/edge-ws-muxer.mjs +1 -1
- package/dist/lib/{browser → neutral}/index.mjs +576 -489
- package/dist/lib/neutral/index.mjs.map +7 -0
- package/dist/lib/neutral/meta.json +1 -0
- package/dist/lib/{browser → neutral}/testing/index.mjs +6 -31
- package/dist/lib/neutral/testing/index.mjs.map +7 -0
- package/dist/types/src/auth.d.ts.map +1 -1
- package/dist/types/src/edge-client.d.ts +18 -15
- package/dist/types/src/edge-client.d.ts.map +1 -1
- package/dist/types/src/edge-http-client.d.ts +80 -22
- package/dist/types/src/edge-http-client.d.ts.map +1 -1
- package/dist/types/src/edge-identity.d.ts.map +1 -1
- package/dist/types/src/edge-ws-connection.d.ts +20 -0
- package/dist/types/src/edge-ws-connection.d.ts.map +1 -1
- package/dist/types/src/edge-ws-muxer.d.ts.map +1 -1
- package/dist/types/src/errors.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/protocol.d.ts +1 -1
- package/dist/types/src/protocol.d.ts.map +1 -1
- package/dist/types/src/testing/test-server.d.ts.map +1 -1
- package/dist/types/src/testing/test-utils.d.ts +3 -3
- package/dist/types/src/testing/test-utils.d.ts.map +1 -1
- package/dist/types/src/utils.d.ts +1 -1
- package/dist/types/src/utils.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +32 -32
- package/src/edge-client.test.ts +20 -15
- package/src/edge-client.ts +90 -43
- package/src/edge-http-client.test.ts +3 -2
- package/src/edge-http-client.ts +355 -74
- package/src/edge-ws-connection.ts +121 -7
- package/src/edge-ws-muxer.ts +1 -1
- package/src/http-client.test.ts +11 -7
- package/src/http-client.ts +18 -8
- package/src/index.ts +4 -3
- package/src/testing/test-utils.ts +8 -8
- package/src/websocket.test.ts +1 -1
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/testing/index.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-X7J46ISZ.mjs +0 -299
- package/dist/lib/node-esm/chunk-X7J46ISZ.mjs.map +0 -7
- package/dist/lib/node-esm/edge-ws-muxer.mjs +0 -12
- package/dist/lib/node-esm/edge-ws-muxer.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs +0 -1103
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/lib/node-esm/testing/index.mjs +0 -186
- package/dist/lib/node-esm/testing/index.mjs.map +0 -7
- /package/dist/lib/{browser → neutral}/edge-ws-muxer.mjs.map +0 -0
|
@@ -6,51 +6,131 @@ import {
|
|
|
6
6
|
getTypename,
|
|
7
7
|
protocol,
|
|
8
8
|
toUint8Array
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-ZIQ5T3A7.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, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 56, S: void 0, A: ["chain", ""] });
|
|
64
|
+
return signPresentation({
|
|
65
|
+
presentation: {
|
|
66
|
+
credentials: credentialsToSign
|
|
67
|
+
},
|
|
68
|
+
signer,
|
|
69
|
+
nonce: challenge,
|
|
70
|
+
signerKey: peerKey,
|
|
71
|
+
chain
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
var createEphemeralEdgeIdentity = async () => {
|
|
77
|
+
const keyring = new Keyring();
|
|
78
|
+
const key = await keyring.createKey();
|
|
79
|
+
return createDeviceEdgeIdentity(keyring, key);
|
|
80
|
+
};
|
|
81
|
+
var createTestHaloEdgeIdentity = async (signer, identityKey, deviceKey) => {
|
|
82
|
+
const deviceAdmission = await createCredential({
|
|
83
|
+
assertion: {
|
|
84
|
+
"@type": "dxos.halo.credentials.AuthorizedDevice",
|
|
85
|
+
deviceKey,
|
|
86
|
+
identityKey
|
|
87
|
+
},
|
|
88
|
+
issuer: identityKey,
|
|
89
|
+
subject: deviceKey,
|
|
90
|
+
signer
|
|
91
|
+
});
|
|
92
|
+
return createChainEdgeIdentity(signer, identityKey, deviceKey, {
|
|
93
|
+
credential: deviceAdmission
|
|
94
|
+
}, [
|
|
95
|
+
await createCredential({
|
|
96
|
+
assertion: {
|
|
97
|
+
"@type": "dxos.halo.credentials.Auth"
|
|
98
|
+
},
|
|
99
|
+
issuer: identityKey,
|
|
100
|
+
subject: identityKey,
|
|
101
|
+
signer
|
|
102
|
+
})
|
|
103
|
+
]);
|
|
104
|
+
};
|
|
105
|
+
var createStubEdgeIdentity = () => {
|
|
106
|
+
const identityKey = PublicKey.random();
|
|
107
|
+
const deviceKey = PublicKey.random();
|
|
108
|
+
return {
|
|
109
|
+
identityKey: identityKey.toHex(),
|
|
110
|
+
peerKey: deviceKey.toHex(),
|
|
111
|
+
presentCredentials: async () => {
|
|
112
|
+
throw new Error("Stub identity does not support authentication.");
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
|
|
14
117
|
// src/edge-client.ts
|
|
15
|
-
import {
|
|
118
|
+
import { Event, PersistentLifecycle, Trigger, TriggerState, scheduleMicroTask, scheduleTaskInterval as scheduleTaskInterval2 } from "@dxos/async";
|
|
119
|
+
import { TRACE_SPAN_ATTRIBUTE } from "@dxos/context";
|
|
16
120
|
import { Resource as Resource2 } from "@dxos/context";
|
|
17
121
|
import { log as log2, logInfo as logInfo2 } from "@dxos/log";
|
|
18
122
|
import { EdgeStatus } from "@dxos/protocols/proto/dxos/client/services";
|
|
19
123
|
|
|
20
124
|
// src/edge-identity.ts
|
|
21
|
-
import { invariant } from "@dxos/invariant";
|
|
125
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
22
126
|
import { schema } from "@dxos/protocols/proto";
|
|
23
|
-
var
|
|
127
|
+
var __dxlog_file2 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/edge-identity.ts";
|
|
24
128
|
var handleAuthChallenge = async (failedResponse, identity) => {
|
|
25
|
-
|
|
26
|
-
F: __dxlog_file,
|
|
27
|
-
L: 21,
|
|
28
|
-
S: void 0,
|
|
29
|
-
A: [
|
|
30
|
-
"failedResponse.status === 401",
|
|
31
|
-
""
|
|
32
|
-
]
|
|
33
|
-
});
|
|
129
|
+
invariant2(failedResponse.status === 401, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 7, S: void 0, A: ["failedResponse.status === 401", ""] });
|
|
34
130
|
const headerValue = failedResponse.headers.get("Www-Authenticate");
|
|
35
|
-
|
|
36
|
-
F: __dxlog_file,
|
|
37
|
-
L: 24,
|
|
38
|
-
S: void 0,
|
|
39
|
-
A: [
|
|
40
|
-
"headerValue?.startsWith('VerifiablePresentation challenge=')",
|
|
41
|
-
""
|
|
42
|
-
]
|
|
43
|
-
});
|
|
131
|
+
invariant2(headerValue?.startsWith("VerifiablePresentation challenge="), void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 9, S: void 0, A: ["headerValue?.startsWith('VerifiablePresentation challenge=')", ""] });
|
|
44
132
|
const challenge = headerValue?.slice("VerifiablePresentation challenge=".length);
|
|
45
|
-
|
|
46
|
-
F: __dxlog_file,
|
|
47
|
-
L: 27,
|
|
48
|
-
S: void 0,
|
|
49
|
-
A: [
|
|
50
|
-
"challenge",
|
|
51
|
-
""
|
|
52
|
-
]
|
|
53
|
-
});
|
|
133
|
+
invariant2(challenge, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 11, S: void 0, A: ["challenge", ""] });
|
|
54
134
|
const presentation = await identity.presentCredentials({
|
|
55
135
|
challenge: Buffer.from(challenge, "base64")
|
|
56
136
|
});
|
|
@@ -61,23 +141,42 @@ var handleAuthChallenge = async (failedResponse, identity) => {
|
|
|
61
141
|
import WebSocket from "isomorphic-ws";
|
|
62
142
|
import { scheduleTask, scheduleTaskInterval } from "@dxos/async";
|
|
63
143
|
import { Context, Resource } from "@dxos/context";
|
|
64
|
-
import { invariant as
|
|
144
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
65
145
|
import { log, logInfo } from "@dxos/log";
|
|
66
146
|
import { EdgeWebsocketProtocol } from "@dxos/protocols";
|
|
67
147
|
import { buf } from "@dxos/protocols/buf";
|
|
68
148
|
import { MessageSchema } from "@dxos/protocols/buf/dxos/edge/messenger_pb";
|
|
149
|
+
var __dxlog_file3 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/edge-ws-connection.ts";
|
|
69
150
|
function _ts_decorate(decorators, target, key, desc) {
|
|
70
151
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
71
152
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
72
153
|
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
154
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
74
155
|
}
|
|
75
|
-
var __dxlog_file2 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/edge-ws-connection.ts";
|
|
76
156
|
var SIGNAL_KEEPALIVE_INTERVAL = 4e3;
|
|
77
157
|
var SIGNAL_KEEPALIVE_TIMEOUT = 12e3;
|
|
78
158
|
var EdgeWsConnection = class extends Resource {
|
|
159
|
+
_identity;
|
|
160
|
+
_connectionInfo;
|
|
161
|
+
_callbacks;
|
|
162
|
+
_inactivityTimeoutCtx;
|
|
163
|
+
_ws;
|
|
164
|
+
_wsMuxer;
|
|
165
|
+
_lastReceivedMessageTimestamp = Date.now();
|
|
166
|
+
_openTimestamp;
|
|
167
|
+
// Latency tracking.
|
|
168
|
+
_pingTimestamp;
|
|
169
|
+
_rtt = 0;
|
|
170
|
+
// Rate tracking with sliding window.
|
|
171
|
+
_uploadRate = 0;
|
|
172
|
+
_downloadRate = 0;
|
|
173
|
+
_rateWindow = 1e4;
|
|
174
|
+
_rateUpdateInterval = 1e3;
|
|
175
|
+
_bytesSamples = [];
|
|
176
|
+
_messagesSent = 0;
|
|
177
|
+
_messagesReceived = 0;
|
|
79
178
|
constructor(_identity, _connectionInfo, _callbacks) {
|
|
80
|
-
super(), this._identity = _identity, this._connectionInfo = _connectionInfo, this._callbacks = _callbacks
|
|
179
|
+
super(), this._identity = _identity, this._connectionInfo = _connectionInfo, this._callbacks = _callbacks;
|
|
81
180
|
}
|
|
82
181
|
get info() {
|
|
83
182
|
return {
|
|
@@ -86,34 +185,32 @@ var EdgeWsConnection = class extends Resource {
|
|
|
86
185
|
device: this._identity.peerKey
|
|
87
186
|
};
|
|
88
187
|
}
|
|
188
|
+
get rtt() {
|
|
189
|
+
return this._rtt;
|
|
190
|
+
}
|
|
191
|
+
get uptime() {
|
|
192
|
+
return this._openTimestamp ? (Date.now() - this._openTimestamp) / 1e3 : 0;
|
|
193
|
+
}
|
|
194
|
+
get uploadRate() {
|
|
195
|
+
return this._uploadRate;
|
|
196
|
+
}
|
|
197
|
+
get downloadRate() {
|
|
198
|
+
return this._downloadRate;
|
|
199
|
+
}
|
|
200
|
+
get messagesSent() {
|
|
201
|
+
return this._messagesSent;
|
|
202
|
+
}
|
|
203
|
+
get messagesReceived() {
|
|
204
|
+
return this._messagesReceived;
|
|
205
|
+
}
|
|
89
206
|
send(message) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
L: 53,
|
|
93
|
-
S: this,
|
|
94
|
-
A: [
|
|
95
|
-
"this._ws",
|
|
96
|
-
""
|
|
97
|
-
]
|
|
98
|
-
});
|
|
99
|
-
invariant2(this._wsMuxer, void 0, {
|
|
100
|
-
F: __dxlog_file2,
|
|
101
|
-
L: 54,
|
|
102
|
-
S: this,
|
|
103
|
-
A: [
|
|
104
|
-
"this._wsMuxer",
|
|
105
|
-
""
|
|
106
|
-
]
|
|
107
|
-
});
|
|
207
|
+
invariant3(this._ws, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 72, S: this, A: ["this._ws", ""] });
|
|
208
|
+
invariant3(this._wsMuxer, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 73, S: this, A: ["this._wsMuxer", ""] });
|
|
108
209
|
log("sending...", {
|
|
109
210
|
peerKey: this._identity.peerKey,
|
|
110
211
|
payload: protocol.getPayloadType(message)
|
|
111
|
-
}, {
|
|
112
|
-
|
|
113
|
-
L: 55,
|
|
114
|
-
S: this,
|
|
115
|
-
C: (f, a) => f(...a)
|
|
116
|
-
});
|
|
212
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 74, S: this });
|
|
213
|
+
this._messagesSent++;
|
|
117
214
|
if (this._ws?.protocol.includes(EdgeWebsocketProtocol.V0)) {
|
|
118
215
|
const binary = buf.toBinary(MessageSchema, message);
|
|
119
216
|
if (binary.length > CLOUDFLARE_MESSAGE_MAX_BYTES) {
|
|
@@ -121,22 +218,15 @@ var EdgeWsConnection = class extends Resource {
|
|
|
121
218
|
byteLength: binary.byteLength,
|
|
122
219
|
serviceId: message.serviceId,
|
|
123
220
|
payload: protocol.getPayloadType(message)
|
|
124
|
-
}, {
|
|
125
|
-
F: __dxlog_file2,
|
|
126
|
-
L: 59,
|
|
127
|
-
S: this,
|
|
128
|
-
C: (f, a) => f(...a)
|
|
129
|
-
});
|
|
221
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 82, S: this });
|
|
130
222
|
return;
|
|
131
223
|
}
|
|
224
|
+
this._recordBytes(binary.byteLength, 0);
|
|
132
225
|
this._ws.send(binary);
|
|
133
226
|
} else {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
S: this,
|
|
138
|
-
C: (f, a) => f(...a)
|
|
139
|
-
}));
|
|
227
|
+
const binary = buf.toBinary(MessageSchema, message);
|
|
228
|
+
this._recordBytes(binary.byteLength, 0);
|
|
229
|
+
this._wsMuxer.send(message).catch((e) => log.catch(e, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 95, S: this }));
|
|
140
230
|
}
|
|
141
231
|
}
|
|
142
232
|
async _open() {
|
|
@@ -148,41 +238,30 @@ var EdgeWsConnection = class extends Resource {
|
|
|
148
238
|
this._connectionInfo.protocolHeader
|
|
149
239
|
] : [
|
|
150
240
|
...baseProtocols
|
|
151
|
-
]
|
|
241
|
+
], this._connectionInfo.headers ? {
|
|
242
|
+
headers: this._connectionInfo.headers
|
|
243
|
+
} : void 0);
|
|
152
244
|
const muxer = new WebSocketMuxer(this._ws);
|
|
153
245
|
this._wsMuxer = muxer;
|
|
154
246
|
this._ws.onopen = () => {
|
|
155
247
|
if (this.isOpen) {
|
|
156
|
-
log("connected", void 0, {
|
|
157
|
-
|
|
158
|
-
L: 85,
|
|
159
|
-
S: this,
|
|
160
|
-
C: (f, a) => f(...a)
|
|
161
|
-
});
|
|
248
|
+
log("connected", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 114, S: this });
|
|
249
|
+
this._openTimestamp = Date.now();
|
|
162
250
|
this._callbacks.onConnected();
|
|
163
251
|
this._scheduleHeartbeats();
|
|
252
|
+
this._scheduleRateCalculation();
|
|
164
253
|
} else {
|
|
165
254
|
log.verbose("connected after becoming inactive", {
|
|
166
255
|
currentIdentity: this._identity
|
|
167
|
-
}, {
|
|
168
|
-
F: __dxlog_file2,
|
|
169
|
-
L: 89,
|
|
170
|
-
S: this,
|
|
171
|
-
C: (f, a) => f(...a)
|
|
172
|
-
});
|
|
256
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 120, S: this });
|
|
173
257
|
}
|
|
174
258
|
};
|
|
175
259
|
this._ws.onclose = (event) => {
|
|
176
260
|
if (this.isOpen) {
|
|
177
|
-
log.warn("disconnected
|
|
261
|
+
log.warn("server disconnected", {
|
|
178
262
|
code: event.code,
|
|
179
263
|
reason: event.reason
|
|
180
|
-
}, {
|
|
181
|
-
F: __dxlog_file2,
|
|
182
|
-
L: 94,
|
|
183
|
-
S: this,
|
|
184
|
-
C: (f, a) => f(...a)
|
|
185
|
-
});
|
|
264
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 127, S: this });
|
|
186
265
|
this._callbacks.onRestartRequired();
|
|
187
266
|
muxer.destroy();
|
|
188
267
|
}
|
|
@@ -192,56 +271,42 @@ var EdgeWsConnection = class extends Resource {
|
|
|
192
271
|
log.warn("edge connection socket error", {
|
|
193
272
|
error: event.error,
|
|
194
273
|
info: event.message
|
|
195
|
-
}, {
|
|
196
|
-
F: __dxlog_file2,
|
|
197
|
-
L: 101,
|
|
198
|
-
S: this,
|
|
199
|
-
C: (f, a) => f(...a)
|
|
200
|
-
});
|
|
274
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 137, S: this });
|
|
201
275
|
this._callbacks.onRestartRequired();
|
|
202
276
|
} else {
|
|
203
277
|
log.verbose("error ignored on closed connection", {
|
|
204
278
|
error: event.error
|
|
205
|
-
}, {
|
|
206
|
-
F: __dxlog_file2,
|
|
207
|
-
L: 104,
|
|
208
|
-
S: this,
|
|
209
|
-
C: (f, a) => f(...a)
|
|
210
|
-
});
|
|
279
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 143, S: this });
|
|
211
280
|
}
|
|
212
281
|
};
|
|
213
282
|
this._ws.onmessage = async (event) => {
|
|
214
283
|
if (!this.isOpen) {
|
|
215
284
|
log.verbose("message ignored on closed connection", {
|
|
216
285
|
event: event.type
|
|
217
|
-
}, {
|
|
218
|
-
F: __dxlog_file2,
|
|
219
|
-
L: 112,
|
|
220
|
-
S: this,
|
|
221
|
-
C: (f, a) => f(...a)
|
|
222
|
-
});
|
|
286
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 152, S: this });
|
|
223
287
|
return;
|
|
224
288
|
}
|
|
225
289
|
this._lastReceivedMessageTimestamp = Date.now();
|
|
226
290
|
if (event.data === "__pong__") {
|
|
291
|
+
if (this._pingTimestamp) {
|
|
292
|
+
this._rtt = Date.now() - this._pingTimestamp;
|
|
293
|
+
this._pingTimestamp = void 0;
|
|
294
|
+
}
|
|
227
295
|
this._rescheduleHeartbeatTimeout();
|
|
228
296
|
return;
|
|
229
297
|
}
|
|
230
298
|
const bytes = await toUint8Array(event.data);
|
|
299
|
+
this._recordBytes(0, bytes.byteLength);
|
|
231
300
|
if (!this.isOpen) {
|
|
232
301
|
return;
|
|
233
302
|
}
|
|
303
|
+
this._messagesReceived++;
|
|
234
304
|
const message = this._ws?.protocol?.includes(EdgeWebsocketProtocol.V0) ? buf.fromBinary(MessageSchema, bytes) : muxer.receiveData(bytes);
|
|
235
305
|
if (message) {
|
|
236
306
|
log("received", {
|
|
237
307
|
from: message.source,
|
|
238
308
|
payload: protocol.getPayloadType(message)
|
|
239
|
-
}, {
|
|
240
|
-
F: __dxlog_file2,
|
|
241
|
-
L: 130,
|
|
242
|
-
S: this,
|
|
243
|
-
C: (f, a) => f(...a)
|
|
244
|
-
});
|
|
309
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 175, S: this });
|
|
245
310
|
this._callbacks.onMessage(message);
|
|
246
311
|
}
|
|
247
312
|
};
|
|
@@ -258,29 +323,18 @@ var EdgeWsConnection = class extends Resource {
|
|
|
258
323
|
if (err instanceof Error && err.message.includes("WebSocket is closed before the connection is established.")) {
|
|
259
324
|
return;
|
|
260
325
|
}
|
|
261
|
-
log.warn("
|
|
326
|
+
log.warn("error closing websocket", {
|
|
262
327
|
err
|
|
263
|
-
}, {
|
|
264
|
-
F: __dxlog_file2,
|
|
265
|
-
L: 148,
|
|
266
|
-
S: this,
|
|
267
|
-
C: (f, a) => f(...a)
|
|
268
|
-
});
|
|
328
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 194, S: this });
|
|
269
329
|
}
|
|
270
330
|
}
|
|
271
331
|
_scheduleHeartbeats() {
|
|
272
|
-
|
|
273
|
-
F: __dxlog_file2,
|
|
274
|
-
L: 153,
|
|
275
|
-
S: this,
|
|
276
|
-
A: [
|
|
277
|
-
"this._ws",
|
|
278
|
-
""
|
|
279
|
-
]
|
|
280
|
-
});
|
|
332
|
+
invariant3(this._ws, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 200, S: this, A: ["this._ws", ""] });
|
|
281
333
|
scheduleTaskInterval(this._ctx, async () => {
|
|
334
|
+
this._pingTimestamp = Date.now();
|
|
282
335
|
this._ws?.send("__ping__");
|
|
283
336
|
}, SIGNAL_KEEPALIVE_INTERVAL);
|
|
337
|
+
this._pingTimestamp = Date.now();
|
|
284
338
|
this._ws.send("__ping__");
|
|
285
339
|
this._rescheduleHeartbeatTimeout();
|
|
286
340
|
}
|
|
@@ -289,21 +343,13 @@ var EdgeWsConnection = class extends Resource {
|
|
|
289
343
|
return;
|
|
290
344
|
}
|
|
291
345
|
void this._inactivityTimeoutCtx?.dispose();
|
|
292
|
-
this._inactivityTimeoutCtx = new Context(void 0, {
|
|
293
|
-
F: __dxlog_file2,
|
|
294
|
-
L: 172
|
|
295
|
-
});
|
|
346
|
+
this._inactivityTimeoutCtx = new Context(void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 216 });
|
|
296
347
|
scheduleTask(this._inactivityTimeoutCtx, () => {
|
|
297
348
|
if (this.isOpen) {
|
|
298
349
|
if (Date.now() - this._lastReceivedMessageTimestamp > SIGNAL_KEEPALIVE_TIMEOUT) {
|
|
299
350
|
log.warn("restart due to inactivity timeout", {
|
|
300
351
|
lastReceivedMessageTimestamp: this._lastReceivedMessageTimestamp
|
|
301
|
-
}, {
|
|
302
|
-
F: __dxlog_file2,
|
|
303
|
-
L: 178,
|
|
304
|
-
S: this,
|
|
305
|
-
C: (f, a) => f(...a)
|
|
306
|
-
});
|
|
352
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 220, S: this });
|
|
307
353
|
this._callbacks.onRestartRequired();
|
|
308
354
|
} else {
|
|
309
355
|
this._rescheduleHeartbeatTimeout();
|
|
@@ -311,6 +357,47 @@ var EdgeWsConnection = class extends Resource {
|
|
|
311
357
|
}
|
|
312
358
|
}, SIGNAL_KEEPALIVE_TIMEOUT);
|
|
313
359
|
}
|
|
360
|
+
_recordBytes(sent, received) {
|
|
361
|
+
const now = Date.now();
|
|
362
|
+
const currentSecond = Math.floor(now / 1e3) * 1e3;
|
|
363
|
+
const existingSample = this._bytesSamples.find((s) => Math.floor(s.timestamp / 1e3) * 1e3 === currentSecond);
|
|
364
|
+
if (existingSample) {
|
|
365
|
+
existingSample.sent += sent;
|
|
366
|
+
existingSample.received += received;
|
|
367
|
+
} else {
|
|
368
|
+
this._bytesSamples.push({
|
|
369
|
+
timestamp: now,
|
|
370
|
+
sent,
|
|
371
|
+
received
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
_scheduleRateCalculation() {
|
|
376
|
+
scheduleTaskInterval(this._ctx, async () => {
|
|
377
|
+
this._calculateRates();
|
|
378
|
+
}, this._rateUpdateInterval);
|
|
379
|
+
this._calculateRates();
|
|
380
|
+
}
|
|
381
|
+
_calculateRates() {
|
|
382
|
+
const now = Date.now();
|
|
383
|
+
const cutoff = now - this._rateWindow;
|
|
384
|
+
this._bytesSamples = this._bytesSamples.filter((s) => s.timestamp > cutoff);
|
|
385
|
+
if (this._bytesSamples.length === 0) {
|
|
386
|
+
this._uploadRate = 0;
|
|
387
|
+
this._downloadRate = 0;
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
let totalSent = 0;
|
|
391
|
+
let totalReceived = 0;
|
|
392
|
+
const oldestTimestamp = Math.min(...this._bytesSamples.map((s) => s.timestamp));
|
|
393
|
+
const timeSpan = (now - oldestTimestamp) / 1e3;
|
|
394
|
+
for (const sample of this._bytesSamples) {
|
|
395
|
+
totalSent += sample.sent;
|
|
396
|
+
totalReceived += sample.received;
|
|
397
|
+
}
|
|
398
|
+
this._uploadRate = timeSpan > 0 ? Math.round(totalSent / timeSpan) : 0;
|
|
399
|
+
this._downloadRate = timeSpan > 0 ? Math.round(totalReceived / timeSpan) : 0;
|
|
400
|
+
}
|
|
314
401
|
};
|
|
315
402
|
_ts_decorate([
|
|
316
403
|
logInfo
|
|
@@ -337,20 +424,31 @@ var getEdgeUrlWithProtocol = (baseUrl, protocol2) => {
|
|
|
337
424
|
};
|
|
338
425
|
|
|
339
426
|
// src/edge-client.ts
|
|
427
|
+
var __dxlog_file4 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/edge-client.ts";
|
|
340
428
|
function _ts_decorate2(decorators, target, key, desc) {
|
|
341
429
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
342
430
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
343
431
|
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;
|
|
344
432
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
345
433
|
}
|
|
346
|
-
var __dxlog_file3 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/edge-client.ts";
|
|
347
434
|
var DEFAULT_TIMEOUT = 1e4;
|
|
435
|
+
var STATUS_REFRESH_INTERVAL = 1e3;
|
|
348
436
|
var EdgeClient = class extends Resource2 {
|
|
437
|
+
_identity;
|
|
438
|
+
_config;
|
|
439
|
+
statusChanged = new Event();
|
|
440
|
+
_persistentLifecycle = new PersistentLifecycle({
|
|
441
|
+
start: async () => this._connect(),
|
|
442
|
+
stop: async (state) => this._disconnect(state)
|
|
443
|
+
});
|
|
444
|
+
_messageListeners = /* @__PURE__ */ new Set();
|
|
445
|
+
_reconnectListeners = /* @__PURE__ */ new Set();
|
|
446
|
+
_baseWsUrl;
|
|
447
|
+
_baseHttpUrl;
|
|
448
|
+
_currentConnection = void 0;
|
|
449
|
+
_ready = new Trigger();
|
|
349
450
|
constructor(_identity, _config) {
|
|
350
|
-
super(), this._identity = _identity, this._config = _config
|
|
351
|
-
start: async () => this._connect(),
|
|
352
|
-
stop: async (state) => this._disconnect(state)
|
|
353
|
-
}), this._messageListeners = /* @__PURE__ */ new Set(), this._reconnectListeners = /* @__PURE__ */ new Set(), this._currentConnection = void 0, this._ready = new Trigger(), this._isActive = (connection) => connection === this._currentConnection;
|
|
451
|
+
super(), this._identity = _identity, this._config = _config;
|
|
354
452
|
this._baseWsUrl = getEdgeUrlWithProtocol(_config.socketEndpoint, "ws");
|
|
355
453
|
this._baseHttpUrl = getEdgeUrlWithProtocol(_config.socketEndpoint, "http");
|
|
356
454
|
}
|
|
@@ -363,7 +461,15 @@ var EdgeClient = class extends Resource2 {
|
|
|
363
461
|
};
|
|
364
462
|
}
|
|
365
463
|
get status() {
|
|
366
|
-
return
|
|
464
|
+
return {
|
|
465
|
+
state: Boolean(this._currentConnection) && this._ready.state === TriggerState.RESOLVED ? EdgeStatus.ConnectionState.CONNECTED : EdgeStatus.ConnectionState.NOT_CONNECTED,
|
|
466
|
+
uptime: this._currentConnection?.uptime ?? 0,
|
|
467
|
+
rtt: this._currentConnection?.rtt ?? 0,
|
|
468
|
+
rateBytesUp: this._currentConnection?.uploadRate ?? 0,
|
|
469
|
+
rateBytesDown: this._currentConnection?.downloadRate ?? 0,
|
|
470
|
+
messagesSent: this._currentConnection?.messagesSent ?? 0,
|
|
471
|
+
messagesReceived: this._currentConnection?.messagesReceived ?? 0
|
|
472
|
+
};
|
|
367
473
|
}
|
|
368
474
|
get identityKey() {
|
|
369
475
|
return this._identity.identityKey;
|
|
@@ -376,17 +482,39 @@ var EdgeClient = class extends Resource2 {
|
|
|
376
482
|
log2("Edge identity changed", {
|
|
377
483
|
identity,
|
|
378
484
|
oldIdentity: this._identity
|
|
379
|
-
}, {
|
|
380
|
-
F: __dxlog_file3,
|
|
381
|
-
L: 99,
|
|
382
|
-
S: this,
|
|
383
|
-
C: (f, a) => f(...a)
|
|
384
|
-
});
|
|
485
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 74, S: this });
|
|
385
486
|
this._identity = identity;
|
|
386
487
|
this._closeCurrentConnection(new EdgeIdentityChangedError());
|
|
387
488
|
void this._persistentLifecycle.scheduleRestart();
|
|
388
489
|
}
|
|
389
490
|
}
|
|
491
|
+
/**
|
|
492
|
+
* Send message.
|
|
493
|
+
* NOTE: The message is guaranteed to be delivered but the service must respond with a message to confirm processing.
|
|
494
|
+
*/
|
|
495
|
+
async send(ctx, message) {
|
|
496
|
+
if (this._ready.state !== TriggerState.RESOLVED) {
|
|
497
|
+
log2("waiting for websocket", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 88, S: this });
|
|
498
|
+
await this._ready.wait({
|
|
499
|
+
timeout: this._config.timeout ?? DEFAULT_TIMEOUT
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
if (!this._currentConnection) {
|
|
503
|
+
throw new EdgeConnectionClosedError();
|
|
504
|
+
}
|
|
505
|
+
if (message.source && (message.source.peerKey !== this._identity.peerKey || message.source.identityKey !== this.identityKey)) {
|
|
506
|
+
throw new EdgeIdentityChangedError();
|
|
507
|
+
}
|
|
508
|
+
const traceCtx = ctx.getAttribute(TRACE_SPAN_ATTRIBUTE);
|
|
509
|
+
if (traceCtx) {
|
|
510
|
+
message.traceContext = {
|
|
511
|
+
$typeName: "dxos.edge.messenger.TraceContext",
|
|
512
|
+
traceparent: traceCtx.traceparent,
|
|
513
|
+
tracestate: traceCtx.tracestate
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
this._currentConnection.send(message);
|
|
517
|
+
}
|
|
390
518
|
onMessage(listener) {
|
|
391
519
|
this._messageListeners.add(listener);
|
|
392
520
|
return () => this._messageListeners.delete(listener);
|
|
@@ -399,12 +527,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
399
527
|
try {
|
|
400
528
|
listener();
|
|
401
529
|
} catch (error) {
|
|
402
|
-
log2.catch(error, void 0, {
|
|
403
|
-
F: __dxlog_file3,
|
|
404
|
-
L: 121,
|
|
405
|
-
S: this,
|
|
406
|
-
C: (f, a) => f(...a)
|
|
407
|
-
});
|
|
530
|
+
log2.catch(error, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 123, S: this });
|
|
408
531
|
}
|
|
409
532
|
}
|
|
410
533
|
});
|
|
@@ -417,22 +540,18 @@ var EdgeClient = class extends Resource2 {
|
|
|
417
540
|
async _open() {
|
|
418
541
|
log2("opening...", {
|
|
419
542
|
info: this.info
|
|
420
|
-
}, {
|
|
421
|
-
F: __dxlog_file3,
|
|
422
|
-
L: 133,
|
|
423
|
-
S: this,
|
|
424
|
-
C: (f, a) => f(...a)
|
|
425
|
-
});
|
|
543
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 133, S: this });
|
|
426
544
|
this._persistentLifecycle.open().catch((err) => {
|
|
427
545
|
log2.warn("Error while opening connection", {
|
|
428
546
|
err
|
|
429
|
-
}, {
|
|
430
|
-
F: __dxlog_file3,
|
|
431
|
-
L: 135,
|
|
432
|
-
S: this,
|
|
433
|
-
C: (f, a) => f(...a)
|
|
434
|
-
});
|
|
547
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 137, S: this });
|
|
435
548
|
});
|
|
549
|
+
scheduleTaskInterval2(this._ctx, async () => {
|
|
550
|
+
if (!this._currentConnection) {
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
this.statusChanged.emit(this.status);
|
|
554
|
+
}, STATUS_REFRESH_INTERVAL);
|
|
436
555
|
}
|
|
437
556
|
/**
|
|
438
557
|
* Close connection and free resources.
|
|
@@ -440,12 +559,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
440
559
|
async _close() {
|
|
441
560
|
log2("closing...", {
|
|
442
561
|
peerKey: this._identity.peerKey
|
|
443
|
-
}, {
|
|
444
|
-
F: __dxlog_file3,
|
|
445
|
-
L: 143,
|
|
446
|
-
S: this,
|
|
447
|
-
C: (f, a) => f(...a)
|
|
448
|
-
});
|
|
562
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 152, S: this });
|
|
449
563
|
this._closeCurrentConnection();
|
|
450
564
|
await this._persistentLifecycle.close();
|
|
451
565
|
}
|
|
@@ -457,12 +571,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
457
571
|
const path = `/ws/${identity.identityKey}/${identity.peerKey}`;
|
|
458
572
|
const protocolHeader = this._config.disableAuth ? void 0 : await this._createAuthHeader(path);
|
|
459
573
|
if (this._identity !== identity) {
|
|
460
|
-
log2("identity changed during auth header request", void 0, {
|
|
461
|
-
F: __dxlog_file3,
|
|
462
|
-
L: 157,
|
|
463
|
-
S: this,
|
|
464
|
-
C: (f, a) => f(...a)
|
|
465
|
-
});
|
|
574
|
+
log2("identity changed during auth header request", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 166, S: this });
|
|
466
575
|
return void 0;
|
|
467
576
|
}
|
|
468
577
|
const restartRequired = new Trigger();
|
|
@@ -470,27 +579,20 @@ var EdgeClient = class extends Resource2 {
|
|
|
470
579
|
log2("Opening websocket", {
|
|
471
580
|
url: url.toString(),
|
|
472
581
|
protocolHeader
|
|
473
|
-
}, {
|
|
474
|
-
F: __dxlog_file3,
|
|
475
|
-
L: 163,
|
|
476
|
-
S: this,
|
|
477
|
-
C: (f, a) => f(...a)
|
|
478
|
-
});
|
|
582
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 171, S: this });
|
|
479
583
|
const connection = new EdgeWsConnection(identity, {
|
|
480
584
|
url,
|
|
481
|
-
protocolHeader
|
|
585
|
+
protocolHeader,
|
|
586
|
+
headers: this._config.clientTag ? {
|
|
587
|
+
"X-DXOS-Client-Tag": this._config.clientTag
|
|
588
|
+
} : void 0
|
|
482
589
|
}, {
|
|
483
590
|
onConnected: () => {
|
|
484
591
|
if (this._isActive(connection)) {
|
|
485
592
|
this._ready.wake();
|
|
486
593
|
this._notifyReconnected();
|
|
487
594
|
} else {
|
|
488
|
-
log2.verbose("connected callback ignored, because connection is not active", void 0, {
|
|
489
|
-
F: __dxlog_file3,
|
|
490
|
-
L: 173,
|
|
491
|
-
S: this,
|
|
492
|
-
C: (f, a) => f(...a)
|
|
493
|
-
});
|
|
595
|
+
log2.verbose("connected callback ignored, because connection is not active", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 187, S: this });
|
|
494
596
|
}
|
|
495
597
|
},
|
|
496
598
|
onRestartRequired: () => {
|
|
@@ -498,12 +600,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
498
600
|
this._closeCurrentConnection();
|
|
499
601
|
void this._persistentLifecycle.scheduleRestart();
|
|
500
602
|
} else {
|
|
501
|
-
log2.verbose("restart requested by inactive connection", void 0, {
|
|
502
|
-
F: __dxlog_file3,
|
|
503
|
-
L: 181,
|
|
504
|
-
S: this,
|
|
505
|
-
C: (f, a) => f(...a)
|
|
506
|
-
});
|
|
603
|
+
log2.verbose("restart requested by inactive connection", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 195, S: this });
|
|
507
604
|
}
|
|
508
605
|
restartRequired.wake();
|
|
509
606
|
},
|
|
@@ -514,12 +611,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
514
611
|
log2.verbose("ignored a message on inactive connection", {
|
|
515
612
|
from: message.source,
|
|
516
613
|
type: message.payload?.typeUrl
|
|
517
|
-
}, {
|
|
518
|
-
F: __dxlog_file3,
|
|
519
|
-
L: 189,
|
|
520
|
-
S: this,
|
|
521
|
-
C: (f, a) => f(...a)
|
|
522
|
-
});
|
|
614
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 203, S: this });
|
|
523
615
|
}
|
|
524
616
|
}
|
|
525
617
|
});
|
|
@@ -551,12 +643,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
551
643
|
} catch (err) {
|
|
552
644
|
log2.error("ws reconnect listener failed", {
|
|
553
645
|
err
|
|
554
|
-
}, {
|
|
555
|
-
F: __dxlog_file3,
|
|
556
|
-
L: 225,
|
|
557
|
-
S: this,
|
|
558
|
-
C: (f, a) => f(...a)
|
|
559
|
-
});
|
|
646
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 238, S: this });
|
|
560
647
|
}
|
|
561
648
|
}
|
|
562
649
|
}
|
|
@@ -568,39 +655,10 @@ var EdgeClient = class extends Resource2 {
|
|
|
568
655
|
log2.error("ws incoming message processing failed", {
|
|
569
656
|
err,
|
|
570
657
|
payload: protocol.getPayloadType(message)
|
|
571
|
-
}, {
|
|
572
|
-
F: __dxlog_file3,
|
|
573
|
-
L: 235,
|
|
574
|
-
S: this,
|
|
575
|
-
C: (f, a) => f(...a)
|
|
576
|
-
});
|
|
658
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 249, S: this });
|
|
577
659
|
}
|
|
578
660
|
}
|
|
579
661
|
}
|
|
580
|
-
/**
|
|
581
|
-
* Send message.
|
|
582
|
-
* NOTE: The message is guaranteed to be delivered but the service must respond with a message to confirm processing.
|
|
583
|
-
*/
|
|
584
|
-
async send(message) {
|
|
585
|
-
if (this._ready.state !== TriggerState.RESOLVED) {
|
|
586
|
-
log2("waiting for websocket to become ready", void 0, {
|
|
587
|
-
F: __dxlog_file3,
|
|
588
|
-
L: 246,
|
|
589
|
-
S: this,
|
|
590
|
-
C: (f, a) => f(...a)
|
|
591
|
-
});
|
|
592
|
-
await this._ready.wait({
|
|
593
|
-
timeout: this._config.timeout ?? DEFAULT_TIMEOUT
|
|
594
|
-
});
|
|
595
|
-
}
|
|
596
|
-
if (!this._currentConnection) {
|
|
597
|
-
throw new EdgeConnectionClosedError();
|
|
598
|
-
}
|
|
599
|
-
if (message.source && (message.source.peerKey !== this._identity.peerKey || message.source.identityKey !== this.identityKey)) {
|
|
600
|
-
throw new EdgeIdentityChangedError();
|
|
601
|
-
}
|
|
602
|
-
this._currentConnection.send(message);
|
|
603
|
-
}
|
|
604
662
|
async _createAuthHeader(path) {
|
|
605
663
|
const httpUrl = new URL(path, this._baseHttpUrl);
|
|
606
664
|
httpUrl.protocol = getEdgeUrlWithProtocol(this._baseWsUrl.toString(), "http");
|
|
@@ -613,15 +671,11 @@ var EdgeClient = class extends Resource2 {
|
|
|
613
671
|
log2.warn("no auth challenge from edge", {
|
|
614
672
|
status: response.status,
|
|
615
673
|
statusText: response.statusText
|
|
616
|
-
}, {
|
|
617
|
-
F: __dxlog_file3,
|
|
618
|
-
L: 271,
|
|
619
|
-
S: this,
|
|
620
|
-
C: (f, a) => f(...a)
|
|
621
|
-
});
|
|
674
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 265, S: this });
|
|
622
675
|
return void 0;
|
|
623
676
|
}
|
|
624
677
|
}
|
|
678
|
+
_isActive = (connection) => connection === this._currentConnection;
|
|
625
679
|
};
|
|
626
680
|
_ts_decorate2([
|
|
627
681
|
logInfo2
|
|
@@ -631,144 +685,39 @@ var encodePresentationWsAuthHeader = (encodedPresentation) => {
|
|
|
631
685
|
return `base64url.bearer.authorization.dxos.org.${encodedToken}`;
|
|
632
686
|
};
|
|
633
687
|
|
|
634
|
-
// src/auth.ts
|
|
635
|
-
import { createCredential, signPresentation } from "@dxos/credentials";
|
|
636
|
-
import { invariant as invariant3 } from "@dxos/invariant";
|
|
637
|
-
import { Keyring } from "@dxos/keyring";
|
|
638
|
-
import { PublicKey } from "@dxos/keys";
|
|
639
|
-
var __dxlog_file4 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/auth.ts";
|
|
640
|
-
var createDeviceEdgeIdentity = async (signer, key) => {
|
|
641
|
-
return {
|
|
642
|
-
identityKey: key.toHex(),
|
|
643
|
-
peerKey: key.toHex(),
|
|
644
|
-
presentCredentials: async ({ challenge }) => {
|
|
645
|
-
return signPresentation({
|
|
646
|
-
presentation: {
|
|
647
|
-
credentials: [
|
|
648
|
-
// Verifier requires at least one credential in the presentation to establish the subject.
|
|
649
|
-
await createCredential({
|
|
650
|
-
assertion: {
|
|
651
|
-
"@type": "dxos.halo.credentials.Auth"
|
|
652
|
-
},
|
|
653
|
-
issuer: key,
|
|
654
|
-
subject: key,
|
|
655
|
-
signer
|
|
656
|
-
})
|
|
657
|
-
]
|
|
658
|
-
},
|
|
659
|
-
signer,
|
|
660
|
-
signerKey: key,
|
|
661
|
-
nonce: challenge
|
|
662
|
-
});
|
|
663
|
-
}
|
|
664
|
-
};
|
|
665
|
-
};
|
|
666
|
-
var createChainEdgeIdentity = async (signer, identityKey, peerKey, chain, credentials) => {
|
|
667
|
-
const credentialsToSign = credentials.length > 0 ? credentials : [
|
|
668
|
-
await createCredential({
|
|
669
|
-
assertion: {
|
|
670
|
-
"@type": "dxos.halo.credentials.Auth"
|
|
671
|
-
},
|
|
672
|
-
issuer: identityKey,
|
|
673
|
-
subject: identityKey,
|
|
674
|
-
signer,
|
|
675
|
-
chain,
|
|
676
|
-
signingKey: peerKey
|
|
677
|
-
})
|
|
678
|
-
];
|
|
679
|
-
return {
|
|
680
|
-
identityKey: identityKey.toHex(),
|
|
681
|
-
peerKey: peerKey.toHex(),
|
|
682
|
-
presentCredentials: async ({ challenge }) => {
|
|
683
|
-
invariant3(chain, void 0, {
|
|
684
|
-
F: __dxlog_file4,
|
|
685
|
-
L: 75,
|
|
686
|
-
S: void 0,
|
|
687
|
-
A: [
|
|
688
|
-
"chain",
|
|
689
|
-
""
|
|
690
|
-
]
|
|
691
|
-
});
|
|
692
|
-
return signPresentation({
|
|
693
|
-
presentation: {
|
|
694
|
-
credentials: credentialsToSign
|
|
695
|
-
},
|
|
696
|
-
signer,
|
|
697
|
-
nonce: challenge,
|
|
698
|
-
signerKey: peerKey,
|
|
699
|
-
chain
|
|
700
|
-
});
|
|
701
|
-
}
|
|
702
|
-
};
|
|
703
|
-
};
|
|
704
|
-
var createEphemeralEdgeIdentity = async () => {
|
|
705
|
-
const keyring = new Keyring();
|
|
706
|
-
const key = await keyring.createKey();
|
|
707
|
-
return createDeviceEdgeIdentity(keyring, key);
|
|
708
|
-
};
|
|
709
|
-
var createTestHaloEdgeIdentity = async (signer, identityKey, deviceKey) => {
|
|
710
|
-
const deviceAdmission = await createCredential({
|
|
711
|
-
assertion: {
|
|
712
|
-
"@type": "dxos.halo.credentials.AuthorizedDevice",
|
|
713
|
-
deviceKey,
|
|
714
|
-
identityKey
|
|
715
|
-
},
|
|
716
|
-
issuer: identityKey,
|
|
717
|
-
subject: deviceKey,
|
|
718
|
-
signer
|
|
719
|
-
});
|
|
720
|
-
return createChainEdgeIdentity(signer, identityKey, deviceKey, {
|
|
721
|
-
credential: deviceAdmission
|
|
722
|
-
}, [
|
|
723
|
-
await createCredential({
|
|
724
|
-
assertion: {
|
|
725
|
-
"@type": "dxos.halo.credentials.Auth"
|
|
726
|
-
},
|
|
727
|
-
issuer: identityKey,
|
|
728
|
-
subject: identityKey,
|
|
729
|
-
signer
|
|
730
|
-
})
|
|
731
|
-
]);
|
|
732
|
-
};
|
|
733
|
-
var createStubEdgeIdentity = () => {
|
|
734
|
-
const identityKey = PublicKey.random();
|
|
735
|
-
const deviceKey = PublicKey.random();
|
|
736
|
-
return {
|
|
737
|
-
identityKey: identityKey.toHex(),
|
|
738
|
-
peerKey: deviceKey.toHex(),
|
|
739
|
-
presentCredentials: async () => {
|
|
740
|
-
throw new Error("Stub identity does not support authentication.");
|
|
741
|
-
}
|
|
742
|
-
};
|
|
743
|
-
};
|
|
744
|
-
|
|
745
688
|
// src/edge-http-client.ts
|
|
746
|
-
import
|
|
747
|
-
import
|
|
689
|
+
import * as FetchHttpClient from "@effect/platform/FetchHttpClient";
|
|
690
|
+
import * as HttpClient from "@effect/platform/HttpClient";
|
|
691
|
+
import * as Effect2 from "effect/Effect";
|
|
692
|
+
import * as Function from "effect/Function";
|
|
748
693
|
import { sleep } from "@dxos/async";
|
|
749
|
-
import {
|
|
694
|
+
import { TRACE_SPAN_ATTRIBUTE as TRACE_SPAN_ATTRIBUTE2 } from "@dxos/context";
|
|
695
|
+
import { runAndForwardErrors } from "@dxos/effect";
|
|
696
|
+
import { invariant as invariant4 } from "@dxos/invariant";
|
|
750
697
|
import { log as log4 } from "@dxos/log";
|
|
751
|
-
import { EdgeAuthChallengeError, EdgeCallFailedError } from "@dxos/protocols";
|
|
698
|
+
import { EDGE_CLIENT_TAG_HEADER, EdgeAuthChallengeError, EdgeCallFailedError } from "@dxos/protocols";
|
|
752
699
|
import { createUrl } from "@dxos/util";
|
|
753
700
|
|
|
754
701
|
// src/http-client.ts
|
|
755
|
-
import
|
|
702
|
+
import * as Context2 from "effect/Context";
|
|
703
|
+
import * as Duration from "effect/Duration";
|
|
704
|
+
import * as Effect from "effect/Effect";
|
|
705
|
+
import * as Layer from "effect/Layer";
|
|
706
|
+
import * as Schedule from "effect/Schedule";
|
|
756
707
|
import { log as log3 } from "@dxos/log";
|
|
757
708
|
var __dxlog_file5 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/http-client.ts";
|
|
758
709
|
var HttpConfig = class _HttpConfig extends Context2.Tag("HttpConfig")() {
|
|
759
|
-
static {
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
});
|
|
765
|
-
}
|
|
710
|
+
static default = Layer.succeed(_HttpConfig, {
|
|
711
|
+
timeout: Duration.millis(1e3),
|
|
712
|
+
retryTimes: 3,
|
|
713
|
+
retryBaseDelay: Duration.millis(1e3)
|
|
714
|
+
});
|
|
766
715
|
};
|
|
767
|
-
var withRetry = (effect, { timeout = Duration.millis(1e3), retryBaseDelay = Duration.millis(1e3), retryTimes = 3 } = {}) => {
|
|
716
|
+
var withRetry = (effect, { timeout: timeout2 = Duration.millis(1e3), retryBaseDelay = Duration.millis(1e3), retryTimes = 3 } = {}) => {
|
|
768
717
|
return effect.pipe(Effect.flatMap((res) => (
|
|
769
718
|
// Treat 500 errors as retryable?
|
|
770
719
|
res.status === 500 ? Effect.fail(new Error(res.status.toString())) : res.json
|
|
771
|
-
)), Effect.timeout(
|
|
720
|
+
)), Effect.timeout(timeout2), Effect.retry({
|
|
772
721
|
schedule: Schedule.exponential(retryBaseDelay).pipe(Schedule.jittered),
|
|
773
722
|
times: retryTimes
|
|
774
723
|
}));
|
|
@@ -777,14 +726,11 @@ var withRetryConfig = (effect) => Effect.gen(function* () {
|
|
|
777
726
|
const config = yield* HttpConfig;
|
|
778
727
|
return yield* withRetry(effect, config);
|
|
779
728
|
});
|
|
780
|
-
var withLogging = (effect) => effect.pipe(Effect.tap((res) =>
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
F: __dxlog_file5,
|
|
784
|
-
|
|
785
|
-
S: void 0,
|
|
786
|
-
C: (f, a) => f(...a)
|
|
787
|
-
})));
|
|
729
|
+
var withLogging = (effect) => effect.pipe(Effect.tap((res) => {
|
|
730
|
+
log3.info("response", {
|
|
731
|
+
status: res.status
|
|
732
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file5, L: 31, S: void 0 });
|
|
733
|
+
}));
|
|
788
734
|
var encodeAuthHeader = (challenge) => {
|
|
789
735
|
const encodedChallenge = Buffer.from(challenge).toString("base64");
|
|
790
736
|
return `VerifiablePresentation pb;base64,${encodedChallenge}`;
|
|
@@ -795,17 +741,21 @@ var __dxlog_file6 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/edge-http
|
|
|
795
741
|
var DEFAULT_RETRY_TIMEOUT = 1500;
|
|
796
742
|
var DEFAULT_RETRY_JITTER = 500;
|
|
797
743
|
var DEFAULT_MAX_RETRIES_COUNT = 3;
|
|
744
|
+
var WARNING_BODY_SIZE = 10 * 1024 * 1024;
|
|
798
745
|
var EdgeHttpClient = class {
|
|
799
|
-
|
|
746
|
+
_baseUrl;
|
|
747
|
+
_clientTag;
|
|
748
|
+
_edgeIdentity;
|
|
749
|
+
/**
|
|
750
|
+
* Auth header is cached until receiving the next 401 from EDGE, at which point it gets refreshed.
|
|
751
|
+
*/
|
|
752
|
+
_authHeader;
|
|
753
|
+
constructor(baseUrl, options) {
|
|
800
754
|
this._baseUrl = getEdgeUrlWithProtocol(baseUrl, "http");
|
|
755
|
+
this._clientTag = options?.clientTag;
|
|
801
756
|
log4("created", {
|
|
802
757
|
url: this._baseUrl
|
|
803
|
-
}, {
|
|
804
|
-
F: __dxlog_file6,
|
|
805
|
-
L: 84,
|
|
806
|
-
S: this,
|
|
807
|
-
C: (f, a) => f(...a)
|
|
808
|
-
});
|
|
758
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 32, S: this });
|
|
809
759
|
}
|
|
810
760
|
get baseUrl() {
|
|
811
761
|
return this._baseUrl;
|
|
@@ -819,24 +769,25 @@ var EdgeHttpClient = class {
|
|
|
819
769
|
//
|
|
820
770
|
// Status
|
|
821
771
|
//
|
|
822
|
-
async getStatus(args) {
|
|
823
|
-
return this._call(new URL("/status", this.baseUrl), {
|
|
772
|
+
async getStatus(ctx, args) {
|
|
773
|
+
return this._call(ctx, new URL("/status", this.baseUrl), {
|
|
824
774
|
...args,
|
|
825
|
-
method: "GET"
|
|
775
|
+
method: "GET",
|
|
776
|
+
auth: true
|
|
826
777
|
});
|
|
827
778
|
}
|
|
828
779
|
//
|
|
829
780
|
// Agents
|
|
830
781
|
//
|
|
831
|
-
createAgent(body, args) {
|
|
832
|
-
return this._call(new URL("/agents/create", this.baseUrl), {
|
|
782
|
+
createAgent(ctx, body, args) {
|
|
783
|
+
return this._call(ctx, new URL("/agents/create", this.baseUrl), {
|
|
833
784
|
...args,
|
|
834
785
|
method: "POST",
|
|
835
786
|
body
|
|
836
787
|
});
|
|
837
788
|
}
|
|
838
|
-
getAgentStatus(request, args) {
|
|
839
|
-
return this._call(new URL(`/users/${request.ownerIdentityKey.toHex()}/agent/status`, this.baseUrl), {
|
|
789
|
+
getAgentStatus(ctx, request, args) {
|
|
790
|
+
return this._call(ctx, new URL(`/users/${request.ownerIdentityKey.toHex()}/agent/status`, this.baseUrl), {
|
|
840
791
|
...args,
|
|
841
792
|
method: "GET"
|
|
842
793
|
});
|
|
@@ -844,14 +795,14 @@ var EdgeHttpClient = class {
|
|
|
844
795
|
//
|
|
845
796
|
// Credentials
|
|
846
797
|
//
|
|
847
|
-
getCredentialsForNotarization(spaceId, args) {
|
|
848
|
-
return this._call(new URL(`/spaces/${spaceId}/notarization`, this.baseUrl), {
|
|
798
|
+
getCredentialsForNotarization(ctx, spaceId, args) {
|
|
799
|
+
return this._call(ctx, new URL(`/spaces/${spaceId}/notarization`, this.baseUrl), {
|
|
849
800
|
...args,
|
|
850
801
|
method: "GET"
|
|
851
802
|
});
|
|
852
803
|
}
|
|
853
|
-
async notarizeCredentials(spaceId, body, args) {
|
|
854
|
-
await this._call(new URL(`/spaces/${spaceId}/notarization`, this.baseUrl), {
|
|
804
|
+
async notarizeCredentials(ctx, spaceId, body, args) {
|
|
805
|
+
await this._call(ctx, new URL(`/spaces/${spaceId}/notarization`, this.baseUrl), {
|
|
855
806
|
...args,
|
|
856
807
|
body,
|
|
857
808
|
method: "POST"
|
|
@@ -860,8 +811,8 @@ var EdgeHttpClient = class {
|
|
|
860
811
|
//
|
|
861
812
|
// Identity
|
|
862
813
|
//
|
|
863
|
-
async recoverIdentity(body, args) {
|
|
864
|
-
return this._call(new URL("/identity/recover", this.baseUrl), {
|
|
814
|
+
async recoverIdentity(ctx, body, args) {
|
|
815
|
+
return this._call(ctx, new URL("/identity/recover", this.baseUrl), {
|
|
865
816
|
...args,
|
|
866
817
|
body,
|
|
867
818
|
method: "POST"
|
|
@@ -870,8 +821,8 @@ var EdgeHttpClient = class {
|
|
|
870
821
|
//
|
|
871
822
|
// Invitations
|
|
872
823
|
//
|
|
873
|
-
async joinSpaceByInvitation(spaceId, body, args) {
|
|
874
|
-
return this._call(new URL(`/spaces/${spaceId}/join`, this.baseUrl), {
|
|
824
|
+
async joinSpaceByInvitation(ctx, spaceId, body, args) {
|
|
825
|
+
return this._call(ctx, new URL(`/spaces/${spaceId}/join`, this.baseUrl), {
|
|
875
826
|
...args,
|
|
876
827
|
body,
|
|
877
828
|
method: "POST"
|
|
@@ -880,14 +831,8 @@ var EdgeHttpClient = class {
|
|
|
880
831
|
//
|
|
881
832
|
// OAuth and credentials
|
|
882
833
|
//
|
|
883
|
-
async
|
|
884
|
-
return this._call(new URL("/
|
|
885
|
-
...args,
|
|
886
|
-
method: "GET"
|
|
887
|
-
});
|
|
888
|
-
}
|
|
889
|
-
async initiateOAuthFlow(body, args) {
|
|
890
|
-
return this._call(new URL("/oauth/initiate", this.baseUrl), {
|
|
834
|
+
async initiateOAuthFlow(ctx, body, args) {
|
|
835
|
+
return this._call(ctx, new URL("/oauth/initiate", this.baseUrl), {
|
|
891
836
|
...args,
|
|
892
837
|
body,
|
|
893
838
|
method: "POST"
|
|
@@ -896,8 +841,8 @@ var EdgeHttpClient = class {
|
|
|
896
841
|
//
|
|
897
842
|
// Spaces
|
|
898
843
|
//
|
|
899
|
-
async createSpace(body, args) {
|
|
900
|
-
return this._call(new URL("/spaces/create", this.baseUrl), {
|
|
844
|
+
async createSpace(ctx, body, args) {
|
|
845
|
+
return this._call(ctx, new URL("/spaces/create", this.baseUrl), {
|
|
901
846
|
...args,
|
|
902
847
|
body,
|
|
903
848
|
method: "POST"
|
|
@@ -906,9 +851,10 @@ var EdgeHttpClient = class {
|
|
|
906
851
|
//
|
|
907
852
|
// Queues
|
|
908
853
|
//
|
|
909
|
-
async queryQueue(subspaceTag, spaceId, query, args) {
|
|
910
|
-
const
|
|
911
|
-
|
|
854
|
+
async queryQueue(ctx, subspaceTag, spaceId, query, args) {
|
|
855
|
+
const queueId = query.queueIds?.[0];
|
|
856
|
+
invariant4(queueId, "queueId required", { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 132, S: this, A: ["queueId", "'queueId required'"] });
|
|
857
|
+
return this._call(ctx, createUrl(new URL(`/spaces/${subspaceTag}/${spaceId}/queue/${queueId}/query`, this.baseUrl), {
|
|
912
858
|
after: query.after,
|
|
913
859
|
before: query.before,
|
|
914
860
|
limit: query.limit,
|
|
@@ -919,8 +865,8 @@ var EdgeHttpClient = class {
|
|
|
919
865
|
method: "GET"
|
|
920
866
|
});
|
|
921
867
|
}
|
|
922
|
-
async insertIntoQueue(subspaceTag, spaceId, queueId, objects, args) {
|
|
923
|
-
return this._call(new URL(`/spaces/${subspaceTag}/${spaceId}/queue/${queueId}`, this.baseUrl), {
|
|
868
|
+
async insertIntoQueue(ctx, subspaceTag, spaceId, queueId, objects, args) {
|
|
869
|
+
return this._call(ctx, new URL(`/spaces/${subspaceTag}/${spaceId}/queue/${queueId}`, this.baseUrl), {
|
|
924
870
|
...args,
|
|
925
871
|
body: {
|
|
926
872
|
objects
|
|
@@ -928,8 +874,8 @@ var EdgeHttpClient = class {
|
|
|
928
874
|
method: "POST"
|
|
929
875
|
});
|
|
930
876
|
}
|
|
931
|
-
async deleteFromQueue(subspaceTag, spaceId, queueId, objectIds, args) {
|
|
932
|
-
return this._call(createUrl(new URL(`/spaces/${subspaceTag}/${spaceId}/queue/${queueId}`, this.baseUrl), {
|
|
877
|
+
async deleteFromQueue(ctx, subspaceTag, spaceId, queueId, objectIds, args) {
|
|
878
|
+
return this._call(ctx, createUrl(new URL(`/spaces/${subspaceTag}/${spaceId}/queue/${queueId}`, this.baseUrl), {
|
|
933
879
|
ids: objectIds.join(",")
|
|
934
880
|
}), {
|
|
935
881
|
...args,
|
|
@@ -939,98 +885,202 @@ var EdgeHttpClient = class {
|
|
|
939
885
|
//
|
|
940
886
|
// Functions
|
|
941
887
|
//
|
|
942
|
-
async uploadFunction(pathParts, body, args) {
|
|
888
|
+
async uploadFunction(ctx, pathParts, body, args) {
|
|
889
|
+
const formData = new FormData();
|
|
890
|
+
formData.append("name", body.name ?? "");
|
|
891
|
+
formData.append("version", body.version);
|
|
892
|
+
formData.append("ownerPublicKey", body.ownerPublicKey);
|
|
893
|
+
formData.append("entryPoint", body.entryPoint);
|
|
894
|
+
body.runtime && formData.append("runtime", body.runtime);
|
|
895
|
+
for (const [filename, content] of Object.entries(body.assets)) {
|
|
896
|
+
formData.append("assets", new Blob([
|
|
897
|
+
content
|
|
898
|
+
], {
|
|
899
|
+
type: getFileMimeType(filename)
|
|
900
|
+
}), filename);
|
|
901
|
+
}
|
|
943
902
|
const path = [
|
|
944
903
|
"functions",
|
|
945
904
|
...pathParts.functionId ? [
|
|
946
905
|
pathParts.functionId
|
|
947
906
|
] : []
|
|
948
907
|
].join("/");
|
|
949
|
-
return this._call(new URL(path, this.baseUrl), {
|
|
908
|
+
return this._call(ctx, new URL(path, this.baseUrl), {
|
|
950
909
|
...args,
|
|
951
|
-
body,
|
|
952
|
-
method: "PUT"
|
|
910
|
+
body: formData,
|
|
911
|
+
method: "PUT",
|
|
912
|
+
json: false
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
async listFunctions(ctx, args) {
|
|
916
|
+
return this._call(ctx, new URL("/functions", this.baseUrl), {
|
|
917
|
+
...args,
|
|
918
|
+
method: "GET"
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
async invokeFunction(ctx, params, input, args) {
|
|
922
|
+
const url = new URL(`/functions/${params.functionId}`, this.baseUrl);
|
|
923
|
+
if (params.version) {
|
|
924
|
+
url.searchParams.set("version", params.version);
|
|
925
|
+
}
|
|
926
|
+
if (params.spaceId) {
|
|
927
|
+
url.searchParams.set("spaceId", params.spaceId.toString());
|
|
928
|
+
}
|
|
929
|
+
if (params.cpuTimeLimit) {
|
|
930
|
+
url.searchParams.set("cpuTimeLimit", params.cpuTimeLimit.toString());
|
|
931
|
+
}
|
|
932
|
+
if (params.subrequestsLimit) {
|
|
933
|
+
url.searchParams.set("subrequestsLimit", params.subrequestsLimit.toString());
|
|
934
|
+
}
|
|
935
|
+
return this._call(ctx, url, {
|
|
936
|
+
...args,
|
|
937
|
+
body: input,
|
|
938
|
+
method: "POST"
|
|
953
939
|
});
|
|
954
940
|
}
|
|
955
941
|
//
|
|
956
942
|
// Workflows
|
|
957
943
|
//
|
|
958
|
-
async executeWorkflow(spaceId, graphId, input, args) {
|
|
959
|
-
return this._call(new URL(`/workflows/${spaceId}/${graphId}`, this.baseUrl), {
|
|
944
|
+
async executeWorkflow(ctx, spaceId, graphId, input, args) {
|
|
945
|
+
return this._call(ctx, new URL(`/workflows/${spaceId}/${graphId}`, this.baseUrl), {
|
|
960
946
|
...args,
|
|
961
947
|
body: input,
|
|
962
948
|
method: "POST"
|
|
963
949
|
});
|
|
964
950
|
}
|
|
965
951
|
//
|
|
952
|
+
// Triggers
|
|
953
|
+
//
|
|
954
|
+
async getCronTriggers(ctx, spaceId) {
|
|
955
|
+
return this._call(ctx, new URL(`/functions/${spaceId}/triggers/crons`, this.baseUrl), {
|
|
956
|
+
method: "GET"
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
async forceRunCronTrigger(ctx, spaceId, triggerId) {
|
|
960
|
+
return this._call(ctx, new URL(`/functions/${spaceId}/triggers/crons/${triggerId}/run`, this.baseUrl), {
|
|
961
|
+
method: "POST"
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
//
|
|
965
|
+
// Query
|
|
966
|
+
//
|
|
967
|
+
/**
|
|
968
|
+
* Execute a QueryAST query against a space.
|
|
969
|
+
*/
|
|
970
|
+
async execQuery(ctx, spaceId, body, args) {
|
|
971
|
+
return this._call(ctx, new URL(`/spaces/${spaceId}/exec-query`, this.baseUrl), {
|
|
972
|
+
...args,
|
|
973
|
+
body,
|
|
974
|
+
method: "POST"
|
|
975
|
+
});
|
|
976
|
+
}
|
|
977
|
+
//
|
|
978
|
+
// Registry
|
|
979
|
+
//
|
|
980
|
+
/**
|
|
981
|
+
* Fetches the hydrated plugin directory from the Edge registry service.
|
|
982
|
+
* Unauthenticated; safe to call without an identity.
|
|
983
|
+
*/
|
|
984
|
+
async getRegistryPlugins(ctx, args) {
|
|
985
|
+
return this._call(ctx, new URL("/registry/plugins", this.baseUrl), {
|
|
986
|
+
...args,
|
|
987
|
+
method: "GET"
|
|
988
|
+
});
|
|
989
|
+
}
|
|
990
|
+
/**
|
|
991
|
+
* Fetches the available release versions for a given plugin repo. `repo` is the
|
|
992
|
+
* GitHub `owner/name` form; this method takes care of URL-encoding before issuing
|
|
993
|
+
* the request. Unauthenticated; same surface area as {@link getRegistryPlugins}.
|
|
994
|
+
*
|
|
995
|
+
* Versions are returned newest first, suitable for direct rendering in a picker.
|
|
996
|
+
*/
|
|
997
|
+
async getRegistryPluginVersions(ctx, repo, args) {
|
|
998
|
+
return this._call(ctx, new URL(`/registry/plugins/${encodeURIComponent(repo)}/versions`, this.baseUrl), {
|
|
999
|
+
...args,
|
|
1000
|
+
method: "GET"
|
|
1001
|
+
});
|
|
1002
|
+
}
|
|
1003
|
+
//
|
|
1004
|
+
// Import/Export space.
|
|
1005
|
+
//
|
|
1006
|
+
async importBundle(ctx, spaceId, body, args) {
|
|
1007
|
+
return this._call(ctx, new URL(`/spaces/${spaceId}/import`, this.baseUrl), {
|
|
1008
|
+
...args,
|
|
1009
|
+
body,
|
|
1010
|
+
method: "PUT"
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
1013
|
+
async exportBundle(ctx, spaceId, body, args) {
|
|
1014
|
+
return this._call(ctx, new URL(`/spaces/${spaceId}/export`, this.baseUrl), {
|
|
1015
|
+
...args,
|
|
1016
|
+
body,
|
|
1017
|
+
method: "POST"
|
|
1018
|
+
});
|
|
1019
|
+
}
|
|
1020
|
+
//
|
|
966
1021
|
// Internal
|
|
967
1022
|
//
|
|
968
|
-
async _fetch(url,
|
|
969
|
-
return pipe(HttpClient.get(url), withLogging, withRetryConfig, Effect2.provide(FetchHttpClient.layer), Effect2.provide(HttpConfig.default), Effect2.withSpan("EdgeHttpClient"),
|
|
1023
|
+
async _fetch(url, _args) {
|
|
1024
|
+
return Function.pipe(HttpClient.get(url), withLogging, withRetryConfig, Effect2.provide(FetchHttpClient.layer), Effect2.provide(HttpConfig.default), Effect2.withSpan("EdgeHttpClient"), runAndForwardErrors);
|
|
970
1025
|
}
|
|
971
1026
|
// TODO(burdon): Refactor with effect (see edge-http-client.test.ts).
|
|
972
|
-
async _call(url, args) {
|
|
1027
|
+
async _call(ctx, url, args) {
|
|
973
1028
|
const shouldRetry = createRetryHandler(args);
|
|
974
|
-
const requestContext = args.context ?? new Context3(void 0, {
|
|
975
|
-
F: __dxlog_file6,
|
|
976
|
-
L: 293
|
|
977
|
-
});
|
|
978
1029
|
log4("fetch", {
|
|
979
1030
|
url,
|
|
980
1031
|
request: args.body
|
|
981
|
-
}, {
|
|
982
|
-
|
|
983
|
-
L: 294,
|
|
984
|
-
S: this,
|
|
985
|
-
C: (f, a) => f(...a)
|
|
986
|
-
});
|
|
1032
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 302, S: this });
|
|
1033
|
+
const traceHeaders = getTraceHeaders(ctx);
|
|
987
1034
|
let handledAuth = false;
|
|
1035
|
+
const tryCount = 1;
|
|
988
1036
|
while (true) {
|
|
989
|
-
let processingError;
|
|
990
|
-
let retryAfterHeaderValue = Number.NaN;
|
|
1037
|
+
let processingError = void 0;
|
|
991
1038
|
try {
|
|
992
|
-
|
|
1039
|
+
if (!this._authHeader && args.auth) {
|
|
1040
|
+
const response2 = await fetch(new URL(`/auth`, this.baseUrl));
|
|
1041
|
+
if (response2.status === 401) {
|
|
1042
|
+
this._authHeader = await this._handleUnauthorized(response2);
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
const request = createRequest(args, this._authHeader, traceHeaders, this._clientTag);
|
|
1046
|
+
log4("call edge", {
|
|
1047
|
+
url,
|
|
1048
|
+
tryCount,
|
|
1049
|
+
authHeader: !!this._authHeader
|
|
1050
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 319, S: this });
|
|
993
1051
|
const response = await fetch(url, request);
|
|
994
|
-
retryAfterHeaderValue = Number(response.headers.get("Retry-After"));
|
|
995
1052
|
if (response.ok) {
|
|
996
|
-
const
|
|
997
|
-
|
|
998
|
-
|
|
1053
|
+
const body2 = await response.clone().json();
|
|
1054
|
+
invariant4(body2, "Expected body to be present", { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 327, S: this, A: ["body", "'Expected body to be present'"] });
|
|
1055
|
+
if (!("success" in body2)) {
|
|
1056
|
+
return body2;
|
|
999
1057
|
}
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
body
|
|
1003
|
-
}, {
|
|
1004
|
-
F: __dxlog_file6,
|
|
1005
|
-
L: 310,
|
|
1006
|
-
S: this,
|
|
1007
|
-
C: (f, a) => f(...a)
|
|
1008
|
-
});
|
|
1009
|
-
if (body.errorData?.type === "auth_challenge" && typeof body.errorData?.challenge === "string") {
|
|
1010
|
-
processingError = new EdgeAuthChallengeError(body.errorData.challenge, body.errorData);
|
|
1011
|
-
} else {
|
|
1012
|
-
processingError = EdgeCallFailedError.fromUnsuccessfulResponse(response, body);
|
|
1058
|
+
if (body2.success) {
|
|
1059
|
+
return body2.data;
|
|
1013
1060
|
}
|
|
1014
1061
|
} else if (response.status === 401 && !handledAuth) {
|
|
1015
1062
|
this._authHeader = await this._handleUnauthorized(response);
|
|
1016
1063
|
handledAuth = true;
|
|
1017
1064
|
continue;
|
|
1065
|
+
}
|
|
1066
|
+
const body = response.headers.get("Content-Type") === "application/json" ? await response.clone().json() : void 0;
|
|
1067
|
+
invariant4(!body?.success, "Expected body to not be a failure response or undefined.", { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 340, S: this, A: ["!body?.success", "'Expected body to not be a failure response or undefined.'"] });
|
|
1068
|
+
if (body?.data?.type === "auth_challenge" && typeof body?.data?.challenge === "string") {
|
|
1069
|
+
processingError = new EdgeAuthChallengeError(body.data.challenge, body.data);
|
|
1070
|
+
} else if (body?.success === false) {
|
|
1071
|
+
processingError = EdgeCallFailedError.fromUnsuccessfulResponse(response, body);
|
|
1018
1072
|
} else {
|
|
1019
|
-
|
|
1073
|
+
invariant4(!response.ok, "Expected response to not be ok.", { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 346, S: this, A: ["!response.ok", "'Expected response to not be ok.'"] });
|
|
1074
|
+
processingError = await EdgeCallFailedError.fromHttpFailure(response);
|
|
1020
1075
|
}
|
|
1021
1076
|
} catch (error) {
|
|
1022
1077
|
processingError = EdgeCallFailedError.fromProcessingFailureCause(error);
|
|
1023
1078
|
}
|
|
1024
|
-
if (processingError
|
|
1025
|
-
log4("retrying edge request", {
|
|
1079
|
+
if (processingError?.isRetryable && await shouldRetry(ctx, processingError.retryAfterMs)) {
|
|
1080
|
+
log4.verbose("retrying edge request", {
|
|
1026
1081
|
url,
|
|
1027
1082
|
processingError
|
|
1028
|
-
}, {
|
|
1029
|
-
F: __dxlog_file6,
|
|
1030
|
-
L: 328,
|
|
1031
|
-
S: this,
|
|
1032
|
-
C: (f, a) => f(...a)
|
|
1033
|
-
});
|
|
1083
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 353, S: this });
|
|
1034
1084
|
} else {
|
|
1035
1085
|
throw processingError;
|
|
1036
1086
|
}
|
|
@@ -1038,35 +1088,63 @@ var EdgeHttpClient = class {
|
|
|
1038
1088
|
}
|
|
1039
1089
|
async _handleUnauthorized(response) {
|
|
1040
1090
|
if (!this._edgeIdentity) {
|
|
1041
|
-
log4.warn("unauthorized response received before identity was set", void 0, {
|
|
1042
|
-
|
|
1043
|
-
L: 337,
|
|
1044
|
-
S: this,
|
|
1045
|
-
C: (f, a) => f(...a)
|
|
1046
|
-
});
|
|
1047
|
-
throw EdgeCallFailedError.fromHttpFailure(response);
|
|
1091
|
+
log4.warn("unauthorized response received before identity was set", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 364, S: this });
|
|
1092
|
+
throw await EdgeCallFailedError.fromHttpFailure(response);
|
|
1048
1093
|
}
|
|
1049
1094
|
const challenge = await handleAuthChallenge(response, this._edgeIdentity);
|
|
1050
1095
|
return encodeAuthHeader(challenge);
|
|
1051
1096
|
}
|
|
1052
1097
|
};
|
|
1053
|
-
var createRequest = ({ method, body }, authHeader) => {
|
|
1098
|
+
var createRequest = ({ method, body, json = true }, authHeader, traceHeaders, clientTag) => {
|
|
1099
|
+
let requestBody;
|
|
1100
|
+
const headers = {};
|
|
1101
|
+
if (json) {
|
|
1102
|
+
requestBody = body && JSON.stringify(body);
|
|
1103
|
+
headers["Content-Type"] = "application/json";
|
|
1104
|
+
} else {
|
|
1105
|
+
requestBody = body;
|
|
1106
|
+
}
|
|
1107
|
+
if (typeof requestBody === "string" && requestBody.length > WARNING_BODY_SIZE) {
|
|
1108
|
+
log4.warn("Request with large body", {
|
|
1109
|
+
bodySize: requestBody.length
|
|
1110
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 381, S: void 0 });
|
|
1111
|
+
}
|
|
1112
|
+
if (authHeader) {
|
|
1113
|
+
headers["Authorization"] = authHeader;
|
|
1114
|
+
}
|
|
1115
|
+
if (traceHeaders) {
|
|
1116
|
+
Object.assign(headers, traceHeaders);
|
|
1117
|
+
}
|
|
1118
|
+
if (clientTag) {
|
|
1119
|
+
headers[EDGE_CLIENT_TAG_HEADER] = clientTag;
|
|
1120
|
+
}
|
|
1054
1121
|
return {
|
|
1055
1122
|
method,
|
|
1056
|
-
body:
|
|
1057
|
-
headers
|
|
1058
|
-
Authorization: authHeader
|
|
1059
|
-
} : void 0
|
|
1123
|
+
body: requestBody,
|
|
1124
|
+
headers
|
|
1060
1125
|
};
|
|
1061
1126
|
};
|
|
1062
|
-
var
|
|
1063
|
-
|
|
1127
|
+
var getTraceHeaders = (ctx) => {
|
|
1128
|
+
const traceCtx = ctx.getAttribute(TRACE_SPAN_ATTRIBUTE2);
|
|
1129
|
+
if (!traceCtx) {
|
|
1130
|
+
return void 0;
|
|
1131
|
+
}
|
|
1132
|
+
const headers = {
|
|
1133
|
+
traceparent: traceCtx.traceparent
|
|
1134
|
+
};
|
|
1135
|
+
if (traceCtx.tracestate) {
|
|
1136
|
+
headers.tracestate = traceCtx.tracestate;
|
|
1137
|
+
}
|
|
1138
|
+
return headers;
|
|
1139
|
+
};
|
|
1140
|
+
var createRetryHandler = ({ retry: retry2 }) => {
|
|
1141
|
+
if (!retry2 || retry2.count < 1) {
|
|
1064
1142
|
return async () => false;
|
|
1065
1143
|
}
|
|
1066
1144
|
let retries = 0;
|
|
1067
|
-
const maxRetries =
|
|
1068
|
-
const baseTimeout =
|
|
1069
|
-
const jitter =
|
|
1145
|
+
const maxRetries = retry2.count ?? DEFAULT_MAX_RETRIES_COUNT;
|
|
1146
|
+
const baseTimeout = retry2.timeout ?? DEFAULT_RETRY_TIMEOUT;
|
|
1147
|
+
const jitter = retry2.jitter ?? DEFAULT_RETRY_JITTER;
|
|
1070
1148
|
return async (ctx, retryAfter) => {
|
|
1071
1149
|
if (++retries > maxRetries || ctx.disposed) {
|
|
1072
1150
|
return false;
|
|
@@ -1074,12 +1152,16 @@ var createRetryHandler = ({ retry }) => {
|
|
|
1074
1152
|
if (retryAfter) {
|
|
1075
1153
|
await sleep(retryAfter);
|
|
1076
1154
|
} else {
|
|
1077
|
-
const
|
|
1078
|
-
await sleep(
|
|
1155
|
+
const timeout2 = baseTimeout + Math.random() * jitter;
|
|
1156
|
+
await sleep(timeout2);
|
|
1079
1157
|
}
|
|
1080
1158
|
return true;
|
|
1081
1159
|
};
|
|
1082
1160
|
};
|
|
1161
|
+
var getFileMimeType = (filename) => [
|
|
1162
|
+
".js",
|
|
1163
|
+
".mjs"
|
|
1164
|
+
].some((codeExtension) => filename.endsWith(codeExtension)) ? "application/javascript+module" : filename.endsWith(".wasm") ? "application/wasm" : "application/octet-stream";
|
|
1083
1165
|
export {
|
|
1084
1166
|
CLOUDFLARE_MESSAGE_MAX_BYTES,
|
|
1085
1167
|
CLOUDFLARE_RPC_MAX_BYTES,
|
|
@@ -1087,6 +1169,7 @@ export {
|
|
|
1087
1169
|
EdgeConnectionClosedError,
|
|
1088
1170
|
EdgeHttpClient,
|
|
1089
1171
|
EdgeIdentityChangedError,
|
|
1172
|
+
HttpConfig,
|
|
1090
1173
|
Protocol,
|
|
1091
1174
|
WebSocketMuxer,
|
|
1092
1175
|
createChainEdgeIdentity,
|
|
@@ -1094,9 +1177,13 @@ export {
|
|
|
1094
1177
|
createEphemeralEdgeIdentity,
|
|
1095
1178
|
createStubEdgeIdentity,
|
|
1096
1179
|
createTestHaloEdgeIdentity,
|
|
1180
|
+
encodeAuthHeader,
|
|
1097
1181
|
getTypename,
|
|
1098
1182
|
handleAuthChallenge,
|
|
1099
1183
|
protocol,
|
|
1100
|
-
toUint8Array
|
|
1184
|
+
toUint8Array,
|
|
1185
|
+
withLogging,
|
|
1186
|
+
withRetry,
|
|
1187
|
+
withRetryConfig
|
|
1101
1188
|
};
|
|
1102
1189
|
//# sourceMappingURL=index.mjs.map
|