@dxos/edge-client 0.8.4-main.f9ba587 → 0.8.4-main.fcc0d83b33
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-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 +570 -483
- 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 +72 -21
- 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 +21 -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 +31 -31
- 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 +336 -70
- package/src/edge-ws-connection.ts +131 -9
- package/src/edge-ws-muxer.ts +1 -1
- package/src/http-client.test.ts +11 -8
- 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 -1090
- 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,21 +141,40 @@ 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
179
|
super(), this._identity = _identity, this._connectionInfo = _connectionInfo, this._callbacks = _callbacks;
|
|
81
180
|
}
|
|
@@ -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: 52,
|
|
93
|
-
S: this,
|
|
94
|
-
A: [
|
|
95
|
-
"this._ws",
|
|
96
|
-
""
|
|
97
|
-
]
|
|
98
|
-
});
|
|
99
|
-
invariant2(this._wsMuxer, void 0, {
|
|
100
|
-
F: __dxlog_file2,
|
|
101
|
-
L: 53,
|
|
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: 54,
|
|
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: 58,
|
|
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: 84,
|
|
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: 88,
|
|
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: 93,
|
|
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,55 +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: 100,
|
|
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: 103,
|
|
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: 111,
|
|
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
|
}
|
|
289
|
+
this._lastReceivedMessageTimestamp = Date.now();
|
|
225
290
|
if (event.data === "__pong__") {
|
|
291
|
+
if (this._pingTimestamp) {
|
|
292
|
+
this._rtt = Date.now() - this._pingTimestamp;
|
|
293
|
+
this._pingTimestamp = void 0;
|
|
294
|
+
}
|
|
226
295
|
this._rescheduleHeartbeatTimeout();
|
|
227
296
|
return;
|
|
228
297
|
}
|
|
229
298
|
const bytes = await toUint8Array(event.data);
|
|
299
|
+
this._recordBytes(0, bytes.byteLength);
|
|
230
300
|
if (!this.isOpen) {
|
|
231
301
|
return;
|
|
232
302
|
}
|
|
303
|
+
this._messagesReceived++;
|
|
233
304
|
const message = this._ws?.protocol?.includes(EdgeWebsocketProtocol.V0) ? buf.fromBinary(MessageSchema, bytes) : muxer.receiveData(bytes);
|
|
234
305
|
if (message) {
|
|
235
306
|
log("received", {
|
|
236
307
|
from: message.source,
|
|
237
308
|
payload: protocol.getPayloadType(message)
|
|
238
|
-
}, {
|
|
239
|
-
F: __dxlog_file2,
|
|
240
|
-
L: 128,
|
|
241
|
-
S: this,
|
|
242
|
-
C: (f, a) => f(...a)
|
|
243
|
-
});
|
|
309
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 175, S: this });
|
|
244
310
|
this._callbacks.onMessage(message);
|
|
245
311
|
}
|
|
246
312
|
};
|
|
@@ -257,29 +323,18 @@ var EdgeWsConnection = class extends Resource {
|
|
|
257
323
|
if (err instanceof Error && err.message.includes("WebSocket is closed before the connection is established.")) {
|
|
258
324
|
return;
|
|
259
325
|
}
|
|
260
|
-
log.warn("
|
|
326
|
+
log.warn("error closing websocket", {
|
|
261
327
|
err
|
|
262
|
-
}, {
|
|
263
|
-
F: __dxlog_file2,
|
|
264
|
-
L: 146,
|
|
265
|
-
S: this,
|
|
266
|
-
C: (f, a) => f(...a)
|
|
267
|
-
});
|
|
328
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 194, S: this });
|
|
268
329
|
}
|
|
269
330
|
}
|
|
270
331
|
_scheduleHeartbeats() {
|
|
271
|
-
|
|
272
|
-
F: __dxlog_file2,
|
|
273
|
-
L: 151,
|
|
274
|
-
S: this,
|
|
275
|
-
A: [
|
|
276
|
-
"this._ws",
|
|
277
|
-
""
|
|
278
|
-
]
|
|
279
|
-
});
|
|
332
|
+
invariant3(this._ws, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 200, S: this, A: ["this._ws", ""] });
|
|
280
333
|
scheduleTaskInterval(this._ctx, async () => {
|
|
334
|
+
this._pingTimestamp = Date.now();
|
|
281
335
|
this._ws?.send("__ping__");
|
|
282
336
|
}, SIGNAL_KEEPALIVE_INTERVAL);
|
|
337
|
+
this._pingTimestamp = Date.now();
|
|
283
338
|
this._ws.send("__ping__");
|
|
284
339
|
this._rescheduleHeartbeatTimeout();
|
|
285
340
|
}
|
|
@@ -288,22 +343,61 @@ var EdgeWsConnection = class extends Resource {
|
|
|
288
343
|
return;
|
|
289
344
|
}
|
|
290
345
|
void this._inactivityTimeoutCtx?.dispose();
|
|
291
|
-
this._inactivityTimeoutCtx = new Context(void 0, {
|
|
292
|
-
F: __dxlog_file2,
|
|
293
|
-
L: 170
|
|
294
|
-
});
|
|
346
|
+
this._inactivityTimeoutCtx = new Context(void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 216 });
|
|
295
347
|
scheduleTask(this._inactivityTimeoutCtx, () => {
|
|
296
348
|
if (this.isOpen) {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
S: this
|
|
301
|
-
|
|
302
|
-
}
|
|
303
|
-
|
|
349
|
+
if (Date.now() - this._lastReceivedMessageTimestamp > SIGNAL_KEEPALIVE_TIMEOUT) {
|
|
350
|
+
log.warn("restart due to inactivity timeout", {
|
|
351
|
+
lastReceivedMessageTimestamp: this._lastReceivedMessageTimestamp
|
|
352
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 220, S: this });
|
|
353
|
+
this._callbacks.onRestartRequired();
|
|
354
|
+
} else {
|
|
355
|
+
this._rescheduleHeartbeatTimeout();
|
|
356
|
+
}
|
|
304
357
|
}
|
|
305
358
|
}, SIGNAL_KEEPALIVE_TIMEOUT);
|
|
306
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
|
+
}
|
|
307
401
|
};
|
|
308
402
|
_ts_decorate([
|
|
309
403
|
logInfo
|
|
@@ -330,20 +424,31 @@ var getEdgeUrlWithProtocol = (baseUrl, protocol2) => {
|
|
|
330
424
|
};
|
|
331
425
|
|
|
332
426
|
// src/edge-client.ts
|
|
427
|
+
var __dxlog_file4 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/edge-client.ts";
|
|
333
428
|
function _ts_decorate2(decorators, target, key, desc) {
|
|
334
429
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
335
430
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
336
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;
|
|
337
432
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
338
433
|
}
|
|
339
|
-
var __dxlog_file3 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/edge-client.ts";
|
|
340
434
|
var DEFAULT_TIMEOUT = 1e4;
|
|
435
|
+
var STATUS_REFRESH_INTERVAL = 1e3;
|
|
341
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();
|
|
342
450
|
constructor(_identity, _config) {
|
|
343
|
-
super(), this._identity = _identity, this._config = _config
|
|
344
|
-
start: async () => this._connect(),
|
|
345
|
-
stop: async (state) => this._disconnect(state)
|
|
346
|
-
}), 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;
|
|
347
452
|
this._baseWsUrl = getEdgeUrlWithProtocol(_config.socketEndpoint, "ws");
|
|
348
453
|
this._baseHttpUrl = getEdgeUrlWithProtocol(_config.socketEndpoint, "http");
|
|
349
454
|
}
|
|
@@ -356,7 +461,15 @@ var EdgeClient = class extends Resource2 {
|
|
|
356
461
|
};
|
|
357
462
|
}
|
|
358
463
|
get status() {
|
|
359
|
-
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
|
+
};
|
|
360
473
|
}
|
|
361
474
|
get identityKey() {
|
|
362
475
|
return this._identity.identityKey;
|
|
@@ -369,17 +482,39 @@ var EdgeClient = class extends Resource2 {
|
|
|
369
482
|
log2("Edge identity changed", {
|
|
370
483
|
identity,
|
|
371
484
|
oldIdentity: this._identity
|
|
372
|
-
}, {
|
|
373
|
-
F: __dxlog_file3,
|
|
374
|
-
L: 99,
|
|
375
|
-
S: this,
|
|
376
|
-
C: (f, a) => f(...a)
|
|
377
|
-
});
|
|
485
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 74, S: this });
|
|
378
486
|
this._identity = identity;
|
|
379
487
|
this._closeCurrentConnection(new EdgeIdentityChangedError());
|
|
380
488
|
void this._persistentLifecycle.scheduleRestart();
|
|
381
489
|
}
|
|
382
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
|
+
}
|
|
383
518
|
onMessage(listener) {
|
|
384
519
|
this._messageListeners.add(listener);
|
|
385
520
|
return () => this._messageListeners.delete(listener);
|
|
@@ -392,12 +527,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
392
527
|
try {
|
|
393
528
|
listener();
|
|
394
529
|
} catch (error) {
|
|
395
|
-
log2.catch(error, void 0, {
|
|
396
|
-
F: __dxlog_file3,
|
|
397
|
-
L: 121,
|
|
398
|
-
S: this,
|
|
399
|
-
C: (f, a) => f(...a)
|
|
400
|
-
});
|
|
530
|
+
log2.catch(error, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 123, S: this });
|
|
401
531
|
}
|
|
402
532
|
}
|
|
403
533
|
});
|
|
@@ -410,22 +540,18 @@ var EdgeClient = class extends Resource2 {
|
|
|
410
540
|
async _open() {
|
|
411
541
|
log2("opening...", {
|
|
412
542
|
info: this.info
|
|
413
|
-
}, {
|
|
414
|
-
F: __dxlog_file3,
|
|
415
|
-
L: 133,
|
|
416
|
-
S: this,
|
|
417
|
-
C: (f, a) => f(...a)
|
|
418
|
-
});
|
|
543
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 133, S: this });
|
|
419
544
|
this._persistentLifecycle.open().catch((err) => {
|
|
420
545
|
log2.warn("Error while opening connection", {
|
|
421
546
|
err
|
|
422
|
-
}, {
|
|
423
|
-
F: __dxlog_file3,
|
|
424
|
-
L: 135,
|
|
425
|
-
S: this,
|
|
426
|
-
C: (f, a) => f(...a)
|
|
427
|
-
});
|
|
547
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 137, S: this });
|
|
428
548
|
});
|
|
549
|
+
scheduleTaskInterval2(this._ctx, async () => {
|
|
550
|
+
if (!this._currentConnection) {
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
this.statusChanged.emit(this.status);
|
|
554
|
+
}, STATUS_REFRESH_INTERVAL);
|
|
429
555
|
}
|
|
430
556
|
/**
|
|
431
557
|
* Close connection and free resources.
|
|
@@ -433,12 +559,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
433
559
|
async _close() {
|
|
434
560
|
log2("closing...", {
|
|
435
561
|
peerKey: this._identity.peerKey
|
|
436
|
-
}, {
|
|
437
|
-
F: __dxlog_file3,
|
|
438
|
-
L: 143,
|
|
439
|
-
S: this,
|
|
440
|
-
C: (f, a) => f(...a)
|
|
441
|
-
});
|
|
562
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 152, S: this });
|
|
442
563
|
this._closeCurrentConnection();
|
|
443
564
|
await this._persistentLifecycle.close();
|
|
444
565
|
}
|
|
@@ -450,12 +571,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
450
571
|
const path = `/ws/${identity.identityKey}/${identity.peerKey}`;
|
|
451
572
|
const protocolHeader = this._config.disableAuth ? void 0 : await this._createAuthHeader(path);
|
|
452
573
|
if (this._identity !== identity) {
|
|
453
|
-
log2("identity changed during auth header request", void 0, {
|
|
454
|
-
F: __dxlog_file3,
|
|
455
|
-
L: 157,
|
|
456
|
-
S: this,
|
|
457
|
-
C: (f, a) => f(...a)
|
|
458
|
-
});
|
|
574
|
+
log2("identity changed during auth header request", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 166, S: this });
|
|
459
575
|
return void 0;
|
|
460
576
|
}
|
|
461
577
|
const restartRequired = new Trigger();
|
|
@@ -463,27 +579,20 @@ var EdgeClient = class extends Resource2 {
|
|
|
463
579
|
log2("Opening websocket", {
|
|
464
580
|
url: url.toString(),
|
|
465
581
|
protocolHeader
|
|
466
|
-
}, {
|
|
467
|
-
F: __dxlog_file3,
|
|
468
|
-
L: 163,
|
|
469
|
-
S: this,
|
|
470
|
-
C: (f, a) => f(...a)
|
|
471
|
-
});
|
|
582
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 171, S: this });
|
|
472
583
|
const connection = new EdgeWsConnection(identity, {
|
|
473
584
|
url,
|
|
474
|
-
protocolHeader
|
|
585
|
+
protocolHeader,
|
|
586
|
+
headers: this._config.clientTag ? {
|
|
587
|
+
"X-DXOS-Client-Tag": this._config.clientTag
|
|
588
|
+
} : void 0
|
|
475
589
|
}, {
|
|
476
590
|
onConnected: () => {
|
|
477
591
|
if (this._isActive(connection)) {
|
|
478
592
|
this._ready.wake();
|
|
479
593
|
this._notifyReconnected();
|
|
480
594
|
} else {
|
|
481
|
-
log2.verbose("connected callback ignored, because connection is not active", void 0, {
|
|
482
|
-
F: __dxlog_file3,
|
|
483
|
-
L: 173,
|
|
484
|
-
S: this,
|
|
485
|
-
C: (f, a) => f(...a)
|
|
486
|
-
});
|
|
595
|
+
log2.verbose("connected callback ignored, because connection is not active", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 187, S: this });
|
|
487
596
|
}
|
|
488
597
|
},
|
|
489
598
|
onRestartRequired: () => {
|
|
@@ -491,12 +600,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
491
600
|
this._closeCurrentConnection();
|
|
492
601
|
void this._persistentLifecycle.scheduleRestart();
|
|
493
602
|
} else {
|
|
494
|
-
log2.verbose("restart requested by inactive connection", void 0, {
|
|
495
|
-
F: __dxlog_file3,
|
|
496
|
-
L: 181,
|
|
497
|
-
S: this,
|
|
498
|
-
C: (f, a) => f(...a)
|
|
499
|
-
});
|
|
603
|
+
log2.verbose("restart requested by inactive connection", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 195, S: this });
|
|
500
604
|
}
|
|
501
605
|
restartRequired.wake();
|
|
502
606
|
},
|
|
@@ -507,12 +611,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
507
611
|
log2.verbose("ignored a message on inactive connection", {
|
|
508
612
|
from: message.source,
|
|
509
613
|
type: message.payload?.typeUrl
|
|
510
|
-
}, {
|
|
511
|
-
F: __dxlog_file3,
|
|
512
|
-
L: 189,
|
|
513
|
-
S: this,
|
|
514
|
-
C: (f, a) => f(...a)
|
|
515
|
-
});
|
|
614
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 203, S: this });
|
|
516
615
|
}
|
|
517
616
|
}
|
|
518
617
|
});
|
|
@@ -544,12 +643,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
544
643
|
} catch (err) {
|
|
545
644
|
log2.error("ws reconnect listener failed", {
|
|
546
645
|
err
|
|
547
|
-
}, {
|
|
548
|
-
F: __dxlog_file3,
|
|
549
|
-
L: 225,
|
|
550
|
-
S: this,
|
|
551
|
-
C: (f, a) => f(...a)
|
|
552
|
-
});
|
|
646
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 238, S: this });
|
|
553
647
|
}
|
|
554
648
|
}
|
|
555
649
|
}
|
|
@@ -561,39 +655,10 @@ var EdgeClient = class extends Resource2 {
|
|
|
561
655
|
log2.error("ws incoming message processing failed", {
|
|
562
656
|
err,
|
|
563
657
|
payload: protocol.getPayloadType(message)
|
|
564
|
-
}, {
|
|
565
|
-
F: __dxlog_file3,
|
|
566
|
-
L: 235,
|
|
567
|
-
S: this,
|
|
568
|
-
C: (f, a) => f(...a)
|
|
569
|
-
});
|
|
658
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 249, S: this });
|
|
570
659
|
}
|
|
571
660
|
}
|
|
572
661
|
}
|
|
573
|
-
/**
|
|
574
|
-
* Send message.
|
|
575
|
-
* NOTE: The message is guaranteed to be delivered but the service must respond with a message to confirm processing.
|
|
576
|
-
*/
|
|
577
|
-
async send(message) {
|
|
578
|
-
if (this._ready.state !== TriggerState.RESOLVED) {
|
|
579
|
-
log2("waiting for websocket to become ready", void 0, {
|
|
580
|
-
F: __dxlog_file3,
|
|
581
|
-
L: 246,
|
|
582
|
-
S: this,
|
|
583
|
-
C: (f, a) => f(...a)
|
|
584
|
-
});
|
|
585
|
-
await this._ready.wait({
|
|
586
|
-
timeout: this._config.timeout ?? DEFAULT_TIMEOUT
|
|
587
|
-
});
|
|
588
|
-
}
|
|
589
|
-
if (!this._currentConnection) {
|
|
590
|
-
throw new EdgeConnectionClosedError();
|
|
591
|
-
}
|
|
592
|
-
if (message.source && (message.source.peerKey !== this._identity.peerKey || message.source.identityKey !== this.identityKey)) {
|
|
593
|
-
throw new EdgeIdentityChangedError();
|
|
594
|
-
}
|
|
595
|
-
this._currentConnection.send(message);
|
|
596
|
-
}
|
|
597
662
|
async _createAuthHeader(path) {
|
|
598
663
|
const httpUrl = new URL(path, this._baseHttpUrl);
|
|
599
664
|
httpUrl.protocol = getEdgeUrlWithProtocol(this._baseWsUrl.toString(), "http");
|
|
@@ -606,15 +671,11 @@ var EdgeClient = class extends Resource2 {
|
|
|
606
671
|
log2.warn("no auth challenge from edge", {
|
|
607
672
|
status: response.status,
|
|
608
673
|
statusText: response.statusText
|
|
609
|
-
}, {
|
|
610
|
-
F: __dxlog_file3,
|
|
611
|
-
L: 271,
|
|
612
|
-
S: this,
|
|
613
|
-
C: (f, a) => f(...a)
|
|
614
|
-
});
|
|
674
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 265, S: this });
|
|
615
675
|
return void 0;
|
|
616
676
|
}
|
|
617
677
|
}
|
|
678
|
+
_isActive = (connection) => connection === this._currentConnection;
|
|
618
679
|
};
|
|
619
680
|
_ts_decorate2([
|
|
620
681
|
logInfo2
|
|
@@ -624,144 +685,39 @@ var encodePresentationWsAuthHeader = (encodedPresentation) => {
|
|
|
624
685
|
return `base64url.bearer.authorization.dxos.org.${encodedToken}`;
|
|
625
686
|
};
|
|
626
687
|
|
|
627
|
-
// src/auth.ts
|
|
628
|
-
import { createCredential, signPresentation } from "@dxos/credentials";
|
|
629
|
-
import { invariant as invariant3 } from "@dxos/invariant";
|
|
630
|
-
import { Keyring } from "@dxos/keyring";
|
|
631
|
-
import { PublicKey } from "@dxos/keys";
|
|
632
|
-
var __dxlog_file4 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/auth.ts";
|
|
633
|
-
var createDeviceEdgeIdentity = async (signer, key) => {
|
|
634
|
-
return {
|
|
635
|
-
identityKey: key.toHex(),
|
|
636
|
-
peerKey: key.toHex(),
|
|
637
|
-
presentCredentials: async ({ challenge }) => {
|
|
638
|
-
return signPresentation({
|
|
639
|
-
presentation: {
|
|
640
|
-
credentials: [
|
|
641
|
-
// Verifier requires at least one credential in the presentation to establish the subject.
|
|
642
|
-
await createCredential({
|
|
643
|
-
assertion: {
|
|
644
|
-
"@type": "dxos.halo.credentials.Auth"
|
|
645
|
-
},
|
|
646
|
-
issuer: key,
|
|
647
|
-
subject: key,
|
|
648
|
-
signer
|
|
649
|
-
})
|
|
650
|
-
]
|
|
651
|
-
},
|
|
652
|
-
signer,
|
|
653
|
-
signerKey: key,
|
|
654
|
-
nonce: challenge
|
|
655
|
-
});
|
|
656
|
-
}
|
|
657
|
-
};
|
|
658
|
-
};
|
|
659
|
-
var createChainEdgeIdentity = async (signer, identityKey, peerKey, chain, credentials) => {
|
|
660
|
-
const credentialsToSign = credentials.length > 0 ? credentials : [
|
|
661
|
-
await createCredential({
|
|
662
|
-
assertion: {
|
|
663
|
-
"@type": "dxos.halo.credentials.Auth"
|
|
664
|
-
},
|
|
665
|
-
issuer: identityKey,
|
|
666
|
-
subject: identityKey,
|
|
667
|
-
signer,
|
|
668
|
-
chain,
|
|
669
|
-
signingKey: peerKey
|
|
670
|
-
})
|
|
671
|
-
];
|
|
672
|
-
return {
|
|
673
|
-
identityKey: identityKey.toHex(),
|
|
674
|
-
peerKey: peerKey.toHex(),
|
|
675
|
-
presentCredentials: async ({ challenge }) => {
|
|
676
|
-
invariant3(chain, void 0, {
|
|
677
|
-
F: __dxlog_file4,
|
|
678
|
-
L: 75,
|
|
679
|
-
S: void 0,
|
|
680
|
-
A: [
|
|
681
|
-
"chain",
|
|
682
|
-
""
|
|
683
|
-
]
|
|
684
|
-
});
|
|
685
|
-
return signPresentation({
|
|
686
|
-
presentation: {
|
|
687
|
-
credentials: credentialsToSign
|
|
688
|
-
},
|
|
689
|
-
signer,
|
|
690
|
-
nonce: challenge,
|
|
691
|
-
signerKey: peerKey,
|
|
692
|
-
chain
|
|
693
|
-
});
|
|
694
|
-
}
|
|
695
|
-
};
|
|
696
|
-
};
|
|
697
|
-
var createEphemeralEdgeIdentity = async () => {
|
|
698
|
-
const keyring = new Keyring();
|
|
699
|
-
const key = await keyring.createKey();
|
|
700
|
-
return createDeviceEdgeIdentity(keyring, key);
|
|
701
|
-
};
|
|
702
|
-
var createTestHaloEdgeIdentity = async (signer, identityKey, deviceKey) => {
|
|
703
|
-
const deviceAdmission = await createCredential({
|
|
704
|
-
assertion: {
|
|
705
|
-
"@type": "dxos.halo.credentials.AuthorizedDevice",
|
|
706
|
-
deviceKey,
|
|
707
|
-
identityKey
|
|
708
|
-
},
|
|
709
|
-
issuer: identityKey,
|
|
710
|
-
subject: deviceKey,
|
|
711
|
-
signer
|
|
712
|
-
});
|
|
713
|
-
return createChainEdgeIdentity(signer, identityKey, deviceKey, {
|
|
714
|
-
credential: deviceAdmission
|
|
715
|
-
}, [
|
|
716
|
-
await createCredential({
|
|
717
|
-
assertion: {
|
|
718
|
-
"@type": "dxos.halo.credentials.Auth"
|
|
719
|
-
},
|
|
720
|
-
issuer: identityKey,
|
|
721
|
-
subject: identityKey,
|
|
722
|
-
signer
|
|
723
|
-
})
|
|
724
|
-
]);
|
|
725
|
-
};
|
|
726
|
-
var createStubEdgeIdentity = () => {
|
|
727
|
-
const identityKey = PublicKey.random();
|
|
728
|
-
const deviceKey = PublicKey.random();
|
|
729
|
-
return {
|
|
730
|
-
identityKey: identityKey.toHex(),
|
|
731
|
-
peerKey: deviceKey.toHex(),
|
|
732
|
-
presentCredentials: async () => {
|
|
733
|
-
throw new Error("Stub identity does not support authentication.");
|
|
734
|
-
}
|
|
735
|
-
};
|
|
736
|
-
};
|
|
737
|
-
|
|
738
688
|
// src/edge-http-client.ts
|
|
739
|
-
import
|
|
740
|
-
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";
|
|
741
693
|
import { sleep } from "@dxos/async";
|
|
742
|
-
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";
|
|
743
697
|
import { log as log4 } from "@dxos/log";
|
|
744
|
-
import { EdgeAuthChallengeError, EdgeCallFailedError } from "@dxos/protocols";
|
|
698
|
+
import { EDGE_CLIENT_TAG_HEADER, EdgeAuthChallengeError, EdgeCallFailedError } from "@dxos/protocols";
|
|
745
699
|
import { createUrl } from "@dxos/util";
|
|
746
700
|
|
|
747
701
|
// src/http-client.ts
|
|
748
|
-
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";
|
|
749
707
|
import { log as log3 } from "@dxos/log";
|
|
750
708
|
var __dxlog_file5 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/http-client.ts";
|
|
751
709
|
var HttpConfig = class _HttpConfig extends Context2.Tag("HttpConfig")() {
|
|
752
|
-
static {
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
});
|
|
758
|
-
}
|
|
710
|
+
static default = Layer.succeed(_HttpConfig, {
|
|
711
|
+
timeout: Duration.millis(1e3),
|
|
712
|
+
retryTimes: 3,
|
|
713
|
+
retryBaseDelay: Duration.millis(1e3)
|
|
714
|
+
});
|
|
759
715
|
};
|
|
760
|
-
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 } = {}) => {
|
|
761
717
|
return effect.pipe(Effect.flatMap((res) => (
|
|
762
718
|
// Treat 500 errors as retryable?
|
|
763
719
|
res.status === 500 ? Effect.fail(new Error(res.status.toString())) : res.json
|
|
764
|
-
)), Effect.timeout(
|
|
720
|
+
)), Effect.timeout(timeout2), Effect.retry({
|
|
765
721
|
schedule: Schedule.exponential(retryBaseDelay).pipe(Schedule.jittered),
|
|
766
722
|
times: retryTimes
|
|
767
723
|
}));
|
|
@@ -770,14 +726,11 @@ var withRetryConfig = (effect) => Effect.gen(function* () {
|
|
|
770
726
|
const config = yield* HttpConfig;
|
|
771
727
|
return yield* withRetry(effect, config);
|
|
772
728
|
});
|
|
773
|
-
var withLogging = (effect) => effect.pipe(Effect.tap((res) =>
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
F: __dxlog_file5,
|
|
777
|
-
|
|
778
|
-
S: void 0,
|
|
779
|
-
C: (f, a) => f(...a)
|
|
780
|
-
})));
|
|
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
|
+
}));
|
|
781
734
|
var encodeAuthHeader = (challenge) => {
|
|
782
735
|
const encodedChallenge = Buffer.from(challenge).toString("base64");
|
|
783
736
|
return `VerifiablePresentation pb;base64,${encodedChallenge}`;
|
|
@@ -788,17 +741,21 @@ var __dxlog_file6 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/edge-http
|
|
|
788
741
|
var DEFAULT_RETRY_TIMEOUT = 1500;
|
|
789
742
|
var DEFAULT_RETRY_JITTER = 500;
|
|
790
743
|
var DEFAULT_MAX_RETRIES_COUNT = 3;
|
|
744
|
+
var WARNING_BODY_SIZE = 10 * 1024 * 1024;
|
|
791
745
|
var EdgeHttpClient = class {
|
|
792
|
-
|
|
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) {
|
|
793
754
|
this._baseUrl = getEdgeUrlWithProtocol(baseUrl, "http");
|
|
755
|
+
this._clientTag = options?.clientTag;
|
|
794
756
|
log4("created", {
|
|
795
757
|
url: this._baseUrl
|
|
796
|
-
}, {
|
|
797
|
-
F: __dxlog_file6,
|
|
798
|
-
L: 84,
|
|
799
|
-
S: this,
|
|
800
|
-
C: (f, a) => f(...a)
|
|
801
|
-
});
|
|
758
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 32, S: this });
|
|
802
759
|
}
|
|
803
760
|
get baseUrl() {
|
|
804
761
|
return this._baseUrl;
|
|
@@ -812,24 +769,25 @@ var EdgeHttpClient = class {
|
|
|
812
769
|
//
|
|
813
770
|
// Status
|
|
814
771
|
//
|
|
815
|
-
async getStatus(args) {
|
|
816
|
-
return this._call(new URL("/status", this.baseUrl), {
|
|
772
|
+
async getStatus(ctx, args) {
|
|
773
|
+
return this._call(ctx, new URL("/status", this.baseUrl), {
|
|
817
774
|
...args,
|
|
818
|
-
method: "GET"
|
|
775
|
+
method: "GET",
|
|
776
|
+
auth: true
|
|
819
777
|
});
|
|
820
778
|
}
|
|
821
779
|
//
|
|
822
780
|
// Agents
|
|
823
781
|
//
|
|
824
|
-
createAgent(body, args) {
|
|
825
|
-
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), {
|
|
826
784
|
...args,
|
|
827
785
|
method: "POST",
|
|
828
786
|
body
|
|
829
787
|
});
|
|
830
788
|
}
|
|
831
|
-
getAgentStatus(request, args) {
|
|
832
|
-
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), {
|
|
833
791
|
...args,
|
|
834
792
|
method: "GET"
|
|
835
793
|
});
|
|
@@ -837,14 +795,14 @@ var EdgeHttpClient = class {
|
|
|
837
795
|
//
|
|
838
796
|
// Credentials
|
|
839
797
|
//
|
|
840
|
-
getCredentialsForNotarization(spaceId, args) {
|
|
841
|
-
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), {
|
|
842
800
|
...args,
|
|
843
801
|
method: "GET"
|
|
844
802
|
});
|
|
845
803
|
}
|
|
846
|
-
async notarizeCredentials(spaceId, body, args) {
|
|
847
|
-
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), {
|
|
848
806
|
...args,
|
|
849
807
|
body,
|
|
850
808
|
method: "POST"
|
|
@@ -853,8 +811,8 @@ var EdgeHttpClient = class {
|
|
|
853
811
|
//
|
|
854
812
|
// Identity
|
|
855
813
|
//
|
|
856
|
-
async recoverIdentity(body, args) {
|
|
857
|
-
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), {
|
|
858
816
|
...args,
|
|
859
817
|
body,
|
|
860
818
|
method: "POST"
|
|
@@ -863,8 +821,8 @@ var EdgeHttpClient = class {
|
|
|
863
821
|
//
|
|
864
822
|
// Invitations
|
|
865
823
|
//
|
|
866
|
-
async joinSpaceByInvitation(spaceId, body, args) {
|
|
867
|
-
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), {
|
|
868
826
|
...args,
|
|
869
827
|
body,
|
|
870
828
|
method: "POST"
|
|
@@ -873,8 +831,8 @@ var EdgeHttpClient = class {
|
|
|
873
831
|
//
|
|
874
832
|
// OAuth and credentials
|
|
875
833
|
//
|
|
876
|
-
async initiateOAuthFlow(body, args) {
|
|
877
|
-
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), {
|
|
878
836
|
...args,
|
|
879
837
|
body,
|
|
880
838
|
method: "POST"
|
|
@@ -883,8 +841,8 @@ var EdgeHttpClient = class {
|
|
|
883
841
|
//
|
|
884
842
|
// Spaces
|
|
885
843
|
//
|
|
886
|
-
async createSpace(body, args) {
|
|
887
|
-
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), {
|
|
888
846
|
...args,
|
|
889
847
|
body,
|
|
890
848
|
method: "POST"
|
|
@@ -893,9 +851,10 @@ var EdgeHttpClient = class {
|
|
|
893
851
|
//
|
|
894
852
|
// Queues
|
|
895
853
|
//
|
|
896
|
-
async queryQueue(subspaceTag, spaceId, query, args) {
|
|
897
|
-
const
|
|
898
|
-
|
|
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), {
|
|
899
858
|
after: query.after,
|
|
900
859
|
before: query.before,
|
|
901
860
|
limit: query.limit,
|
|
@@ -906,8 +865,8 @@ var EdgeHttpClient = class {
|
|
|
906
865
|
method: "GET"
|
|
907
866
|
});
|
|
908
867
|
}
|
|
909
|
-
async insertIntoQueue(subspaceTag, spaceId, queueId, objects, args) {
|
|
910
|
-
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), {
|
|
911
870
|
...args,
|
|
912
871
|
body: {
|
|
913
872
|
objects
|
|
@@ -915,8 +874,8 @@ var EdgeHttpClient = class {
|
|
|
915
874
|
method: "POST"
|
|
916
875
|
});
|
|
917
876
|
}
|
|
918
|
-
async deleteFromQueue(subspaceTag, spaceId, queueId, objectIds, args) {
|
|
919
|
-
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), {
|
|
920
879
|
ids: objectIds.join(",")
|
|
921
880
|
}), {
|
|
922
881
|
...args,
|
|
@@ -926,98 +885,189 @@ var EdgeHttpClient = class {
|
|
|
926
885
|
//
|
|
927
886
|
// Functions
|
|
928
887
|
//
|
|
929
|
-
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
|
+
}
|
|
930
902
|
const path = [
|
|
931
903
|
"functions",
|
|
932
904
|
...pathParts.functionId ? [
|
|
933
905
|
pathParts.functionId
|
|
934
906
|
] : []
|
|
935
907
|
].join("/");
|
|
936
|
-
return this._call(new URL(path, this.baseUrl), {
|
|
908
|
+
return this._call(ctx, new URL(path, this.baseUrl), {
|
|
937
909
|
...args,
|
|
938
|
-
body,
|
|
939
|
-
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"
|
|
940
939
|
});
|
|
941
940
|
}
|
|
942
941
|
//
|
|
943
942
|
// Workflows
|
|
944
943
|
//
|
|
945
|
-
async executeWorkflow(spaceId, graphId, input, args) {
|
|
946
|
-
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), {
|
|
947
946
|
...args,
|
|
948
947
|
body: input,
|
|
949
948
|
method: "POST"
|
|
950
949
|
});
|
|
951
950
|
}
|
|
952
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
|
+
// Import/Export space.
|
|
992
|
+
//
|
|
993
|
+
async importBundle(ctx, spaceId, body, args) {
|
|
994
|
+
return this._call(ctx, new URL(`/spaces/${spaceId}/import`, this.baseUrl), {
|
|
995
|
+
...args,
|
|
996
|
+
body,
|
|
997
|
+
method: "PUT"
|
|
998
|
+
});
|
|
999
|
+
}
|
|
1000
|
+
async exportBundle(ctx, spaceId, body, args) {
|
|
1001
|
+
return this._call(ctx, new URL(`/spaces/${spaceId}/export`, this.baseUrl), {
|
|
1002
|
+
...args,
|
|
1003
|
+
body,
|
|
1004
|
+
method: "POST"
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
1007
|
+
//
|
|
953
1008
|
// Internal
|
|
954
1009
|
//
|
|
955
|
-
async _fetch(url,
|
|
956
|
-
return pipe(HttpClient.get(url), withLogging, withRetryConfig, Effect2.provide(FetchHttpClient.layer), Effect2.provide(HttpConfig.default), Effect2.withSpan("EdgeHttpClient"),
|
|
1010
|
+
async _fetch(url, _args) {
|
|
1011
|
+
return Function.pipe(HttpClient.get(url), withLogging, withRetryConfig, Effect2.provide(FetchHttpClient.layer), Effect2.provide(HttpConfig.default), Effect2.withSpan("EdgeHttpClient"), runAndForwardErrors);
|
|
957
1012
|
}
|
|
958
1013
|
// TODO(burdon): Refactor with effect (see edge-http-client.test.ts).
|
|
959
|
-
async _call(url, args) {
|
|
1014
|
+
async _call(ctx, url, args) {
|
|
960
1015
|
const shouldRetry = createRetryHandler(args);
|
|
961
|
-
const requestContext = args.context ?? new Context3(void 0, {
|
|
962
|
-
F: __dxlog_file6,
|
|
963
|
-
L: 289
|
|
964
|
-
});
|
|
965
1016
|
log4("fetch", {
|
|
966
1017
|
url,
|
|
967
1018
|
request: args.body
|
|
968
|
-
}, {
|
|
969
|
-
|
|
970
|
-
L: 290,
|
|
971
|
-
S: this,
|
|
972
|
-
C: (f, a) => f(...a)
|
|
973
|
-
});
|
|
1019
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 290, S: this });
|
|
1020
|
+
const traceHeaders = getTraceHeaders(ctx);
|
|
974
1021
|
let handledAuth = false;
|
|
1022
|
+
const tryCount = 1;
|
|
975
1023
|
while (true) {
|
|
976
|
-
let processingError;
|
|
977
|
-
let retryAfterHeaderValue = Number.NaN;
|
|
1024
|
+
let processingError = void 0;
|
|
978
1025
|
try {
|
|
979
|
-
|
|
1026
|
+
if (!this._authHeader && args.auth) {
|
|
1027
|
+
const response2 = await fetch(new URL(`/auth`, this.baseUrl));
|
|
1028
|
+
if (response2.status === 401) {
|
|
1029
|
+
this._authHeader = await this._handleUnauthorized(response2);
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
const request = createRequest(args, this._authHeader, traceHeaders, this._clientTag);
|
|
1033
|
+
log4("call edge", {
|
|
1034
|
+
url,
|
|
1035
|
+
tryCount,
|
|
1036
|
+
authHeader: !!this._authHeader
|
|
1037
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 307, S: this });
|
|
980
1038
|
const response = await fetch(url, request);
|
|
981
|
-
retryAfterHeaderValue = Number(response.headers.get("Retry-After"));
|
|
982
1039
|
if (response.ok) {
|
|
983
|
-
const
|
|
984
|
-
|
|
985
|
-
|
|
1040
|
+
const body2 = await response.clone().json();
|
|
1041
|
+
invariant4(body2, "Expected body to be present", { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 315, S: this, A: ["body", "'Expected body to be present'"] });
|
|
1042
|
+
if (!("success" in body2)) {
|
|
1043
|
+
return body2;
|
|
986
1044
|
}
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
body
|
|
990
|
-
}, {
|
|
991
|
-
F: __dxlog_file6,
|
|
992
|
-
L: 306,
|
|
993
|
-
S: this,
|
|
994
|
-
C: (f, a) => f(...a)
|
|
995
|
-
});
|
|
996
|
-
if (body.errorData?.type === "auth_challenge" && typeof body.errorData?.challenge === "string") {
|
|
997
|
-
processingError = new EdgeAuthChallengeError(body.errorData.challenge, body.errorData);
|
|
998
|
-
} else {
|
|
999
|
-
processingError = EdgeCallFailedError.fromUnsuccessfulResponse(response, body);
|
|
1045
|
+
if (body2.success) {
|
|
1046
|
+
return body2.data;
|
|
1000
1047
|
}
|
|
1001
1048
|
} else if (response.status === 401 && !handledAuth) {
|
|
1002
1049
|
this._authHeader = await this._handleUnauthorized(response);
|
|
1003
1050
|
handledAuth = true;
|
|
1004
1051
|
continue;
|
|
1052
|
+
}
|
|
1053
|
+
const body = response.headers.get("Content-Type") === "application/json" ? await response.clone().json() : void 0;
|
|
1054
|
+
invariant4(!body?.success, "Expected body to not be a failure response or undefined.", { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 328, S: this, A: ["!body?.success", "'Expected body to not be a failure response or undefined.'"] });
|
|
1055
|
+
if (body?.data?.type === "auth_challenge" && typeof body?.data?.challenge === "string") {
|
|
1056
|
+
processingError = new EdgeAuthChallengeError(body.data.challenge, body.data);
|
|
1057
|
+
} else if (body?.success === false) {
|
|
1058
|
+
processingError = EdgeCallFailedError.fromUnsuccessfulResponse(response, body);
|
|
1005
1059
|
} else {
|
|
1006
|
-
|
|
1060
|
+
invariant4(!response.ok, "Expected response to not be ok.", { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 334, S: this, A: ["!response.ok", "'Expected response to not be ok.'"] });
|
|
1061
|
+
processingError = await EdgeCallFailedError.fromHttpFailure(response);
|
|
1007
1062
|
}
|
|
1008
1063
|
} catch (error) {
|
|
1009
1064
|
processingError = EdgeCallFailedError.fromProcessingFailureCause(error);
|
|
1010
1065
|
}
|
|
1011
|
-
if (processingError
|
|
1012
|
-
log4("retrying edge request", {
|
|
1066
|
+
if (processingError?.isRetryable && await shouldRetry(ctx, processingError.retryAfterMs)) {
|
|
1067
|
+
log4.verbose("retrying edge request", {
|
|
1013
1068
|
url,
|
|
1014
1069
|
processingError
|
|
1015
|
-
}, {
|
|
1016
|
-
F: __dxlog_file6,
|
|
1017
|
-
L: 324,
|
|
1018
|
-
S: this,
|
|
1019
|
-
C: (f, a) => f(...a)
|
|
1020
|
-
});
|
|
1070
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 341, S: this });
|
|
1021
1071
|
} else {
|
|
1022
1072
|
throw processingError;
|
|
1023
1073
|
}
|
|
@@ -1025,35 +1075,63 @@ var EdgeHttpClient = class {
|
|
|
1025
1075
|
}
|
|
1026
1076
|
async _handleUnauthorized(response) {
|
|
1027
1077
|
if (!this._edgeIdentity) {
|
|
1028
|
-
log4.warn("unauthorized response received before identity was set", void 0, {
|
|
1029
|
-
|
|
1030
|
-
L: 333,
|
|
1031
|
-
S: this,
|
|
1032
|
-
C: (f, a) => f(...a)
|
|
1033
|
-
});
|
|
1034
|
-
throw EdgeCallFailedError.fromHttpFailure(response);
|
|
1078
|
+
log4.warn("unauthorized response received before identity was set", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 352, S: this });
|
|
1079
|
+
throw await EdgeCallFailedError.fromHttpFailure(response);
|
|
1035
1080
|
}
|
|
1036
1081
|
const challenge = await handleAuthChallenge(response, this._edgeIdentity);
|
|
1037
1082
|
return encodeAuthHeader(challenge);
|
|
1038
1083
|
}
|
|
1039
1084
|
};
|
|
1040
|
-
var createRequest = ({ method, body }, authHeader) => {
|
|
1085
|
+
var createRequest = ({ method, body, json = true }, authHeader, traceHeaders, clientTag) => {
|
|
1086
|
+
let requestBody;
|
|
1087
|
+
const headers = {};
|
|
1088
|
+
if (json) {
|
|
1089
|
+
requestBody = body && JSON.stringify(body);
|
|
1090
|
+
headers["Content-Type"] = "application/json";
|
|
1091
|
+
} else {
|
|
1092
|
+
requestBody = body;
|
|
1093
|
+
}
|
|
1094
|
+
if (typeof requestBody === "string" && requestBody.length > WARNING_BODY_SIZE) {
|
|
1095
|
+
log4.warn("Request with large body", {
|
|
1096
|
+
bodySize: requestBody.length
|
|
1097
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 369, S: void 0 });
|
|
1098
|
+
}
|
|
1099
|
+
if (authHeader) {
|
|
1100
|
+
headers["Authorization"] = authHeader;
|
|
1101
|
+
}
|
|
1102
|
+
if (traceHeaders) {
|
|
1103
|
+
Object.assign(headers, traceHeaders);
|
|
1104
|
+
}
|
|
1105
|
+
if (clientTag) {
|
|
1106
|
+
headers[EDGE_CLIENT_TAG_HEADER] = clientTag;
|
|
1107
|
+
}
|
|
1041
1108
|
return {
|
|
1042
1109
|
method,
|
|
1043
|
-
body:
|
|
1044
|
-
headers
|
|
1045
|
-
Authorization: authHeader
|
|
1046
|
-
} : void 0
|
|
1110
|
+
body: requestBody,
|
|
1111
|
+
headers
|
|
1047
1112
|
};
|
|
1048
1113
|
};
|
|
1049
|
-
var
|
|
1050
|
-
|
|
1114
|
+
var getTraceHeaders = (ctx) => {
|
|
1115
|
+
const traceCtx = ctx.getAttribute(TRACE_SPAN_ATTRIBUTE2);
|
|
1116
|
+
if (!traceCtx) {
|
|
1117
|
+
return void 0;
|
|
1118
|
+
}
|
|
1119
|
+
const headers = {
|
|
1120
|
+
traceparent: traceCtx.traceparent
|
|
1121
|
+
};
|
|
1122
|
+
if (traceCtx.tracestate) {
|
|
1123
|
+
headers.tracestate = traceCtx.tracestate;
|
|
1124
|
+
}
|
|
1125
|
+
return headers;
|
|
1126
|
+
};
|
|
1127
|
+
var createRetryHandler = ({ retry: retry2 }) => {
|
|
1128
|
+
if (!retry2 || retry2.count < 1) {
|
|
1051
1129
|
return async () => false;
|
|
1052
1130
|
}
|
|
1053
1131
|
let retries = 0;
|
|
1054
|
-
const maxRetries =
|
|
1055
|
-
const baseTimeout =
|
|
1056
|
-
const jitter =
|
|
1132
|
+
const maxRetries = retry2.count ?? DEFAULT_MAX_RETRIES_COUNT;
|
|
1133
|
+
const baseTimeout = retry2.timeout ?? DEFAULT_RETRY_TIMEOUT;
|
|
1134
|
+
const jitter = retry2.jitter ?? DEFAULT_RETRY_JITTER;
|
|
1057
1135
|
return async (ctx, retryAfter) => {
|
|
1058
1136
|
if (++retries > maxRetries || ctx.disposed) {
|
|
1059
1137
|
return false;
|
|
@@ -1061,12 +1139,16 @@ var createRetryHandler = ({ retry }) => {
|
|
|
1061
1139
|
if (retryAfter) {
|
|
1062
1140
|
await sleep(retryAfter);
|
|
1063
1141
|
} else {
|
|
1064
|
-
const
|
|
1065
|
-
await sleep(
|
|
1142
|
+
const timeout2 = baseTimeout + Math.random() * jitter;
|
|
1143
|
+
await sleep(timeout2);
|
|
1066
1144
|
}
|
|
1067
1145
|
return true;
|
|
1068
1146
|
};
|
|
1069
1147
|
};
|
|
1148
|
+
var getFileMimeType = (filename) => [
|
|
1149
|
+
".js",
|
|
1150
|
+
".mjs"
|
|
1151
|
+
].some((codeExtension) => filename.endsWith(codeExtension)) ? "application/javascript+module" : filename.endsWith(".wasm") ? "application/wasm" : "application/octet-stream";
|
|
1070
1152
|
export {
|
|
1071
1153
|
CLOUDFLARE_MESSAGE_MAX_BYTES,
|
|
1072
1154
|
CLOUDFLARE_RPC_MAX_BYTES,
|
|
@@ -1074,6 +1156,7 @@ export {
|
|
|
1074
1156
|
EdgeConnectionClosedError,
|
|
1075
1157
|
EdgeHttpClient,
|
|
1076
1158
|
EdgeIdentityChangedError,
|
|
1159
|
+
HttpConfig,
|
|
1077
1160
|
Protocol,
|
|
1078
1161
|
WebSocketMuxer,
|
|
1079
1162
|
createChainEdgeIdentity,
|
|
@@ -1081,9 +1164,13 @@ export {
|
|
|
1081
1164
|
createEphemeralEdgeIdentity,
|
|
1082
1165
|
createStubEdgeIdentity,
|
|
1083
1166
|
createTestHaloEdgeIdentity,
|
|
1167
|
+
encodeAuthHeader,
|
|
1084
1168
|
getTypename,
|
|
1085
1169
|
handleAuthChallenge,
|
|
1086
1170
|
protocol,
|
|
1087
|
-
toUint8Array
|
|
1171
|
+
toUint8Array,
|
|
1172
|
+
withLogging,
|
|
1173
|
+
withRetry,
|
|
1174
|
+
withRetryConfig
|
|
1088
1175
|
};
|
|
1089
1176
|
//# sourceMappingURL=index.mjs.map
|