@flaxia/node 0.5.0 → 0.5.1
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/assets/ai-inference.js +241 -85
- package/dist/assets/webgpuProbe.js +357 -0
- package/dist/client/SignalingClient.d.ts.map +1 -1
- package/dist/client/__tests__/mobile-lifecycle.test.d.ts +2 -0
- package/dist/client/__tests__/mobile-lifecycle.test.d.ts.map +1 -0
- package/dist/client/mobile-lifecycle.d.ts +20 -0
- package/dist/client/mobile-lifecycle.d.ts.map +1 -0
- package/dist/executor/WorkerPool.d.ts +7 -1
- package/dist/executor/WorkerPool.d.ts.map +1 -1
- package/dist/executor/__tests__/resourceReporter.test.d.ts +2 -0
- package/dist/executor/__tests__/resourceReporter.test.d.ts.map +1 -0
- package/dist/executor/memoryProbe.d.ts +5 -0
- package/dist/executor/memoryProbe.d.ts.map +1 -1
- package/dist/executor/resourceReporter.d.ts +15 -0
- package/dist/executor/resourceReporter.d.ts.map +1 -0
- package/dist/executor/webgpuProbe.d.ts +16 -5
- package/dist/executor/webgpuProbe.d.ts.map +1 -1
- package/dist/index.js +943 -291
- package/dist/swarm/__tests__/peer-quality.test.d.ts +2 -0
- package/dist/swarm/__tests__/peer-quality.test.d.ts.map +1 -0
- package/dist/swarm/__tests__/peer-transport.test.d.ts +2 -0
- package/dist/swarm/__tests__/peer-transport.test.d.ts.map +1 -0
- package/dist/swarm/adapter.d.ts +1 -1
- package/dist/swarm/adapter.d.ts.map +1 -1
- package/dist/swarm/controller.d.ts +4 -0
- package/dist/swarm/controller.d.ts.map +1 -1
- package/dist/swarm/messages.d.ts +2 -2
- package/dist/swarm/messages.d.ts.map +1 -1
- package/dist/swarm/peer-quality.d.ts +14 -0
- package/dist/swarm/peer-quality.d.ts.map +1 -0
- package/dist/swarm/peer-transport.d.ts +81 -0
- package/dist/swarm/peer-transport.d.ts.map +1 -0
- package/dist/swarm/runtime.d.ts +5 -1
- package/dist/swarm/runtime.d.ts.map +1 -1
- package/dist/swarm-engine.js +39 -20
- package/dist/worker.js +331 -208
- package/dist/workloads/__tests__/model-pipeline-cache.test.d.ts +2 -0
- package/dist/workloads/__tests__/model-pipeline-cache.test.d.ts.map +1 -0
- package/dist/workloads/ai-inference.d.ts +6 -0
- package/dist/workloads/ai-inference.d.ts.map +1 -1
- package/dist/workloads/model-pipeline-cache.d.ts +48 -0
- package/dist/workloads/model-pipeline-cache.d.ts.map +1 -0
- package/package.json +1 -1
- package/dist/assets/dist.js +0 -209
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as
|
|
1
|
+
import { A as e, C as t, D as n, E as r, S as i, T as a, _ as o, b as s, d as c, g as l, i as u, n as d, o as f, p, r as m, s as h, w as g } from "./assets/webgpuProbe.js";
|
|
2
|
+
import { t as _ } from "./assets/egress-guard.js";
|
|
3
3
|
//#region src/consent/notice.ts
|
|
4
|
-
var
|
|
4
|
+
var v = {
|
|
5
5
|
summary: "同意すると、このブラウザは第三者から依頼された処理をバックグラウンドで実行します。",
|
|
6
6
|
items: [
|
|
7
7
|
"実行する処理: 顧客(第三者)が依頼したワークロード。任意の WebAssembly コンテナの実行や、画像の NSFW(成人向け)判定などを含みます。",
|
|
@@ -12,34 +12,34 @@ var u = {
|
|
|
12
12
|
acceptGateHint: "開示内容を確認できるよう、「同意して開始」はしばらくの間押せません。",
|
|
13
13
|
acceptLabel: "同意して開始",
|
|
14
14
|
rejectLabel: "拒否"
|
|
15
|
-
},
|
|
16
|
-
function
|
|
15
|
+
}, y = 4320 * 60 * 60 * 1e3, b = "flaxia_consent_record", x = "flaxia_consent_granted", ee = "flaxia_consent_expiry", S = "flaxia_consent_denied", C = 1, te = 1e4, w = 2e3, ne = "flaxia-consent-integrity", re = 1, T = "keys", E = "consent-hmac-sha256-v1", ie = (...e) => console.warn("[flaxia-node]", ...e), ae = /* @__PURE__ */ new Map();
|
|
16
|
+
function oe(e) {
|
|
17
17
|
try {
|
|
18
18
|
return localStorage.getItem(e);
|
|
19
19
|
} catch {
|
|
20
|
-
return
|
|
20
|
+
return ae.get(e) ?? null;
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
-
function
|
|
23
|
+
function se(e, t) {
|
|
24
24
|
try {
|
|
25
25
|
localStorage.setItem(e, t);
|
|
26
26
|
} catch {
|
|
27
|
-
|
|
27
|
+
ae.set(e, t);
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
-
function
|
|
30
|
+
function D(e) {
|
|
31
31
|
try {
|
|
32
32
|
localStorage.removeItem(e);
|
|
33
33
|
} catch {
|
|
34
|
-
|
|
34
|
+
ae.delete(e);
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
-
function
|
|
37
|
+
function ce(e) {
|
|
38
38
|
return new Promise((t, n) => {
|
|
39
39
|
e.onsuccess = () => t(e.result), e.onerror = () => n(e.error ?? /* @__PURE__ */ Error("IndexedDB request failed"));
|
|
40
40
|
});
|
|
41
41
|
}
|
|
42
|
-
function
|
|
42
|
+
function le() {
|
|
43
43
|
return new Promise((e, t) => {
|
|
44
44
|
let n;
|
|
45
45
|
try {
|
|
@@ -53,37 +53,37 @@ function T() {
|
|
|
53
53
|
}
|
|
54
54
|
let r;
|
|
55
55
|
try {
|
|
56
|
-
r = n.open(
|
|
56
|
+
r = n.open(ne, re);
|
|
57
57
|
} catch (e) {
|
|
58
58
|
t(e);
|
|
59
59
|
return;
|
|
60
60
|
}
|
|
61
61
|
r.onupgradeneeded = () => {
|
|
62
62
|
let e = r.result;
|
|
63
|
-
e.objectStoreNames.contains(
|
|
63
|
+
e.objectStoreNames.contains(T) || e.createObjectStore(T);
|
|
64
64
|
}, r.onsuccess = () => e(r.result), r.onerror = () => t(r.error ?? /* @__PURE__ */ Error("IndexedDB open failed")), r.onblocked = () => t(/* @__PURE__ */ Error("IndexedDB open blocked"));
|
|
65
65
|
});
|
|
66
66
|
}
|
|
67
|
-
function
|
|
67
|
+
function ue(e) {
|
|
68
68
|
if (!e || typeof e != "object") return !1;
|
|
69
69
|
let t = e;
|
|
70
70
|
return t.type === "secret" && t.algorithm?.name === "HMAC";
|
|
71
71
|
}
|
|
72
|
-
var
|
|
72
|
+
var de = {
|
|
73
73
|
async load() {
|
|
74
|
-
let e = await
|
|
74
|
+
let e = await le();
|
|
75
75
|
try {
|
|
76
|
-
let t = await
|
|
77
|
-
return
|
|
76
|
+
let t = await ce(e.transaction(T, "readonly").objectStore(T).get(E));
|
|
77
|
+
return ue(t) ? t : null;
|
|
78
78
|
} finally {
|
|
79
79
|
e.close();
|
|
80
80
|
}
|
|
81
81
|
},
|
|
82
82
|
async save(e) {
|
|
83
|
-
let t = await
|
|
83
|
+
let t = await le();
|
|
84
84
|
try {
|
|
85
|
-
let n = t.transaction(
|
|
86
|
-
n.objectStore(
|
|
85
|
+
let n = t.transaction(T, "readwrite");
|
|
86
|
+
n.objectStore(T).put(e, E), await new Promise((e, t) => {
|
|
87
87
|
n.oncomplete = () => e(), n.onerror = () => t(n.error ?? /* @__PURE__ */ Error("IndexedDB write failed")), n.onabort = () => t(n.error ?? /* @__PURE__ */ Error("IndexedDB write aborted"));
|
|
88
88
|
});
|
|
89
89
|
} finally {
|
|
@@ -91,10 +91,10 @@ var ae = {
|
|
|
91
91
|
}
|
|
92
92
|
},
|
|
93
93
|
async clear() {
|
|
94
|
-
let e = await
|
|
94
|
+
let e = await le();
|
|
95
95
|
try {
|
|
96
|
-
let t = e.transaction(
|
|
97
|
-
t.objectStore(
|
|
96
|
+
let t = e.transaction(T, "readwrite");
|
|
97
|
+
t.objectStore(T).delete(E), await new Promise((e, n) => {
|
|
98
98
|
t.oncomplete = () => e(), t.onerror = () => n(t.error ?? /* @__PURE__ */ Error("IndexedDB delete failed")), t.onabort = () => n(t.error ?? /* @__PURE__ */ Error("IndexedDB delete aborted"));
|
|
99
99
|
});
|
|
100
100
|
} finally {
|
|
@@ -102,7 +102,7 @@ var ae = {
|
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
};
|
|
105
|
-
function
|
|
105
|
+
function fe(e, t, n) {
|
|
106
106
|
return new Promise((r) => {
|
|
107
107
|
let i = !1, a, o = (e) => {
|
|
108
108
|
i || (i = !0, a !== void 0 && clearTimeout(a), r(e));
|
|
@@ -110,15 +110,15 @@ function E(e, t, n) {
|
|
|
110
110
|
a = setTimeout(() => o(t), n), e.then((e) => o(e), () => o(t));
|
|
111
111
|
});
|
|
112
112
|
}
|
|
113
|
-
var
|
|
114
|
-
function
|
|
113
|
+
var pe = de, O = null, k = null, A = !1, j = !1, M = null, N = 0, P = 0, F = null, me = !1;
|
|
114
|
+
function he() {
|
|
115
115
|
try {
|
|
116
116
|
let e = globalThis.location?.origin;
|
|
117
117
|
if (typeof e == "string" && e.length > 0) return e;
|
|
118
118
|
} catch {}
|
|
119
119
|
return "unknown";
|
|
120
120
|
}
|
|
121
|
-
var
|
|
121
|
+
var ge = he, _e = () => ge(), ve = {
|
|
122
122
|
name: "HMAC",
|
|
123
123
|
hash: "SHA-256"
|
|
124
124
|
};
|
|
@@ -129,7 +129,7 @@ function I() {
|
|
|
129
129
|
} catch {}
|
|
130
130
|
return null;
|
|
131
131
|
}
|
|
132
|
-
function
|
|
132
|
+
function ye(e) {
|
|
133
133
|
let t = new TextEncoder().encode(JSON.stringify([
|
|
134
134
|
e.v,
|
|
135
135
|
e.noticeVersion,
|
|
@@ -139,12 +139,12 @@ function de(e) {
|
|
|
139
139
|
])), n = new Uint8Array(t.byteLength);
|
|
140
140
|
return n.set(t), n;
|
|
141
141
|
}
|
|
142
|
-
function
|
|
142
|
+
function be(e) {
|
|
143
143
|
let t = "";
|
|
144
144
|
for (let n of e) t += String.fromCharCode(n);
|
|
145
145
|
return btoa(t).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
146
146
|
}
|
|
147
|
-
function
|
|
147
|
+
function xe(e) {
|
|
148
148
|
try {
|
|
149
149
|
let t = e.replace(/-/g, "+").replace(/_/g, "/"), n = t + "=".repeat((4 - t.length % 4) % 4), r = atob(n), i = new Uint8Array(r.length);
|
|
150
150
|
for (let e = 0; e < r.length; e += 1) i[e] = r.charCodeAt(e);
|
|
@@ -153,40 +153,40 @@ function pe(e) {
|
|
|
153
153
|
return null;
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
|
-
async function
|
|
157
|
-
let e = await
|
|
156
|
+
async function Se() {
|
|
157
|
+
let e = await fe(pe.load(), null, w);
|
|
158
158
|
if (e) return e;
|
|
159
159
|
let t = I();
|
|
160
160
|
if (!t) return null;
|
|
161
161
|
try {
|
|
162
|
-
let e = await t.generateKey(
|
|
163
|
-
return await
|
|
162
|
+
let e = await t.generateKey(ve, !1, ["sign", "verify"]);
|
|
163
|
+
return await fe(pe.save(e), void 0, w), e;
|
|
164
164
|
} catch {
|
|
165
165
|
return null;
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
|
-
async function
|
|
168
|
+
async function Ce(e) {
|
|
169
169
|
let t = I();
|
|
170
170
|
if (!t || !O) return null;
|
|
171
171
|
try {
|
|
172
|
-
let n = await t.sign("HMAC", O,
|
|
173
|
-
return
|
|
172
|
+
let n = await t.sign("HMAC", O, ye(e));
|
|
173
|
+
return be(new Uint8Array(n));
|
|
174
174
|
} catch {
|
|
175
175
|
return null;
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
|
-
async function
|
|
178
|
+
async function we(e) {
|
|
179
179
|
let t = I();
|
|
180
180
|
if (!t || !O || !e.mac) return !1;
|
|
181
|
-
let n =
|
|
181
|
+
let n = xe(e.mac);
|
|
182
182
|
if (!n) return !1;
|
|
183
183
|
try {
|
|
184
|
-
return await t.verify("HMAC", O, n,
|
|
184
|
+
return await t.verify("HMAC", O, n, ye(e));
|
|
185
185
|
} catch {
|
|
186
186
|
return !1;
|
|
187
187
|
}
|
|
188
188
|
}
|
|
189
|
-
function
|
|
189
|
+
function Te(e) {
|
|
190
190
|
if (!e) return null;
|
|
191
191
|
try {
|
|
192
192
|
let t = JSON.parse(e);
|
|
@@ -204,128 +204,128 @@ function _e(e) {
|
|
|
204
204
|
return null;
|
|
205
205
|
}
|
|
206
206
|
}
|
|
207
|
-
function
|
|
207
|
+
function Ee(e, t) {
|
|
208
208
|
return !(!Number.isFinite(e.grantedAt) || !Number.isFinite(e.expiry) || e.expiry <= t || e.grantedAt > e.expiry || e.expiry - e.grantedAt > 15552e6);
|
|
209
209
|
}
|
|
210
|
-
function
|
|
211
|
-
return e.v ===
|
|
210
|
+
function De(e) {
|
|
211
|
+
return e.v === C && e.noticeVersion === 2 && e.origin === _e();
|
|
212
212
|
}
|
|
213
|
-
function
|
|
214
|
-
return
|
|
213
|
+
function Oe() {
|
|
214
|
+
return Te(oe(b));
|
|
215
215
|
}
|
|
216
|
-
function
|
|
217
|
-
|
|
216
|
+
function ke(e) {
|
|
217
|
+
se(b, JSON.stringify(e));
|
|
218
218
|
}
|
|
219
|
-
function
|
|
220
|
-
|
|
219
|
+
function L() {
|
|
220
|
+
D(b);
|
|
221
221
|
}
|
|
222
|
-
function
|
|
223
|
-
|
|
222
|
+
function R() {
|
|
223
|
+
D(x), D(ee);
|
|
224
224
|
}
|
|
225
|
-
var
|
|
225
|
+
var Ae = () => {
|
|
226
226
|
let e = k;
|
|
227
|
-
return !e || !A ? !1 :
|
|
228
|
-
},
|
|
229
|
-
async function
|
|
227
|
+
return !e || !A ? !1 : Ee(e, Date.now()) && De(e);
|
|
228
|
+
}, je = () => oe(S) === "true", z = () => Ae() ? "granted" : je() ? "denied" : "unset", B = () => (M ||= Me(), M);
|
|
229
|
+
async function Me() {
|
|
230
230
|
let e = ++N, t = P, n = null;
|
|
231
231
|
try {
|
|
232
|
-
n = await
|
|
232
|
+
n = await Se();
|
|
233
233
|
} catch {
|
|
234
234
|
n = null;
|
|
235
235
|
}
|
|
236
|
-
if (e !== N) return
|
|
237
|
-
O = n,
|
|
238
|
-
let r =
|
|
239
|
-
return r !== null && await
|
|
236
|
+
if (e !== N) return z();
|
|
237
|
+
O = n, R();
|
|
238
|
+
let r = Oe();
|
|
239
|
+
return r !== null && await we(r) && Ee(r, Date.now()) && De(r) && r ? t === P && e === N && (k = r, A = !0) : r && !j && (L(), t === P && e === N && (k = null, A = !1)), z();
|
|
240
240
|
}
|
|
241
|
-
function
|
|
241
|
+
function Ne() {
|
|
242
242
|
let e = F;
|
|
243
|
-
return F = null, e && Date.now() - e.at <=
|
|
243
|
+
return F = null, e && Date.now() - e.at <= te ? {
|
|
244
244
|
noticeVersion: e.noticeVersion,
|
|
245
245
|
source: "user-gesture"
|
|
246
|
-
} :
|
|
246
|
+
} : me ? {
|
|
247
247
|
noticeVersion: 2,
|
|
248
248
|
source: "host-managed"
|
|
249
249
|
} : null;
|
|
250
250
|
}
|
|
251
|
-
function
|
|
252
|
-
return typeof e != "number" || !Number.isFinite(e) || e <= 0 ?
|
|
251
|
+
function Pe(e) {
|
|
252
|
+
return typeof e != "number" || !Number.isFinite(e) || e <= 0 ? y : Math.min(Math.floor(e), y);
|
|
253
253
|
}
|
|
254
|
-
function
|
|
254
|
+
function Fe(e, t) {
|
|
255
255
|
let n = Date.now();
|
|
256
256
|
return {
|
|
257
|
-
v:
|
|
257
|
+
v: C,
|
|
258
258
|
noticeVersion: e,
|
|
259
|
-
origin:
|
|
259
|
+
origin: _e(),
|
|
260
260
|
grantedAt: n,
|
|
261
|
-
expiry: n +
|
|
261
|
+
expiry: n + Pe(t),
|
|
262
262
|
mac: ""
|
|
263
263
|
};
|
|
264
264
|
}
|
|
265
|
-
function
|
|
266
|
-
|
|
267
|
-
let n =
|
|
268
|
-
return k = n, A = !0, j = !0, P += 1,
|
|
265
|
+
function Ie(e, t) {
|
|
266
|
+
D(S), R();
|
|
267
|
+
let n = Fe(e.noticeVersion, t);
|
|
268
|
+
return k = n, A = !0, j = !0, P += 1, ke(n), n;
|
|
269
269
|
}
|
|
270
|
-
async function
|
|
270
|
+
async function Le(e) {
|
|
271
271
|
try {
|
|
272
|
-
if (await
|
|
273
|
-
let t = await
|
|
272
|
+
if (await B(), k !== e) return;
|
|
273
|
+
let t = await Ce(e);
|
|
274
274
|
if (k !== e) return;
|
|
275
275
|
if (!t) {
|
|
276
|
-
|
|
276
|
+
L(), j = !1;
|
|
277
277
|
return;
|
|
278
278
|
}
|
|
279
279
|
let n = {
|
|
280
280
|
...e,
|
|
281
281
|
mac: t
|
|
282
282
|
};
|
|
283
|
-
k = n, A = !0,
|
|
283
|
+
k = n, A = !0, ke(n), j = !1;
|
|
284
284
|
} catch {
|
|
285
|
-
k === e && (
|
|
285
|
+
k === e && (L(), j = !1);
|
|
286
286
|
}
|
|
287
287
|
}
|
|
288
|
-
var
|
|
289
|
-
let e =
|
|
288
|
+
var Re = () => {
|
|
289
|
+
let e = Ne();
|
|
290
290
|
if (!e) {
|
|
291
|
-
|
|
291
|
+
ie("refusing programmatic consent grant: consent requires the built-in banner to be rendered and accepted by the visitor (see setHostManagedConsentAllowed for host-managed UIs)");
|
|
292
292
|
return;
|
|
293
293
|
}
|
|
294
|
-
|
|
295
|
-
},
|
|
294
|
+
Le(Ie(e));
|
|
295
|
+
}, ze = (e = 2) => {
|
|
296
296
|
F = {
|
|
297
297
|
noticeVersion: e,
|
|
298
298
|
at: Date.now()
|
|
299
299
|
};
|
|
300
|
-
},
|
|
301
|
-
|
|
302
|
-
},
|
|
303
|
-
|
|
304
|
-
},
|
|
305
|
-
|
|
306
|
-
},
|
|
307
|
-
async function
|
|
308
|
-
let e = P, t =
|
|
300
|
+
}, Be = (e) => {
|
|
301
|
+
me = e === !0;
|
|
302
|
+
}, Ve = () => {
|
|
303
|
+
L(), R(), k = null, A = !1, j = !1, P += 1, se(S, "true");
|
|
304
|
+
}, He = () => {
|
|
305
|
+
L(), R(), D(S), k = null, A = !1, j = !1, F = null, O = null, N += 1, P += 1, M = null, fe(pe.clear(), void 0, w);
|
|
306
|
+
}, Ue = oe, We = se, Ge = D;
|
|
307
|
+
async function Ke() {
|
|
308
|
+
let e = P, t = Oe();
|
|
309
309
|
if (!t) {
|
|
310
310
|
k = null, A = !1;
|
|
311
311
|
return;
|
|
312
312
|
}
|
|
313
313
|
if (!I()) return;
|
|
314
314
|
if (!O) {
|
|
315
|
-
M = null, await
|
|
315
|
+
M = null, await B();
|
|
316
316
|
return;
|
|
317
317
|
}
|
|
318
|
-
let n = await
|
|
318
|
+
let n = await we(t), r = Oe();
|
|
319
319
|
if (e !== P || !r || JSON.stringify(r) !== JSON.stringify(t)) return;
|
|
320
|
-
let i = n &&
|
|
320
|
+
let i = n && Ee(t, Date.now()) && De(t);
|
|
321
321
|
k = i ? t : null, A = i;
|
|
322
322
|
}
|
|
323
323
|
try {
|
|
324
324
|
typeof globalThis.addEventListener == "function" && globalThis.addEventListener("storage", (e) => {
|
|
325
|
-
e.key !== null && e.key !==
|
|
325
|
+
e.key !== null && e.key !== b && e.key !== S || (P += 1, Ke());
|
|
326
326
|
});
|
|
327
327
|
} catch {}
|
|
328
|
-
var
|
|
328
|
+
var qe = () => {
|
|
329
329
|
try {
|
|
330
330
|
if (typeof crypto < "u" && typeof crypto.randomUUID == "function") return crypto.randomUUID();
|
|
331
331
|
} catch {}
|
|
@@ -334,38 +334,38 @@ var Ne = () => {
|
|
|
334
334
|
return (e === "x" ? t : t & 3 | 8).toString(16);
|
|
335
335
|
});
|
|
336
336
|
};
|
|
337
|
-
|
|
337
|
+
B();
|
|
338
338
|
//#endregion
|
|
339
339
|
//#region src/consent/ConsentUI.ts
|
|
340
|
-
var
|
|
340
|
+
var V = "#6366f1", Je = 1500, Ye = 1500, Xe = 6e4, Ze = 80, Qe = 40, $e = [
|
|
341
341
|
"bottom-right",
|
|
342
342
|
"bottom-left",
|
|
343
343
|
"top-right",
|
|
344
344
|
"top-left"
|
|
345
|
-
],
|
|
346
|
-
function
|
|
347
|
-
if (typeof e != "string") return
|
|
345
|
+
], et = /^#[0-9a-f]{3}$/i, tt = /^#[0-9a-f]{6}$/i, nt = /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/i, rt = /^rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(0|1|0?\.\d+)\s*\)$/i, it = new Map((/* @__PURE__ */ "black.white.red.green.blue.indigo.violet.purple.teal.cyan.orange.pink.brown.gray.grey.slate.navy.maroon.olive.gold.crimson.tomato.salmon.coral.seagreen.steelblue.royalblue.dodgerblue.mediumseagreen.mediumpurple.rebeccapurple".split(".")).map((e) => [e, e]));
|
|
346
|
+
function at(e) {
|
|
347
|
+
if (typeof e != "string") return V;
|
|
348
348
|
let t = e.trim();
|
|
349
|
-
if (t.length === 0 || t.length > 64) return
|
|
350
|
-
if (
|
|
351
|
-
let n =
|
|
349
|
+
if (t.length === 0 || t.length > 64) return V;
|
|
350
|
+
if (et.test(t) || tt.test(t)) return t.toLowerCase();
|
|
351
|
+
let n = nt.exec(t);
|
|
352
352
|
if (n) {
|
|
353
353
|
let [e, t, r] = n.slice(1).map(Number);
|
|
354
|
-
return e <= 255 && t <= 255 && r <= 255 ? `rgb(${e}, ${t}, ${r})` :
|
|
354
|
+
return e <= 255 && t <= 255 && r <= 255 ? `rgb(${e}, ${t}, ${r})` : V;
|
|
355
355
|
}
|
|
356
|
-
let r =
|
|
356
|
+
let r = rt.exec(t);
|
|
357
357
|
if (r) {
|
|
358
358
|
let [e, t, n] = r.slice(1, 4).map(Number), i = Number(r[4]);
|
|
359
|
-
return e <= 255 && t <= 255 && n <= 255 && i >= 0 && i <= 1 ? `rgba(${e}, ${t}, ${n}, ${i})` :
|
|
359
|
+
return e <= 255 && t <= 255 && n <= 255 && i >= 0 && i <= 1 ? `rgba(${e}, ${t}, ${n}, ${i})` : V;
|
|
360
360
|
}
|
|
361
|
-
return
|
|
361
|
+
return it.get(t.toLowerCase()) ?? V;
|
|
362
362
|
}
|
|
363
|
-
function
|
|
363
|
+
function ot(e, t, n) {
|
|
364
364
|
if (typeof e != "string") return t;
|
|
365
365
|
let r = e.replace(/[\u0000-\u001f\u007f-\u009f\u200b-\u200f\u202a-\u202e\u2066-\u2069]/g, "").replace(/\s+/g, " ").trim();
|
|
366
366
|
return r.length === 0 ? t : r.length > n ? `${r.slice(0, n)}…` : r;
|
|
367
367
|
}
|
|
368
|
-
function
|
|
368
|
+
function st(e) {
|
|
369
369
|
if (typeof e != "string" || e.trim().length === 0) return null;
|
|
370
370
|
try {
|
|
371
371
|
let t = new URL(e.trim());
|
|
@@ -374,75 +374,75 @@ function qe(e) {
|
|
|
374
374
|
return null;
|
|
375
375
|
}
|
|
376
376
|
}
|
|
377
|
-
function
|
|
377
|
+
function ct(e) {
|
|
378
378
|
return {
|
|
379
|
-
brandName:
|
|
380
|
-
position:
|
|
381
|
-
accentColor:
|
|
382
|
-
acceptLabel:
|
|
383
|
-
rejectLabel:
|
|
384
|
-
privacyPolicyUrl:
|
|
385
|
-
minVisibleMs:
|
|
379
|
+
brandName: ot(e?.brandName, "Flaxia Crowd", Ze),
|
|
380
|
+
position: $e.includes(e?.position) ? e.position : "bottom-right",
|
|
381
|
+
accentColor: at(e?.accentColor),
|
|
382
|
+
acceptLabel: ot(e?.acceptLabel, v.acceptLabel, Qe),
|
|
383
|
+
rejectLabel: ot(e?.rejectLabel, v.rejectLabel, Qe),
|
|
384
|
+
privacyPolicyUrl: st(e?.privacyPolicyUrl),
|
|
385
|
+
minVisibleMs: lt(e?.minVisibleMs)
|
|
386
386
|
};
|
|
387
387
|
}
|
|
388
|
-
function
|
|
389
|
-
return typeof e != "number" || !Number.isFinite(e) ?
|
|
388
|
+
function lt(e) {
|
|
389
|
+
return typeof e != "number" || !Number.isFinite(e) ? Je : Math.min(Math.max(Math.floor(e), Ye), Xe);
|
|
390
390
|
}
|
|
391
|
-
function
|
|
392
|
-
return typeof t.minVisibleMs == "number" && Number.isFinite(t.minVisibleMs) ? Math.min(Math.max(Math.floor(t.minVisibleMs), 0),
|
|
391
|
+
function ut(e, t) {
|
|
392
|
+
return typeof t.minVisibleMs == "number" && Number.isFinite(t.minVisibleMs) ? Math.min(Math.max(Math.floor(t.minVisibleMs), 0), Xe) : e;
|
|
393
393
|
}
|
|
394
|
-
var
|
|
394
|
+
var dt = "\n .overlay {\n position: fixed;\n __flaxia_position__;\n padding: 20px;\n background: #fff;\n color: #1f2937;\n border: 1px solid #ccc;\n box-shadow: 0 4px 6px rgba(0,0,0,0.1);\n z-index: 9999;\n border-radius: 8px;\n max-width: 300px;\n font-family: sans-serif;\n }\n .overlay h3 {\n margin: 0 0 8px;\n color: #111827;\n font-size: 16px;\n }\n .overlay p {\n margin: 0 0 12px;\n color: #4b5563;\n font-size: 14px;\n line-height: 1.4;\n }\n .overlay ul {\n margin: 0 0 12px;\n padding-left: 18px;\n color: #4b5563;\n font-size: 13px;\n line-height: 1.45;\n }\n .overlay li {\n margin-bottom: 6px;\n }\n .overlay .hint {\n margin: 0 0 8px;\n color: #6b7280;\n font-size: 12px;\n }\n .overlay .privacy {\n margin: 0 0 8px;\n font-size: 12px;\n }\n .overlay .privacy a {\n color: __flaxia_accent__;\n }\n button {\n background: __flaxia_accent__;\n color: white;\n border: none;\n padding: 10px 15px;\n border-radius: 4px;\n cursor: pointer;\n margin-top: 10px;\n width: 100%;\n font-size: 14px;\n }\n button:disabled {\n opacity: 0.6;\n cursor: default;\n }\n button.reject {\n background: transparent;\n color: #4b5563;\n border: 1px solid #ccc;\n }\n @media (prefers-color-scheme: dark) {\n .overlay {\n background: #1f2937;\n color: #f9fafb;\n border-color: #374151;\n box-shadow: 0 4px 6px rgba(0,0,0,0.4);\n }\n .overlay h3 {\n color: #f9fafb;\n }\n .overlay p,\n .overlay ul {\n color: #d1d5db;\n }\n .overlay .hint {\n color: #9ca3af;\n }\n button.reject {\n color: #d1d5db;\n border-color: #4b5563;\n }\n }\n", ft = class {
|
|
395
395
|
constructor(e, t, n, r, i) {
|
|
396
|
-
this.config =
|
|
396
|
+
this.config = ct(t), this.options = i ?? {}, this.root = e.attachShadow({ mode: "closed" }), this.render(n, r);
|
|
397
397
|
}
|
|
398
398
|
shadowRootForTesting() {
|
|
399
399
|
return this.root;
|
|
400
400
|
}
|
|
401
401
|
render(e, t) {
|
|
402
|
-
let { brandName: n, position: r, accentColor: i, acceptLabel: a, rejectLabel: o, privacyPolicyUrl: s } = this.config, [c, l] = r.split("-"),
|
|
403
|
-
|
|
404
|
-
let
|
|
405
|
-
|
|
406
|
-
let
|
|
407
|
-
|
|
408
|
-
let
|
|
409
|
-
|
|
410
|
-
let
|
|
411
|
-
for (let e of
|
|
402
|
+
let { brandName: n, position: r, accentColor: i, acceptLabel: a, rejectLabel: o, privacyPolicyUrl: s } = this.config, [c, l] = r.split("-"), u = document.createElement("style");
|
|
403
|
+
u.textContent = dt.replace(/__flaxia_accent__/g, i).replace("__flaxia_position__", `${c}: 20px; ${l}: 20px`);
|
|
404
|
+
let d = document.createElement("div");
|
|
405
|
+
d.className = "overlay", d.setAttribute("role", "dialog"), d.setAttribute("aria-labelledby", "flaxia-consent-title");
|
|
406
|
+
let f = document.createElement("h3");
|
|
407
|
+
f.id = "flaxia-consent-title", f.textContent = n;
|
|
408
|
+
let p = document.createElement("p");
|
|
409
|
+
p.textContent = v.summary;
|
|
410
|
+
let m = document.createElement("ul");
|
|
411
|
+
for (let e of v.items) {
|
|
412
412
|
let t = document.createElement("li");
|
|
413
|
-
t.textContent = e,
|
|
413
|
+
t.textContent = e, m.appendChild(t);
|
|
414
414
|
}
|
|
415
|
-
if (
|
|
415
|
+
if (d.append(f, p, m), s) {
|
|
416
416
|
let e = document.createElement("p");
|
|
417
417
|
e.className = "privacy";
|
|
418
418
|
let t = document.createElement("a");
|
|
419
|
-
t.href = s, t.target = "_blank", t.rel = "noopener noreferrer", t.textContent = "プライバシーポリシー", e.appendChild(t),
|
|
419
|
+
t.href = s, t.target = "_blank", t.rel = "noopener noreferrer", t.textContent = "プライバシーポリシー", e.appendChild(t), d.appendChild(e);
|
|
420
420
|
}
|
|
421
|
-
let
|
|
422
|
-
|
|
421
|
+
let h = document.createElement("p");
|
|
422
|
+
h.className = "hint", h.textContent = v.acceptGateHint;
|
|
423
|
+
let g = document.createElement("button");
|
|
424
|
+
g.id = "consent-btn", g.type = "button", g.textContent = a;
|
|
423
425
|
let _ = document.createElement("button");
|
|
424
|
-
_.id = "
|
|
425
|
-
let
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
let C = (e) => {
|
|
432
|
-
S || (S = !0, f.remove(), e?.());
|
|
426
|
+
_.id = "reject-btn", _.type = "button", _.className = "reject", _.textContent = o;
|
|
427
|
+
let y = this.options.now ?? (() => Date.now()), b = this.options.schedule ?? ((e, t) => void setTimeout(e, t)), x = ut(this.config.minVisibleMs, this.options), ee = y() + x, S = x <= 0, C = !1;
|
|
428
|
+
S || (g.disabled = !0, g.setAttribute("aria-disabled", "true"), b(() => {
|
|
429
|
+
S = !0, g.disabled = !1, g.removeAttribute("aria-disabled"), h.remove();
|
|
430
|
+
}, x));
|
|
431
|
+
let te = (e) => {
|
|
432
|
+
C || (C = !0, d.remove(), e?.());
|
|
433
433
|
};
|
|
434
|
-
|
|
435
|
-
!
|
|
436
|
-
}),
|
|
437
|
-
|
|
438
|
-
}),
|
|
434
|
+
g.addEventListener("click", () => {
|
|
435
|
+
!S || y() < ee || (ze(2), te(e));
|
|
436
|
+
}), _.addEventListener("click", () => {
|
|
437
|
+
te(t);
|
|
438
|
+
}), S || d.appendChild(h), d.append(g, _), this.root.append(u, d);
|
|
439
439
|
}
|
|
440
|
-
},
|
|
440
|
+
}, H = (...e) => console.log("[flaxia-node]", ...e), pt = class e {
|
|
441
441
|
static {
|
|
442
442
|
this.MAX_PENDING_CONTROLS = 64;
|
|
443
443
|
}
|
|
444
444
|
constructor(e, t = 3e5) {
|
|
445
|
-
this.worker = null, this.queue = [], this.active = null, this.pendingControls = [], this._lastCpuLoad = 0, this.workerUrl = e || "/worker.js", this.defaultTimeoutMs = t, this.initWorker();
|
|
445
|
+
this.worker = null, this.queue = [], this.active = null, this.pendingControls = [], this._lastCpuLoad = 0, this._hasCpuLoadSample = !1, this._modelCacheSnapshot = null, this.workerUrl = e || "/worker.js", this.defaultTimeoutMs = t, this.initWorker();
|
|
446
446
|
}
|
|
447
447
|
initWorker() {
|
|
448
448
|
if (typeof Worker > "u") return;
|
|
@@ -460,7 +460,7 @@ var Ze = "\n .overlay {\n position: fixed;\n __flaxia_position__;\n pa
|
|
|
460
460
|
return;
|
|
461
461
|
}
|
|
462
462
|
let l = () => this.execute(e, t, n, r, i, a, s, c, o);
|
|
463
|
-
this.active ? (
|
|
463
|
+
this.active ? (H(`task queued id=${e} workload=${t} (active task running)`), this.queue.push({
|
|
464
464
|
id: e,
|
|
465
465
|
job: l,
|
|
466
466
|
reject: c
|
|
@@ -474,7 +474,7 @@ var Ze = "\n .overlay {\n position: fixed;\n __flaxia_position__;\n pa
|
|
|
474
474
|
return;
|
|
475
475
|
}
|
|
476
476
|
let u = r ?? this.defaultTimeoutMs, d = !1, f = performance.now();
|
|
477
|
-
|
|
477
|
+
H(`task start id=${e} workload=${t} timeoutMs=${u}`);
|
|
478
478
|
let p = (t) => {
|
|
479
479
|
if (d) return;
|
|
480
480
|
d = !0;
|
|
@@ -483,12 +483,12 @@ var Ze = "\n .overlay {\n position: fixed;\n __flaxia_position__;\n pa
|
|
|
483
483
|
}, m = (n) => {
|
|
484
484
|
let { id: r, type: a, result: l, error: u, token: d, cpuLoad: m } = n.data;
|
|
485
485
|
if (r === e) {
|
|
486
|
-
if (a === "token") {
|
|
486
|
+
if (g(n.data.modelCache) && (this._modelCacheSnapshot = n.data.modelCache), a === "token") {
|
|
487
487
|
i?.(d);
|
|
488
488
|
return;
|
|
489
489
|
}
|
|
490
490
|
if (a === "heartbeat") {
|
|
491
|
-
typeof m == "number" && Number.isFinite(m) && (this._lastCpuLoad = Math.min(1, Math.max(0, m)));
|
|
491
|
+
typeof m == "number" && Number.isFinite(m) && (this._lastCpuLoad = Math.min(1, Math.max(0, m)), this._hasCpuLoadSample = !0);
|
|
492
492
|
return;
|
|
493
493
|
}
|
|
494
494
|
if (a === "swarm-frame") {
|
|
@@ -499,16 +499,16 @@ var Ze = "\n .overlay {\n position: fixed;\n __flaxia_position__;\n pa
|
|
|
499
499
|
c?.onMessage?.(n.data.message);
|
|
500
500
|
return;
|
|
501
501
|
}
|
|
502
|
-
a === "done" ? (
|
|
502
|
+
a === "done" ? (H(`task done id=${e} workload=${t} durationMs=${Math.round(performance.now() - f)}`), p(() => o(l))) : a === "error" ? (H(`task failed id=${e} workload=${t} error=${u}`), p(() => s(Error(u)))) : (H(`task unknown-message id=${e} type=${String(a)}`), p(() => s(/* @__PURE__ */ Error(`Unknown message type: ${String(a)}`))));
|
|
503
503
|
}
|
|
504
|
-
}, h = () => l.removeEventListener("message", m),
|
|
505
|
-
|
|
504
|
+
}, h = () => l.removeEventListener("message", m), _ = setTimeout(() => {
|
|
505
|
+
H(`task timeout id=${e} workload=${t} (worker terminated after ${u}ms)`), this.cleanupWorker(), p(() => s(/* @__PURE__ */ Error("TIMEOUT")));
|
|
506
506
|
}, u);
|
|
507
507
|
this.active = {
|
|
508
508
|
id: e,
|
|
509
509
|
resolve: o,
|
|
510
510
|
reject: s,
|
|
511
|
-
timer:
|
|
511
|
+
timer: _,
|
|
512
512
|
worker: l,
|
|
513
513
|
removeListener: h
|
|
514
514
|
}, l.addEventListener("message", m);
|
|
@@ -560,11 +560,17 @@ var Ze = "\n .overlay {\n position: fixed;\n __flaxia_position__;\n pa
|
|
|
560
560
|
frame: e
|
|
561
561
|
}, [e]);
|
|
562
562
|
}
|
|
563
|
+
setTokenFlow(e, t) {
|
|
564
|
+
return this.active?.id === e ? this.postToActive({
|
|
565
|
+
type: "token-flow",
|
|
566
|
+
paused: t
|
|
567
|
+
}) : !1;
|
|
568
|
+
}
|
|
563
569
|
abort(e, t) {
|
|
564
570
|
let n = this.queue.findIndex((t) => t.id === e);
|
|
565
571
|
if (n >= 0) {
|
|
566
572
|
let [r] = this.queue.splice(n, 1);
|
|
567
|
-
return this.pendingControls = this.pendingControls.filter((t) => t.taskId !== e),
|
|
573
|
+
return this.pendingControls = this.pendingControls.filter((t) => t.taskId !== e), H(`task aborted before start id=${e} reason=${t}`), r.reject(Error(t)), !0;
|
|
568
574
|
}
|
|
569
575
|
if (this.active?.id !== e || !this.worker) return !1;
|
|
570
576
|
try {
|
|
@@ -572,13 +578,13 @@ var Ze = "\n .overlay {\n position: fixed;\n __flaxia_position__;\n pa
|
|
|
572
578
|
id: e,
|
|
573
579
|
type: "abort",
|
|
574
580
|
reason: t
|
|
575
|
-
}),
|
|
581
|
+
}), H(`task abort sent id=${e} reason=${t}`), !0;
|
|
576
582
|
} catch {
|
|
577
583
|
return !1;
|
|
578
584
|
}
|
|
579
585
|
}
|
|
580
586
|
handleWorkerError(e) {
|
|
581
|
-
|
|
587
|
+
H(`worker error error=${e.message}`);
|
|
582
588
|
let t = this.active;
|
|
583
589
|
this.cleanupWorker(), t && (clearTimeout(t.timer), this.active = null, t.reject(e), this.dequeue());
|
|
584
590
|
}
|
|
@@ -587,13 +593,13 @@ var Ze = "\n .overlay {\n position: fixed;\n __flaxia_position__;\n pa
|
|
|
587
593
|
e && e.job();
|
|
588
594
|
}
|
|
589
595
|
cleanupWorker() {
|
|
590
|
-
this.worker &&= (this.worker.terminate(), null), this.initWorker();
|
|
596
|
+
this.worker &&= (this.worker.terminate(), null), this._modelCacheSnapshot = null, this.initWorker();
|
|
591
597
|
}
|
|
592
598
|
terminate() {
|
|
593
599
|
let e = this.queue;
|
|
594
600
|
this.queue = [], this.pendingControls = [];
|
|
595
601
|
for (let t of e) t.reject(/* @__PURE__ */ Error("TERMINATED"));
|
|
596
|
-
this.active &&= (clearTimeout(this.active.timer), this.active.reject(/* @__PURE__ */ Error("TERMINATED")), null), this.worker &&= (this.worker.terminate(), null);
|
|
602
|
+
this.active &&= (clearTimeout(this.active.timer), this.active.reject(/* @__PURE__ */ Error("TERMINATED")), null), this.worker &&= (this.worker.terminate(), null), this._modelCacheSnapshot = null;
|
|
597
603
|
}
|
|
598
604
|
resume() {
|
|
599
605
|
this.worker || this.initWorker();
|
|
@@ -601,26 +607,577 @@ var Ze = "\n .overlay {\n position: fixed;\n __flaxia_position__;\n pa
|
|
|
601
607
|
get lastCpuLoad() {
|
|
602
608
|
return this._lastCpuLoad;
|
|
603
609
|
}
|
|
604
|
-
|
|
610
|
+
get hasCpuLoadSample() {
|
|
611
|
+
return this._hasCpuLoadSample;
|
|
612
|
+
}
|
|
613
|
+
get modelCacheSnapshot() {
|
|
614
|
+
let e = this._modelCacheSnapshot;
|
|
615
|
+
return !e || e.expiresAt <= Date.now() ? null : e;
|
|
616
|
+
}
|
|
617
|
+
}, U = null, mt = null;
|
|
618
|
+
function W(e, t, n, r, i, a) {
|
|
619
|
+
return {
|
|
620
|
+
value: e,
|
|
621
|
+
unit: t,
|
|
622
|
+
source: n,
|
|
623
|
+
sampledAt: r,
|
|
624
|
+
expiresAt: i,
|
|
625
|
+
sampleCount: a
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
function G(e, t, n) {
|
|
629
|
+
return W(null, e, "unknown", t, t + n, 0);
|
|
630
|
+
}
|
|
631
|
+
async function ht(e, t) {
|
|
632
|
+
return e ? ((!U || U.expiresAt <= t) && (mt ||= d().then((e) => (U = e, e)).finally(() => {
|
|
633
|
+
mt = null;
|
|
634
|
+
}), U = await mt), U) : null;
|
|
635
|
+
}
|
|
636
|
+
async function gt(e) {
|
|
637
|
+
let t = e.now ?? Date.now(), r = t + n, i = u(), a = i.bytes !== null && i.sampledAt !== null && t - i.sampledAt <= 864e5, s = Number.isFinite(e.deviceMemory) && e.deviceMemory > 0 && e.deviceMemory <= 1024, c = await ht(e.probeGpu === !0, t), l = c?.sampledAt ?? t, d = c?.expiresAt ?? t + 6e5;
|
|
638
|
+
return {
|
|
639
|
+
version: 1,
|
|
640
|
+
sampledAt: t,
|
|
641
|
+
expiresAt: r,
|
|
642
|
+
cpuLoad: typeof e.cpuLoad == "number" && Number.isFinite(e.cpuLoad) && e.cpuLoad >= 0 && e.cpuLoad <= 1 ? W(e.cpuLoad, "ratio", "estimated", t, r, 1) : G("ratio", t, n),
|
|
643
|
+
wasmMemoryLowerBound: a ? W(i.bytes, "bytes", "measured", i.sampledAt, i.sampledAt + o, 1) : G("bytes", t, o),
|
|
644
|
+
deviceMemory: s ? W(e.deviceMemory, "GiB", "estimated", t, t + o, 1) : G("GiB", t, o),
|
|
645
|
+
gpu: {
|
|
646
|
+
status: c?.status ?? "unknown",
|
|
647
|
+
sampledAt: l,
|
|
648
|
+
expiresAt: d,
|
|
649
|
+
architecture: c?.architecture ? W(c.architecture, "text", "measured", l, d, 1) : G("text", l, p),
|
|
650
|
+
maxStorageBufferBindingSize: c?.maxStorageBufferBindingSize !== null && c?.maxStorageBufferBindingSize !== void 0 ? W(c.maxStorageBufferBindingSize, "bytes", "measured", l, d, 1) : G("bytes", l, p),
|
|
651
|
+
computeCompletionMs: c?.computeCompletionMs !== null && c?.computeCompletionMs !== void 0 ? W(c.computeCompletionMs, "ms", "measured", l, d, c.sampleCount) : G("ms", l, p),
|
|
652
|
+
memoryBytes: G("bytes", l, p)
|
|
653
|
+
}
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
//#endregion
|
|
657
|
+
//#region src/swarm/peer-quality.ts
|
|
658
|
+
var _t = 15e3;
|
|
659
|
+
function vt(e) {
|
|
660
|
+
let t = e.filter((e) => Number.isFinite(e) && e >= 0).slice(-5);
|
|
661
|
+
if (!t.length) return [];
|
|
662
|
+
let n = [...t].sort((e, t) => e - t), r = n[Math.floor(n.length / 2)], i = r + Math.max(20, r * 4);
|
|
663
|
+
return t.filter((e) => e <= i);
|
|
664
|
+
}
|
|
665
|
+
function K(e, t) {
|
|
666
|
+
return !Number.isFinite(e) || e < 0 || !Number.isFinite(t) || t <= 0 ? null : e * 8 / t / 1e3;
|
|
667
|
+
}
|
|
668
|
+
function yt(e, t) {
|
|
669
|
+
let n = vt(e);
|
|
670
|
+
if (!n.length) return {
|
|
671
|
+
value: null,
|
|
672
|
+
sampledAt: t,
|
|
673
|
+
sampleCount: 0
|
|
674
|
+
};
|
|
675
|
+
let r = [...n].sort((e, t) => e - t);
|
|
676
|
+
return {
|
|
677
|
+
value: r[Math.floor(r.length / 2)],
|
|
678
|
+
sampledAt: t,
|
|
679
|
+
sampleCount: n.length
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
function bt(e, n, r, i, a) {
|
|
683
|
+
let o = (e, t) => {
|
|
684
|
+
let r = (r) => {
|
|
685
|
+
let i = t?.[r] ?? n;
|
|
686
|
+
return n - i >= 6e4 ? yt([], n) : yt(e[r] ?? [], i);
|
|
687
|
+
};
|
|
688
|
+
return {
|
|
689
|
+
rttMs: r("rttMs"),
|
|
690
|
+
jitterMs: r("jitterMs"),
|
|
691
|
+
sendMbps: r("sendMbps"),
|
|
692
|
+
receiveMbps: r("receiveMbps")
|
|
693
|
+
};
|
|
694
|
+
};
|
|
695
|
+
return {
|
|
696
|
+
version: 1,
|
|
697
|
+
peerNodeId: e,
|
|
698
|
+
sampledAt: n,
|
|
699
|
+
expiresAt: n + t,
|
|
700
|
+
webRtc: o(r, a?.webRtc),
|
|
701
|
+
application: o(i, a?.application)
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
//#endregion
|
|
705
|
+
//#region src/swarm/peer-transport.ts
|
|
706
|
+
var xt = 5e3, q = 16 * 1024, St = l, Ct = 256 * 1024, wt = 1129860166, J = 16, Tt = 2, Et = 64, Dt = "flaxia-swarm-v1", Ot = "flaxia-peer-quality-v1", kt = 128, At = [{ urls: "stun:stun.cloudflare.com:3478" }];
|
|
707
|
+
function jt() {
|
|
708
|
+
return {
|
|
709
|
+
rttMs: [],
|
|
710
|
+
jitterMs: [],
|
|
711
|
+
sendMbps: [],
|
|
712
|
+
receiveMbps: []
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
function Mt(e) {
|
|
716
|
+
if (e.byteLength < J || e.byteLength > 16400) return null;
|
|
717
|
+
let t = new DataView(e);
|
|
718
|
+
if (t.getUint32(0, !0) !== wt) return null;
|
|
719
|
+
let n = t.getUint32(4, !0), r = t.getUint16(8, !0), i = t.getUint16(10, !0), a = t.getUint32(12, !0);
|
|
720
|
+
if (a < 1 || a > St || i < 1 || i !== Math.ceil(a / 16384) || r >= i) return null;
|
|
721
|
+
let o = Math.min(q, a - r * q);
|
|
722
|
+
return e.byteLength - J === o ? {
|
|
723
|
+
messageId: n,
|
|
724
|
+
index: r,
|
|
725
|
+
count: i,
|
|
726
|
+
totalBytes: a,
|
|
727
|
+
payload: new Uint8Array(e, J)
|
|
728
|
+
} : null;
|
|
729
|
+
}
|
|
730
|
+
function Nt(e, t) {
|
|
731
|
+
if (e.byteLength < 1 || e.byteLength > St) throw Error(`swarm peer frame size is outside 1..${St} bytes`);
|
|
732
|
+
let n = Math.ceil(e.byteLength / q), r = [];
|
|
733
|
+
for (let i = 0; i < n; i++) {
|
|
734
|
+
let a = i * q, o = Math.min(a + q, e.byteLength), s = new Uint8Array(e, a, o - a), c = new ArrayBuffer(J + s.byteLength), l = new DataView(c);
|
|
735
|
+
l.setUint32(0, wt, !0), l.setUint32(4, t >>> 0, !0), l.setUint16(8, i, !0), l.setUint16(10, n, !0), l.setUint32(12, e.byteLength, !0), new Uint8Array(c, J).set(s), r.push(c);
|
|
736
|
+
}
|
|
737
|
+
return r;
|
|
738
|
+
}
|
|
739
|
+
var Pt = class {
|
|
740
|
+
constructor() {
|
|
741
|
+
this.assemblies = /* @__PURE__ */ new Map();
|
|
742
|
+
}
|
|
743
|
+
accept(e, t = Date.now()) {
|
|
744
|
+
this.expire(t);
|
|
745
|
+
let n = Mt(e);
|
|
746
|
+
if (!n) return null;
|
|
747
|
+
let r = this.assemblies.get(n.messageId);
|
|
748
|
+
if (!r) {
|
|
749
|
+
if (this.assemblies.size >= Tt) return null;
|
|
750
|
+
r = {
|
|
751
|
+
count: n.count,
|
|
752
|
+
totalBytes: n.totalBytes,
|
|
753
|
+
parts: Array(n.count),
|
|
754
|
+
received: 0,
|
|
755
|
+
receivedBytes: 0,
|
|
756
|
+
createdAt: t
|
|
757
|
+
}, this.assemblies.set(n.messageId, r);
|
|
758
|
+
}
|
|
759
|
+
if (r.count !== n.count || r.totalBytes !== n.totalBytes) return this.assemblies.delete(n.messageId), null;
|
|
760
|
+
let i = r.parts[n.index];
|
|
761
|
+
if (i) return i.byteLength === n.payload.byteLength && i.every((e, t) => e === n.payload[t]) || this.assemblies.delete(n.messageId), null;
|
|
762
|
+
let a = n.payload.slice();
|
|
763
|
+
if (r.parts[n.index] = a, r.received++, r.receivedBytes += a.byteLength, r.receivedBytes > r.totalBytes) return this.assemblies.delete(n.messageId), null;
|
|
764
|
+
if (r.received !== r.count) return null;
|
|
765
|
+
if (r.receivedBytes !== r.totalBytes) return this.assemblies.delete(n.messageId), null;
|
|
766
|
+
let o = new Uint8Array(r.totalBytes), s = 0;
|
|
767
|
+
for (let e of r.parts) {
|
|
768
|
+
if (!e) return this.assemblies.delete(n.messageId), null;
|
|
769
|
+
o.set(e, s), s += e.byteLength;
|
|
770
|
+
}
|
|
771
|
+
return this.assemblies.delete(n.messageId), o.buffer;
|
|
772
|
+
}
|
|
773
|
+
clear() {
|
|
774
|
+
this.assemblies.clear();
|
|
775
|
+
}
|
|
776
|
+
expire(e) {
|
|
777
|
+
for (let [t, n] of this.assemblies) e - n.createdAt > 5e3 * 2 && this.assemblies.delete(t);
|
|
778
|
+
}
|
|
779
|
+
}, Ft = class {
|
|
780
|
+
constructor(e) {
|
|
781
|
+
this.options = e, this.peers = /* @__PURE__ */ new Map(), this.reassembler = new Pt(), this.nextMessageId = 1, this.mode = "undecided", this.closed = !1, this.failed = !1, this.readyPromise = null, this.readyResolve = null, this.readyTimer = null, this.qualityTimer = null, this.samplingQuality = !1;
|
|
782
|
+
}
|
|
783
|
+
get selectedMode() {
|
|
784
|
+
return this.mode;
|
|
785
|
+
}
|
|
786
|
+
async start() {
|
|
787
|
+
if (this.closed || this.peers.size) return;
|
|
788
|
+
if (typeof RTCPeerConnection > "u" && !this.options.createPeerConnection) {
|
|
789
|
+
this.unavailable();
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
let e = [...new Set([this.options.previousNodeId, this.options.nextNodeId])].filter((e) => !!e && e !== this.options.nodeId);
|
|
793
|
+
try {
|
|
794
|
+
for (let t of e) {
|
|
795
|
+
let e = (this.options.createPeerConnection ?? ((e) => new RTCPeerConnection(e)))({ iceServers: At }), n = {
|
|
796
|
+
nodeId: t,
|
|
797
|
+
connection: e,
|
|
798
|
+
channel: null,
|
|
799
|
+
remoteDescriptionSet: !1,
|
|
800
|
+
pendingCandidates: [],
|
|
801
|
+
quality: {
|
|
802
|
+
webRtc: jt(),
|
|
803
|
+
application: jt()
|
|
804
|
+
},
|
|
805
|
+
qualitySampledAt: {
|
|
806
|
+
webRtc: {},
|
|
807
|
+
application: {}
|
|
808
|
+
},
|
|
809
|
+
applicationBytesSent: 0,
|
|
810
|
+
applicationBytesReceived: 0,
|
|
811
|
+
lastApplicationBytesSent: 0,
|
|
812
|
+
lastApplicationBytesReceived: 0,
|
|
813
|
+
nextProbeId: 1
|
|
814
|
+
};
|
|
815
|
+
this.peers.set(t, n), e.onicecandidate = (e) => {
|
|
816
|
+
let n = e.candidate;
|
|
817
|
+
this.options.onSignal(t, {
|
|
818
|
+
kind: "candidate",
|
|
819
|
+
candidate: n?.candidate ? {
|
|
820
|
+
candidate: n.candidate,
|
|
821
|
+
sdpMid: n.sdpMid,
|
|
822
|
+
sdpMLineIndex: n.sdpMLineIndex,
|
|
823
|
+
usernameFragment: n.usernameFragment
|
|
824
|
+
} : null
|
|
825
|
+
});
|
|
826
|
+
}, e.ondatachannel = (e) => this.bindChannel(n, e.channel), e.onconnectionstatechange = () => {
|
|
827
|
+
(e.connectionState === "failed" || e.connectionState === "closed") && this.unavailable();
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
for (let e of this.peers.values()) {
|
|
831
|
+
let { nodeId: t, connection: n } = e;
|
|
832
|
+
if (this.options.nodeId.localeCompare(t) < 0) {
|
|
833
|
+
this.bindChannel(e, n.createDataChannel(Dt, { ordered: !0 }));
|
|
834
|
+
let r = await n.createOffer();
|
|
835
|
+
if (this.closed || this.failed) return;
|
|
836
|
+
await n.setLocalDescription(r);
|
|
837
|
+
let i = n.localDescription;
|
|
838
|
+
if (!i?.sdp || i.type !== "offer" && i.type !== "answer") throw Error("empty local SDP offer");
|
|
839
|
+
this.options.onSignal(t, {
|
|
840
|
+
kind: "description",
|
|
841
|
+
description: {
|
|
842
|
+
type: i.type,
|
|
843
|
+
sdp: i.sdp
|
|
844
|
+
}
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
this.resolveReadyIfOpen();
|
|
849
|
+
} catch (e) {
|
|
850
|
+
this.unavailable(e instanceof Error ? e : Error(String(e)));
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
async handleSignal(e, t) {
|
|
854
|
+
if (this.closed || this.failed) return;
|
|
855
|
+
let n = this.peers.get(e);
|
|
856
|
+
if (n) try {
|
|
857
|
+
if (t.kind === "description") {
|
|
858
|
+
await n.connection.setRemoteDescription(t.description), n.remoteDescriptionSet = !0;
|
|
859
|
+
for (let e of n.pendingCandidates.splice(0)) await n.connection.addIceCandidate(e);
|
|
860
|
+
if (t.description.type === "offer") {
|
|
861
|
+
let t = await n.connection.createAnswer();
|
|
862
|
+
await n.connection.setLocalDescription(t);
|
|
863
|
+
let r = n.connection.localDescription;
|
|
864
|
+
if (!r?.sdp || r.type !== "offer" && r.type !== "answer") throw Error("empty local SDP answer");
|
|
865
|
+
this.options.onSignal(e, {
|
|
866
|
+
kind: "description",
|
|
867
|
+
description: {
|
|
868
|
+
type: r.type,
|
|
869
|
+
sdp: r.sdp
|
|
870
|
+
}
|
|
871
|
+
});
|
|
872
|
+
}
|
|
873
|
+
} else if (t.candidate !== null) if (n.remoteDescriptionSet) await n.connection.addIceCandidate(t.candidate);
|
|
874
|
+
else {
|
|
875
|
+
if (n.pendingCandidates.length >= Et) throw Error("too many ICE candidates before remote description");
|
|
876
|
+
n.pendingCandidates.push(t.candidate);
|
|
877
|
+
}
|
|
878
|
+
} catch (e) {
|
|
879
|
+
this.unavailable(e instanceof Error ? e : Error(String(e)));
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
waitUntilReady(e = this.options.connectTimeoutMs ?? 5e3) {
|
|
883
|
+
return this.mode === "undecided" ? this.readyPromise ? this.readyPromise : this.failed || this.closed || !this.peers.size ? Promise.resolve(!1) : this.allPeersOpen() ? Promise.resolve(!0) : (this.readyPromise = new Promise((t) => {
|
|
884
|
+
this.readyResolve = t, this.readyTimer = setTimeout(() => this.resolveReady(this.allPeersOpen()), e);
|
|
885
|
+
}), this.readyPromise) : Promise.resolve(this.mode === "peer");
|
|
886
|
+
}
|
|
887
|
+
selectMode(e) {
|
|
888
|
+
if (!(this.closed || this.mode !== "undecided")) {
|
|
889
|
+
if (this.mode = e, e === "relay") {
|
|
890
|
+
this.stopQualitySampling(), this.closePeerConnections();
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
this.allPeersOpen() ? this.startQualitySampling() : this.unavailable(/* @__PURE__ */ Error("peer mode selected without every data channel open"));
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
async sendFrame(e) {
|
|
897
|
+
if (this.mode !== "peer") return !1;
|
|
898
|
+
let t = this.options.nextNodeId, n = t ? this.peers.get(t)?.channel : void 0;
|
|
899
|
+
if (!n || n.readyState !== "open") {
|
|
900
|
+
let e = /* @__PURE__ */ Error("swarm peer data channel closed during the session");
|
|
901
|
+
throw this.unavailable(e), e;
|
|
902
|
+
}
|
|
903
|
+
let r = this.nextMessageId++ >>> 0;
|
|
904
|
+
try {
|
|
905
|
+
for (let t of Nt(e, r)) {
|
|
906
|
+
if (await this.waitForBuffer(n), n.readyState !== "open") throw Error("swarm peer data channel closed while sending");
|
|
907
|
+
n.send(t);
|
|
908
|
+
}
|
|
909
|
+
let i = t ? this.peers.get(t) : void 0;
|
|
910
|
+
return i && (i.applicationBytesSent += e.byteLength), !0;
|
|
911
|
+
} catch (e) {
|
|
912
|
+
let t = e instanceof Error ? e : Error(String(e));
|
|
913
|
+
throw this.unavailable(t), t;
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
close() {
|
|
917
|
+
this.closed || (this.closed = !0, this.stopQualitySampling(), this.resolveReady(!1), this.closePeerConnections(), this.reassembler.clear());
|
|
918
|
+
}
|
|
919
|
+
bindChannel(e, t) {
|
|
920
|
+
if (e.channel && e.channel !== t) {
|
|
921
|
+
try {
|
|
922
|
+
t.close();
|
|
923
|
+
} catch {}
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
e.channel = t, t.binaryType = "arraybuffer", t.bufferedAmountLowThreshold = Ct / 2, t.onopen = () => this.resolveReadyIfOpen(), t.onmessage = (t) => {
|
|
927
|
+
if (typeof t.data == "string") {
|
|
928
|
+
this.handleQualityProbe(e, t.data);
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
if (e.nodeId !== this.options.previousNodeId || !(t.data instanceof ArrayBuffer)) return;
|
|
932
|
+
let n = this.reassembler.accept(t.data, this.options.now?.());
|
|
933
|
+
n && (e.applicationBytesReceived += n.byteLength, this.options.onFrame(n));
|
|
934
|
+
}, t.onclose = () => this.unavailable(/* @__PURE__ */ Error("swarm peer data channel closed")), t.onerror = () => this.unavailable(/* @__PURE__ */ Error("swarm peer data channel failed")), this.resolveReadyIfOpen();
|
|
935
|
+
}
|
|
936
|
+
allPeersOpen() {
|
|
937
|
+
return this.peers.size ? [...this.peers.values()].every((e) => e.channel?.readyState === "open") : !1;
|
|
938
|
+
}
|
|
939
|
+
resolveReadyIfOpen() {
|
|
940
|
+
this.allPeersOpen() && this.resolveReady(!0);
|
|
941
|
+
}
|
|
942
|
+
resolveReady(e) {
|
|
943
|
+
this.readyTimer && clearTimeout(this.readyTimer), this.readyTimer = null;
|
|
944
|
+
let t = this.readyResolve;
|
|
945
|
+
this.readyResolve = null, t?.(e && !this.failed && !this.closed);
|
|
946
|
+
}
|
|
947
|
+
unavailable(e = /* @__PURE__ */ Error("swarm peer link unavailable")) {
|
|
948
|
+
this.closed || this.failed || (this.failed = !0, this.stopQualitySampling(), this.resolveReady(!1), this.mode === "peer" && this.options.onFailure(e));
|
|
949
|
+
}
|
|
950
|
+
async waitForBuffer(e) {
|
|
951
|
+
e.bufferedAmount <= 262144 || await new Promise((t, n) => {
|
|
952
|
+
let r = setTimeout(() => i(/* @__PURE__ */ Error("swarm peer send buffer stalled")), xt), i = (i) => {
|
|
953
|
+
clearTimeout(r), e.removeEventListener("bufferedamountlow", a), e.removeEventListener("close", o), i ? n(i) : t();
|
|
954
|
+
}, a = () => i(), o = () => i(/* @__PURE__ */ Error("swarm peer data channel closed while backpressured"));
|
|
955
|
+
e.addEventListener("bufferedamountlow", a, { once: !0 }), e.addEventListener("close", o, { once: !0 });
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
closePeerConnections() {
|
|
959
|
+
this.stopQualitySampling();
|
|
960
|
+
for (let e of this.peers.values()) e.channel?.close(), e.connection.close();
|
|
961
|
+
this.peers.clear();
|
|
962
|
+
}
|
|
963
|
+
startQualitySampling() {
|
|
964
|
+
this.qualityTimer || !this.options.onQuality || (this.samplePeerQuality(), this.qualityTimer = setInterval(() => void this.samplePeerQuality(), _t));
|
|
965
|
+
}
|
|
966
|
+
stopQualitySampling() {
|
|
967
|
+
this.qualityTimer && clearInterval(this.qualityTimer), this.qualityTimer = null;
|
|
968
|
+
for (let e of this.peers.values()) e.pendingProbe = void 0;
|
|
969
|
+
}
|
|
970
|
+
wallNow() {
|
|
971
|
+
return this.options.now?.() ?? Date.now();
|
|
972
|
+
}
|
|
973
|
+
monotonicNow() {
|
|
974
|
+
return this.options.monotonicNow?.() ?? (typeof performance < "u" ? performance.now() : Date.now());
|
|
975
|
+
}
|
|
976
|
+
recordQuality(e, t, n, r) {
|
|
977
|
+
if (!Number.isFinite(r) || r < 0) return;
|
|
978
|
+
let i = e.quality[t][n], a = this.wallNow(), o = e.qualitySampledAt[t][n];
|
|
979
|
+
o !== void 0 && a - o >= 6e4 && (i.length = 0), i.push(r), e.qualitySampledAt[t][n] = a, i.length > 5 && i.splice(0, i.length - 5);
|
|
980
|
+
}
|
|
981
|
+
sendQualityProbe(e) {
|
|
982
|
+
let t = e.channel;
|
|
983
|
+
if (e.pendingProbe && this.monotonicNow() - e.pendingProbe.sentAt > 15e3 * 2 && (e.pendingProbe = void 0), !t || t.readyState !== "open" || t.bufferedAmount > 262144 || e.pendingProbe) return;
|
|
984
|
+
let n = e.nextProbeId++;
|
|
985
|
+
e.pendingProbe = {
|
|
986
|
+
id: n,
|
|
987
|
+
sentAt: this.monotonicNow()
|
|
988
|
+
};
|
|
989
|
+
try {
|
|
990
|
+
t.send(JSON.stringify({
|
|
991
|
+
type: Ot,
|
|
992
|
+
kind: "ping",
|
|
993
|
+
id: n
|
|
994
|
+
}));
|
|
995
|
+
} catch {
|
|
996
|
+
e.pendingProbe = void 0;
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
handleQualityProbe(e, t) {
|
|
1000
|
+
if (t.length > kt) return;
|
|
1001
|
+
let n;
|
|
1002
|
+
try {
|
|
1003
|
+
let e = JSON.parse(t);
|
|
1004
|
+
if (!e || typeof e != "object" || Array.isArray(e)) return;
|
|
1005
|
+
n = e;
|
|
1006
|
+
} catch {
|
|
1007
|
+
return;
|
|
1008
|
+
}
|
|
1009
|
+
if (n.type !== Ot || !Number.isSafeInteger(n.id) || n.id < 1) return;
|
|
1010
|
+
if (n.kind === "ping") {
|
|
1011
|
+
if (e.channel?.readyState !== "open" || e.channel.bufferedAmount > 262144) return;
|
|
1012
|
+
try {
|
|
1013
|
+
e.channel.send(JSON.stringify({
|
|
1014
|
+
type: Ot,
|
|
1015
|
+
kind: "pong",
|
|
1016
|
+
id: n.id
|
|
1017
|
+
}));
|
|
1018
|
+
} catch {}
|
|
1019
|
+
return;
|
|
1020
|
+
}
|
|
1021
|
+
let r = e.pendingProbe;
|
|
1022
|
+
if (n.kind !== "pong" || !r || r.id !== n.id) return;
|
|
1023
|
+
e.pendingProbe = void 0;
|
|
1024
|
+
let i = Math.max(0, this.monotonicNow() - r.sentAt);
|
|
1025
|
+
this.recordQuality(e, "application", "rttMs", i), e.lastApplicationRttMs !== void 0 && this.recordQuality(e, "application", "jitterMs", Math.abs(i - e.lastApplicationRttMs)), e.lastApplicationRttMs = i;
|
|
1026
|
+
}
|
|
1027
|
+
async samplePeerQuality() {
|
|
1028
|
+
if (!(this.closed || this.failed || this.mode !== "peer" || !this.options.onQuality || this.samplingQuality)) {
|
|
1029
|
+
this.samplingQuality = !0;
|
|
1030
|
+
try {
|
|
1031
|
+
let e = this.wallNow(), t = [];
|
|
1032
|
+
for (let n of this.peers.values()) {
|
|
1033
|
+
if (n.channel?.readyState !== "open") continue;
|
|
1034
|
+
this.sendQualityProbe(n);
|
|
1035
|
+
let r = this.monotonicNow();
|
|
1036
|
+
if (await this.sampleWebRtc(n, r), n.lastApplicationSampleAt !== void 0) {
|
|
1037
|
+
let e = r - n.lastApplicationSampleAt, t = K(n.applicationBytesSent - n.lastApplicationBytesSent, e), i = K(n.applicationBytesReceived - n.lastApplicationBytesReceived, e);
|
|
1038
|
+
t !== null && this.recordQuality(n, "application", "sendMbps", t), i !== null && this.recordQuality(n, "application", "receiveMbps", i);
|
|
1039
|
+
}
|
|
1040
|
+
n.lastApplicationSampleAt = r, n.lastApplicationBytesSent = n.applicationBytesSent, n.lastApplicationBytesReceived = n.applicationBytesReceived, t.push(bt(n.nodeId, e, n.quality.webRtc, n.quality.application, n.qualitySampledAt));
|
|
1041
|
+
}
|
|
1042
|
+
t.length && this.options.onQuality(t.slice(0, 2));
|
|
1043
|
+
} finally {
|
|
1044
|
+
this.samplingQuality = !1;
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
async sampleWebRtc(e, t) {
|
|
1049
|
+
try {
|
|
1050
|
+
let n = await e.connection.getStats(), r = [];
|
|
1051
|
+
n.forEach((e) => r.push(e));
|
|
1052
|
+
let i = r.filter((e) => e.type === "candidate-pair" && e.state === "succeeded"), a = i.find((e) => e.selected === !0) ?? i.find((e) => e.nominated === !0) ?? i[0], o = a?.currentRoundTripTime;
|
|
1053
|
+
typeof o == "number" && Number.isFinite(o) && o >= 0 && this.recordQuality(e, "webRtc", "rttMs", o * 1e3);
|
|
1054
|
+
let s = a?.availableOutgoingBitrate;
|
|
1055
|
+
typeof s == "number" && Number.isFinite(s) && s >= 0 && this.recordQuality(e, "webRtc", "sendMbps", s / 1e6);
|
|
1056
|
+
let c = a?.availableIncomingBitrate;
|
|
1057
|
+
typeof c == "number" && Number.isFinite(c) && c >= 0 && this.recordQuality(e, "webRtc", "receiveMbps", c / 1e6);
|
|
1058
|
+
let l = r.filter((e) => e.type === "data-channel"), u = (e) => {
|
|
1059
|
+
let t = l.map((t) => t[e]).filter((e) => typeof e == "number" && Number.isFinite(e) && e >= 0);
|
|
1060
|
+
return t.length ? t.reduce((e, t) => e + t, 0) : void 0;
|
|
1061
|
+
}, d = u("bytesSent"), f = u("bytesReceived");
|
|
1062
|
+
if (e.lastRtcSampleAt !== void 0) {
|
|
1063
|
+
let n = t - e.lastRtcSampleAt;
|
|
1064
|
+
if (d !== void 0 && e.lastRtcBytesSent !== void 0 && s === void 0) {
|
|
1065
|
+
let t = K(d - e.lastRtcBytesSent, n);
|
|
1066
|
+
t !== null && this.recordQuality(e, "webRtc", "sendMbps", t);
|
|
1067
|
+
}
|
|
1068
|
+
if (f !== void 0 && e.lastRtcBytesReceived !== void 0 && c === void 0) {
|
|
1069
|
+
let t = K(f - e.lastRtcBytesReceived, n);
|
|
1070
|
+
t !== null && this.recordQuality(e, "webRtc", "receiveMbps", t);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
d !== void 0 && (e.lastRtcBytesSent = d), f !== void 0 && (e.lastRtcBytesReceived = f), e.lastRtcSampleAt = t;
|
|
1074
|
+
} catch {}
|
|
1075
|
+
}
|
|
1076
|
+
};
|
|
1077
|
+
function It(e, t) {
|
|
1078
|
+
if (!h(e)) return !1;
|
|
1079
|
+
let n = e;
|
|
1080
|
+
return n.type === "swarm-peer-signal" && n.taskId === t.taskId && n.sessionId === t.sessionId && n.attemptId === t.attemptId && n.toNodeId === t.nodeId && typeof n.fromNodeId == "string" && t.peers.includes(n.fromNodeId) && typeof n.signal == "object" && n.signal !== null;
|
|
1081
|
+
}
|
|
1082
|
+
//#endregion
|
|
1083
|
+
//#region src/client/mobile-lifecycle.ts
|
|
1084
|
+
var Lt = .25, Rt = .08, zt = .45;
|
|
1085
|
+
function Bt(e, t) {
|
|
1086
|
+
let n = e.batteryCharging === !1, r = n && typeof e.batteryLevel == "number" && e.batteryLevel <= Lt, i = n && typeof e.batteryLevel == "number" && e.batteryLevel <= Rt, a = e.effectiveType === "slow-2g" || e.effectiveType === "2g", o = r || a || e.saveData === !0;
|
|
1087
|
+
return {
|
|
1088
|
+
suspend: e.hidden || e.pageHidden || !e.online || i,
|
|
1089
|
+
constrained: o,
|
|
1090
|
+
maxCpuLoad: o ? Math.min(t ?? zt, zt) : t
|
|
1091
|
+
};
|
|
1092
|
+
}
|
|
1093
|
+
//#endregion
|
|
1094
|
+
//#region src/client/SignalingClient.ts
|
|
1095
|
+
var Y = (...e) => console.log("[flaxia-node]", ...e), X = (...e) => console.error("[flaxia-node]", ...e);
|
|
605
1096
|
function Z(e) {
|
|
606
1097
|
let t = /* @__PURE__ */ new Set();
|
|
607
1098
|
if (!Array.isArray(e)) return [];
|
|
608
1099
|
for (let n of e.slice(0, 32)) try {
|
|
609
|
-
let e =
|
|
1100
|
+
let e = _(n);
|
|
610
1101
|
e.origin === n && t.add(e.origin);
|
|
611
1102
|
} catch {}
|
|
612
1103
|
return [...t];
|
|
613
1104
|
}
|
|
614
|
-
var
|
|
1105
|
+
var Vt = "flaxia_node_id", Q = "flaxia_node_token", Ht = class {
|
|
1106
|
+
receiveSwarmEnvelope(t) {
|
|
1107
|
+
let n = e(t);
|
|
1108
|
+
!n || ![...this.swarmSessions.values()].includes(n.sessionId) || (this.swarmInboundChain = this.swarmInboundChain.then(async () => {
|
|
1109
|
+
let e = this.swarmHopKeys.get(n.sessionId);
|
|
1110
|
+
if (e && e.chainLength > 1) {
|
|
1111
|
+
if (!n.mac || !e.inboundKey) return;
|
|
1112
|
+
if (!await a(e.inboundKey, n.sessionId, n.frame, n.mac)) {
|
|
1113
|
+
X(`swarm frame rejected: bad hop MAC sessionId=${n.sessionId}`);
|
|
1114
|
+
return;
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
this.workerPool.sendFrame(n.frame);
|
|
1118
|
+
}).catch(() => {}));
|
|
1119
|
+
}
|
|
1120
|
+
ensureSwarmPeerTransport(e) {
|
|
1121
|
+
let t = typeof e.sessionId == "string" ? e.sessionId : "", n = typeof e.taskId == "string" ? e.taskId : "", r = typeof e.attemptId == "string" ? e.attemptId : "";
|
|
1122
|
+
if (!t || !n || !r || this.swarmPeerTransports.has(t)) return;
|
|
1123
|
+
let i = typeof e.previousNodeId == "string" ? e.previousNodeId : void 0, a = typeof e.nextNodeId == "string" ? e.nextNodeId : void 0, o = [...new Set([i, a].filter((e) => !!e))];
|
|
1124
|
+
this.swarmPeerMetadata.set(t, {
|
|
1125
|
+
taskId: n,
|
|
1126
|
+
attemptId: r,
|
|
1127
|
+
peers: o
|
|
1128
|
+
});
|
|
1129
|
+
let s = new Ft({
|
|
1130
|
+
sessionId: t,
|
|
1131
|
+
taskId: n,
|
|
1132
|
+
attemptId: r,
|
|
1133
|
+
nodeId: this.nodeId,
|
|
1134
|
+
previousNodeId: i,
|
|
1135
|
+
nextNodeId: a,
|
|
1136
|
+
onSignal: (e, i) => this.send({
|
|
1137
|
+
type: "swarm-peer-signal",
|
|
1138
|
+
taskId: n,
|
|
1139
|
+
sessionId: t,
|
|
1140
|
+
attemptId: r,
|
|
1141
|
+
toNodeId: e,
|
|
1142
|
+
signal: i
|
|
1143
|
+
}),
|
|
1144
|
+
onFrame: (e) => this.receiveSwarmEnvelope(e),
|
|
1145
|
+
onQuality: (e) => this.send({
|
|
1146
|
+
type: "swarm-peer-quality",
|
|
1147
|
+
taskId: n,
|
|
1148
|
+
sessionId: t,
|
|
1149
|
+
attemptId: r,
|
|
1150
|
+
reports: e
|
|
1151
|
+
}),
|
|
1152
|
+
onFailure: (e) => {
|
|
1153
|
+
this.swarmFailureReported.add(t), this.send({
|
|
1154
|
+
type: "swarm-error",
|
|
1155
|
+
taskId: n,
|
|
1156
|
+
sessionId: t,
|
|
1157
|
+
attemptId: r,
|
|
1158
|
+
error: e.message
|
|
1159
|
+
});
|
|
1160
|
+
}
|
|
1161
|
+
});
|
|
1162
|
+
this.swarmPeerTransports.set(t, s), s.start();
|
|
1163
|
+
}
|
|
1164
|
+
handleSwarmPeerSignal(e) {
|
|
1165
|
+
let t = typeof e.sessionId == "string" ? e.sessionId : "", n = this.swarmPeerMetadata.get(t), r = this.swarmPeerTransports.get(t);
|
|
1166
|
+
!n || !r || !It(e, {
|
|
1167
|
+
...n,
|
|
1168
|
+
sessionId: t,
|
|
1169
|
+
nodeId: this.nodeId
|
|
1170
|
+
}) || r.handleSignal(e.fromNodeId, e.signal);
|
|
1171
|
+
}
|
|
615
1172
|
retireSwarmSession(e) {
|
|
616
|
-
this.swarmHopKeys.delete(e), this.retiredSwarmSessions.add(e), this.retiredSwarmSessions.size > 64 && this.retiredSwarmSessions.delete(this.retiredSwarmSessions.values().next().value);
|
|
1173
|
+
this.swarmHopKeys.delete(e), this.swarmPeerTransports.get(e)?.close(), this.swarmPeerTransports.delete(e), this.swarmPeerMetadata.delete(e), this.swarmFailureReported.delete(e), this.retiredSwarmSessions.add(e), this.retiredSwarmSessions.size > 64 && this.retiredSwarmSessions.delete(this.retiredSwarmSessions.values().next().value);
|
|
617
1174
|
}
|
|
618
1175
|
constructor(e, t, n) {
|
|
619
|
-
this.config = e, this.workerPool = t, this.nodeId = n, this.ws = null, this.reconnectAttempts = 0, this.MAX_RECONNECT_DELAY = 3e4, this.destroyed = !1, this.suspended = !1, this.
|
|
1176
|
+
this.config = e, this.workerPool = t, this.nodeId = n, this.ws = null, this.reconnectAttempts = 0, this.MAX_RECONNECT_DELAY = 3e4, this.destroyed = !1, this.suspended = !1, this.lifecycleCleanup = [], this.lifecyclePageHidden = !1, this.lifecycleOffline = !1, this.lifecycleEpoch = 0, this.batteryState = null, this.networkState = null, this.inflightTasks = /* @__PURE__ */ new Set(), this.abortedTasks = /* @__PURE__ */ new Set(), this.swarmSessions = /* @__PURE__ */ new Map(), this.retiredSwarmSessions = /* @__PURE__ */ new Set(), this.swarmHopKeys = /* @__PURE__ */ new Map(), this.swarmPeerTransports = /* @__PURE__ */ new Map(), this.swarmPeerMetadata = /* @__PURE__ */ new Map(), this.swarmFailureReported = /* @__PURE__ */ new Set(), this.swarmInboundChain = Promise.resolve(), this.swarmOutboundChain = Promise.resolve(), this.attempts = /* @__PURE__ */ new Map(), this.cachedToken = null;
|
|
620
1177
|
}
|
|
621
1178
|
async connect() {
|
|
622
1179
|
if (this.destroyed) return;
|
|
623
|
-
if (
|
|
1180
|
+
if (z() !== "granted") {
|
|
624
1181
|
this.disconnect();
|
|
625
1182
|
return;
|
|
626
1183
|
}
|
|
@@ -632,102 +1189,109 @@ var et = "flaxia_node_id", tt = "flaxia_node_token", nt = class {
|
|
|
632
1189
|
} catch {}
|
|
633
1190
|
this.ws = null;
|
|
634
1191
|
}
|
|
635
|
-
this.
|
|
636
|
-
let
|
|
637
|
-
if (
|
|
1192
|
+
if (this.setupMobileLifecycleHandlers(), this.suspended) return;
|
|
1193
|
+
let e = await this.obtainToken();
|
|
1194
|
+
if (this.destroyed || this.suspended) return;
|
|
1195
|
+
if (z() !== "granted") {
|
|
638
1196
|
Y("connect cancelled because consent was revoked while obtaining a token");
|
|
639
1197
|
return;
|
|
640
1198
|
}
|
|
641
|
-
if (!
|
|
1199
|
+
if (!e) {
|
|
642
1200
|
X("token acquisition failed; scheduling reconnect"), this.scheduleReconnect();
|
|
643
1201
|
return;
|
|
644
1202
|
}
|
|
645
|
-
let
|
|
646
|
-
|
|
647
|
-
let
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
},
|
|
651
|
-
if (this.ws !==
|
|
1203
|
+
let t = i(this.config.orchestratorUrl, "/crowd/signal"), n = new WebSocket(t, s(e.token));
|
|
1204
|
+
n.binaryType = "arraybuffer", this.ws = n;
|
|
1205
|
+
let r = !1;
|
|
1206
|
+
n.onopen = () => {
|
|
1207
|
+
r = !0, this.reconnectAttempts = 0, Y(`signal connected ${t}`), this.sendHeartbeat(n);
|
|
1208
|
+
}, n.onmessage = async (e) => {
|
|
1209
|
+
if (this.ws !== n) return;
|
|
652
1210
|
if (typeof e.data != "string") {
|
|
653
|
-
|
|
654
|
-
if (!r || ![...this.swarmSessions.values()].includes(r.sessionId)) return;
|
|
655
|
-
this.swarmInboundChain = this.swarmInboundChain.then(async () => {
|
|
656
|
-
let e = this.swarmHopKeys.get(r.sessionId);
|
|
657
|
-
if (e && e.chainLength > 1) {
|
|
658
|
-
if (!r.mac || !e.inboundKey) return;
|
|
659
|
-
if (!await t(e.inboundKey, r.sessionId, r.frame, r.mac)) {
|
|
660
|
-
X(`swarm frame rejected: bad hop MAC sessionId=${r.sessionId}`);
|
|
661
|
-
return;
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
this.workerPool.sendFrame(r.frame);
|
|
665
|
-
}).catch(() => {});
|
|
1211
|
+
this.receiveSwarmEnvelope(e.data);
|
|
666
1212
|
return;
|
|
667
1213
|
}
|
|
668
|
-
let
|
|
1214
|
+
let t;
|
|
669
1215
|
try {
|
|
670
|
-
|
|
1216
|
+
t = JSON.parse(e.data);
|
|
671
1217
|
} catch {
|
|
672
1218
|
return;
|
|
673
1219
|
}
|
|
674
|
-
if (
|
|
675
|
-
this.
|
|
676
|
-
type: "pong",
|
|
677
|
-
cpuLoad: this.workerPool.lastCpuLoad
|
|
678
|
-
});
|
|
1220
|
+
if (t.type === "ping") {
|
|
1221
|
+
this.sendHeartbeat(n);
|
|
679
1222
|
return;
|
|
680
1223
|
}
|
|
681
|
-
if (
|
|
682
|
-
let e =
|
|
1224
|
+
if (t.type === "task") {
|
|
1225
|
+
let e = t;
|
|
683
1226
|
Y(`task received taskId=${e.taskId} workload=${e.workload} timeoutMs=${e.timeoutMs ?? "default"}`), typeof e.attemptId == "string" && this.attempts.set(e.taskId, e.attemptId);
|
|
684
|
-
let
|
|
1227
|
+
let n = e.attemptId ?? this.attempts.get(e.taskId);
|
|
685
1228
|
try {
|
|
686
1229
|
await this.handleTask(e);
|
|
687
|
-
} catch (
|
|
688
|
-
let i =
|
|
1230
|
+
} catch (r) {
|
|
1231
|
+
let i = r instanceof Error ? r.message : String(r);
|
|
689
1232
|
if (this.abortedTasks.delete(e.taskId)) {
|
|
690
1233
|
Y(`task stopped on coordinator abort taskId=${e.taskId} error=${i}`);
|
|
691
1234
|
return;
|
|
692
1235
|
}
|
|
693
1236
|
X(`task failed taskId=${e.taskId} workload=${e.workload} error=${i}`), this.send({
|
|
694
1237
|
type: "error",
|
|
695
|
-
taskId: String(
|
|
1238
|
+
taskId: String(t.taskId ?? ""),
|
|
696
1239
|
error: i,
|
|
697
|
-
attemptId:
|
|
1240
|
+
attemptId: n
|
|
698
1241
|
});
|
|
699
1242
|
}
|
|
700
1243
|
return;
|
|
701
1244
|
}
|
|
702
|
-
if (
|
|
703
|
-
let e = String(
|
|
704
|
-
if (!e || typeof
|
|
705
|
-
if (
|
|
706
|
-
inboundKey: typeof
|
|
707
|
-
outboundKey: typeof
|
|
708
|
-
chainLength: typeof
|
|
709
|
-
}), typeof
|
|
710
|
-
this.workerPool.sendControl(
|
|
1245
|
+
if (t.type === "swarm-init" || t.type === "swarm-slice") {
|
|
1246
|
+
let e = String(t.taskId ?? "");
|
|
1247
|
+
if (!e || typeof t.sessionId != "string" || this.retiredSwarmSessions.has(t.sessionId)) return;
|
|
1248
|
+
if (t.type === "swarm-slice" && (this.ensureSwarmPeerTransport(t), this.swarmHopKeys.set(t.sessionId, {
|
|
1249
|
+
inboundKey: typeof t.inboundKey == "string" ? t.inboundKey : void 0,
|
|
1250
|
+
outboundKey: typeof t.outboundKey == "string" ? t.outboundKey : void 0,
|
|
1251
|
+
chainLength: typeof t.chainLength == "number" ? t.chainLength : 1
|
|
1252
|
+
})), typeof t.attemptId == "string" && this.attempts.set(e, t.attemptId), this.swarmSessions.get(e) === t.sessionId) {
|
|
1253
|
+
this.workerPool.sendControl(t, t.sessionId);
|
|
711
1254
|
return;
|
|
712
1255
|
}
|
|
713
|
-
this.startSwarm(e,
|
|
1256
|
+
this.startSwarm(e, t);
|
|
1257
|
+
return;
|
|
1258
|
+
}
|
|
1259
|
+
if (t.type === "swarm-peer-signal") {
|
|
1260
|
+
this.handleSwarmPeerSignal(t);
|
|
1261
|
+
return;
|
|
1262
|
+
}
|
|
1263
|
+
if (t.type === "swarm-transport") {
|
|
1264
|
+
let e = typeof t.sessionId == "string" ? t.sessionId : "", n = this.swarmPeerMetadata.get(e), r = this.swarmPeerTransports.get(e);
|
|
1265
|
+
n && r && t.taskId === n.taskId && t.attemptId === n.attemptId && (t.mode === "peer" || t.mode === "relay") && r.selectMode(t.mode);
|
|
1266
|
+
return;
|
|
1267
|
+
}
|
|
1268
|
+
if (t.type === "swarm-flow") {
|
|
1269
|
+
let e = typeof t.taskId == "string" ? t.taskId : "", n = typeof t.sessionId == "string" ? t.sessionId : "", r = typeof t.attemptId == "string" ? t.attemptId : "";
|
|
1270
|
+
e && n && this.swarmSessions.get(e) === n && this.attempts.get(e) === r && typeof t.paused == "boolean" && this.workerPool.sendControl(t, n);
|
|
714
1271
|
return;
|
|
715
1272
|
}
|
|
716
|
-
if (
|
|
717
|
-
|
|
1273
|
+
if (t.type === "task-flow") {
|
|
1274
|
+
let e = typeof t.taskId == "string" ? t.taskId : "", n = typeof t.attemptId == "string" ? t.attemptId : "";
|
|
1275
|
+
e && this.attempts.get(e) === n && typeof t.paused == "boolean" && this.workerPool.setTokenFlow(e, t.paused);
|
|
718
1276
|
return;
|
|
719
1277
|
}
|
|
720
|
-
if (
|
|
721
|
-
|
|
722
|
-
e && this.swarmSessions.get(e) === r.sessionId && this.workerPool.sendControl(r, r.sessionId);
|
|
1278
|
+
if (t.type === "swarm-start") {
|
|
1279
|
+
this.swarmSessions.get(String(t.taskId)) === t.sessionId && this.workerPool.sendControl(t, t.sessionId);
|
|
723
1280
|
return;
|
|
724
1281
|
}
|
|
725
|
-
if (
|
|
726
|
-
|
|
1282
|
+
if (t.type === "swarm-error") {
|
|
1283
|
+
let e = String(t.taskId ?? "");
|
|
1284
|
+
e && this.swarmSessions.get(e) === t.sessionId && this.workerPool.sendControl(t, t.sessionId);
|
|
727
1285
|
return;
|
|
728
1286
|
}
|
|
729
|
-
|
|
730
|
-
|
|
1287
|
+
if (t.type === "abort") {
|
|
1288
|
+
this.handleAbort(t);
|
|
1289
|
+
return;
|
|
1290
|
+
}
|
|
1291
|
+
}, n.onerror = () => {
|
|
1292
|
+
this.ws === n && X("signal websocket error");
|
|
1293
|
+
}, n.onclose = (e) => {
|
|
1294
|
+
n.onclose = null, this.ws === n && (this.ws = null, r || (this.cachedToken = null), !this.destroyed && (Y(`signal disconnected code=${e.code} reason=${JSON.stringify(e.reason)} clean=${e.wasClean}; scheduling reconnect attempt=${this.reconnectAttempts + 1}`), this.scheduleReconnect()));
|
|
731
1295
|
};
|
|
732
1296
|
}
|
|
733
1297
|
handleAbort(e) {
|
|
@@ -738,6 +1302,20 @@ var et = "flaxia_node_id", tt = "flaxia_node_token", nt = class {
|
|
|
738
1302
|
let i = r ?? t;
|
|
739
1303
|
r && this.retireSwarmSession(r), this.workerPool.abort(i, n) && this.abortedTasks.add(i), Y(`task abort received taskId=${t} error=${n}`);
|
|
740
1304
|
}
|
|
1305
|
+
async sendHeartbeat(e) {
|
|
1306
|
+
if (this.ws !== e || e.readyState !== WebSocket.OPEN || z() !== "granted") return;
|
|
1307
|
+
let t = (this.config.capabilities ?? ["ai-inference", "image-process"]).includes("swarm-inference") && this.config.allowModelDownload === !0, n = navigator.deviceMemory, r = await gt({
|
|
1308
|
+
cpuLoad: this.workerPool.hasCpuLoadSample ? this.workerPool.lastCpuLoad : null,
|
|
1309
|
+
deviceMemory: n,
|
|
1310
|
+
probeGpu: t
|
|
1311
|
+
});
|
|
1312
|
+
this.ws !== e || e.readyState !== WebSocket.OPEN || z() !== "granted" || this.send({
|
|
1313
|
+
type: "pong",
|
|
1314
|
+
cpuLoad: this.workerPool.hasCpuLoadSample ? this.workerPool.lastCpuLoad : null,
|
|
1315
|
+
resources: r,
|
|
1316
|
+
modelCache: this.workerPool.modelCacheSnapshot
|
|
1317
|
+
});
|
|
1318
|
+
}
|
|
741
1319
|
scheduleReconnect() {
|
|
742
1320
|
let e = Math.min(1e3 * 2 ** this.reconnectAttempts, this.MAX_RECONNECT_DELAY);
|
|
743
1321
|
setTimeout(() => {
|
|
@@ -745,13 +1323,15 @@ var et = "flaxia_node_id", tt = "flaxia_node_token", nt = class {
|
|
|
745
1323
|
}, e);
|
|
746
1324
|
}
|
|
747
1325
|
disconnect() {
|
|
748
|
-
Y(`disconnect nodeId=${this.nodeId}`), this.destroyed = !0, this.suspended = !1, this.
|
|
1326
|
+
Y(`disconnect nodeId=${this.nodeId}`), this.destroyed = !0, this.suspended = !1, this.removeMobileLifecycleHandlers();
|
|
749
1327
|
try {
|
|
750
1328
|
this.ws?.close();
|
|
751
1329
|
} catch {}
|
|
752
1330
|
this.ws = null;
|
|
1331
|
+
for (let e of this.swarmPeerTransports.values()) e.close();
|
|
1332
|
+
this.swarmPeerTransports.clear(), this.swarmPeerMetadata.clear();
|
|
753
1333
|
try {
|
|
754
|
-
delete window[
|
|
1334
|
+
delete window[Ut];
|
|
755
1335
|
} catch {}
|
|
756
1336
|
try {
|
|
757
1337
|
this.workerPool.terminate();
|
|
@@ -774,36 +1354,41 @@ var et = "flaxia_node_id", tt = "flaxia_node_token", nt = class {
|
|
|
774
1354
|
!this.suspended || this.destroyed || (Y("resumed"), this.suspended = !1, this.workerPool.resume(), this.connect());
|
|
775
1355
|
}
|
|
776
1356
|
async obtainToken() {
|
|
777
|
-
let e = () =>
|
|
1357
|
+
let e = () => z() === "granted";
|
|
778
1358
|
if (!e()) return null;
|
|
779
1359
|
try {
|
|
780
1360
|
if (this.cachedToken && this.cachedToken.expiresAt > Date.now() + 6e4) return Y(`token cached nodeId=${this.cachedToken.nodeId} expiresIn=${Math.round((this.cachedToken.expiresAt - Date.now()) / 1e3)}s`), this.cachedToken;
|
|
781
|
-
let t =
|
|
1361
|
+
let t = f(), n = t >= m, r = this.config.capabilities ?? ["ai-inference", "image-process"], i = n ? [...r] : [];
|
|
782
1362
|
Z(this.config.containerImageOrigins).length === 0 && (i = i.filter((e) => e !== "container"));
|
|
783
1363
|
let a;
|
|
784
1364
|
if (n && r.includes("swarm-inference") && this.config.allowModelDownload === !0) {
|
|
785
|
-
|
|
786
|
-
|
|
1365
|
+
let t = await gt({
|
|
1366
|
+
cpuLoad: this.workerPool.hasCpuLoadSample ? this.workerPool.lastCpuLoad : null,
|
|
1367
|
+
deviceMemory: navigator.deviceMemory,
|
|
1368
|
+
probeGpu: !0
|
|
1369
|
+
});
|
|
1370
|
+
if (!e()) return null;
|
|
1371
|
+
t.gpu.status === "available" ? (a = { webgpu: !0 }, t.gpu.architecture.value && (a.gpuArchitecture = t.gpu.architecture.value), t.gpu.maxStorageBufferBindingSize.value !== null && (a.maxStorageBufferBindingSize = t.gpu.maxStorageBufferBindingSize.value)) : i = i.filter((e) => e !== "swarm-inference");
|
|
787
1372
|
} else i = i.filter((e) => e !== "swarm-inference");
|
|
788
1373
|
Y(`register capability probe capable=${n} wasmMemoryBytes=${t} capabilities=${JSON.stringify(i)} webgpu=${a?.webgpu ?? !1}`);
|
|
789
|
-
let
|
|
1374
|
+
let o = this.config.orchestratorUrl.replace(/\/+$/, "");
|
|
790
1375
|
if (!e()) return null;
|
|
791
|
-
let
|
|
1376
|
+
let s = await fetch(`${o}/crowd/nodes/register`, {
|
|
792
1377
|
method: "POST",
|
|
793
1378
|
headers: { "Content-Type": "application/json" },
|
|
794
1379
|
body: JSON.stringify({
|
|
795
1380
|
siteId: this.config.siteId,
|
|
796
1381
|
capabilities: i,
|
|
797
1382
|
fileSources: Z(this.config.fileSourceOrigins).length > 0,
|
|
798
|
-
wasmMemoryBytes:
|
|
1383
|
+
wasmMemoryBytes: f(),
|
|
799
1384
|
deviceMemory: typeof navigator.deviceMemory == "number" ? navigator.deviceMemory : null,
|
|
800
1385
|
swarm: a
|
|
801
1386
|
})
|
|
802
1387
|
});
|
|
803
1388
|
if (!e()) return null;
|
|
804
|
-
if (!
|
|
805
|
-
let
|
|
806
|
-
return e() ?
|
|
1389
|
+
if (!s.ok) return X(`node register failed HTTP ${s.status} (${o}/crowd/nodes/register)`), null;
|
|
1390
|
+
let c = await s.json();
|
|
1391
|
+
return e() ? c.token ? (typeof c.nodeId == "string" && c.nodeId && (this.nodeId = c.nodeId), this.cachedToken = c, Y(`node registered nodeId=${this.nodeId} expiresIn=${Math.round((c.expiresAt - Date.now()) / 1e3)}s`), c) : (X("node register returned no token"), null) : null;
|
|
807
1392
|
} catch (e) {
|
|
808
1393
|
return X("node register threw", e instanceof Error ? e.message : e), null;
|
|
809
1394
|
}
|
|
@@ -822,11 +1407,22 @@ var et = "flaxia_node_id", tt = "flaxia_node_token", nt = class {
|
|
|
822
1407
|
X(`swarm frame not sent: no hop key sessionId=${e}`);
|
|
823
1408
|
return;
|
|
824
1409
|
}
|
|
825
|
-
|
|
1410
|
+
let i = await r(n.outboundKey, e, t), a = this.swarmPeerTransports.get(e);
|
|
1411
|
+
(!a || !await a.sendFrame(i)) && this.sendBinary(i);
|
|
826
1412
|
return;
|
|
827
1413
|
}
|
|
828
|
-
|
|
829
|
-
|
|
1414
|
+
let i = c(e, t), a = this.swarmPeerTransports.get(e);
|
|
1415
|
+
(!a || !await a.sendFrame(i)) && this.sendBinary(i);
|
|
1416
|
+
}).catch((t) => {
|
|
1417
|
+
let n = this.swarmPeerMetadata.get(e);
|
|
1418
|
+
!n || this.swarmFailureReported.has(e) || (this.swarmFailureReported.add(e), this.send({
|
|
1419
|
+
type: "swarm-error",
|
|
1420
|
+
taskId: n.taskId,
|
|
1421
|
+
sessionId: e,
|
|
1422
|
+
attemptId: n.attemptId,
|
|
1423
|
+
error: t instanceof Error ? t.message : String(t)
|
|
1424
|
+
}));
|
|
1425
|
+
});
|
|
830
1426
|
}
|
|
831
1427
|
async startSwarm(e, t) {
|
|
832
1428
|
let n = t.sessionId;
|
|
@@ -842,12 +1438,26 @@ var et = "flaxia_node_id", tt = "flaxia_node_token", nt = class {
|
|
|
842
1438
|
token: t,
|
|
843
1439
|
attemptId: a
|
|
844
1440
|
});
|
|
845
|
-
}, { maxCpuLoad: this.
|
|
1441
|
+
}, { maxCpuLoad: this.effectiveMaxCpuLoad() }, {
|
|
846
1442
|
onFrame: (e) => this.queueSwarmFrame(n, e),
|
|
847
|
-
onMessage: (e) =>
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
1443
|
+
onMessage: (e) => {
|
|
1444
|
+
let t = e && typeof e == "object" && !("attemptId" in e) ? {
|
|
1445
|
+
...e,
|
|
1446
|
+
attemptId: a
|
|
1447
|
+
} : e;
|
|
1448
|
+
if (t?.type === "swarm-ready") {
|
|
1449
|
+
let e = this.swarmPeerTransports.get(n);
|
|
1450
|
+
(async () => {
|
|
1451
|
+
let n = e ? await e.waitUntilReady() : !1;
|
|
1452
|
+
this.send({
|
|
1453
|
+
...t,
|
|
1454
|
+
peerReady: n
|
|
1455
|
+
});
|
|
1456
|
+
})();
|
|
1457
|
+
return;
|
|
1458
|
+
}
|
|
1459
|
+
this.send(t);
|
|
1460
|
+
}
|
|
851
1461
|
});
|
|
852
1462
|
this.abortedTasks.delete(n) || this.send({
|
|
853
1463
|
type: "result",
|
|
@@ -882,7 +1492,7 @@ var et = "flaxia_node_id", tt = "flaxia_node_token", nt = class {
|
|
|
882
1492
|
attemptId: n
|
|
883
1493
|
});
|
|
884
1494
|
}, {
|
|
885
|
-
maxCpuLoad: this.
|
|
1495
|
+
maxCpuLoad: this.effectiveMaxCpuLoad(),
|
|
886
1496
|
fileSourceOrigins: Z(this.config.fileSourceOrigins),
|
|
887
1497
|
containerImageOrigins: Z(this.config.containerImageOrigins)
|
|
888
1498
|
});
|
|
@@ -896,74 +1506,116 @@ var et = "flaxia_node_id", tt = "flaxia_node_token", nt = class {
|
|
|
896
1506
|
this.inflightTasks.delete(e.taskId), this.attempts.delete(e.taskId);
|
|
897
1507
|
}
|
|
898
1508
|
}
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
1509
|
+
listenForLifecycle(e, t, n) {
|
|
1510
|
+
e.addEventListener(t, n), this.lifecycleCleanup.push(() => e.removeEventListener(t, n));
|
|
1511
|
+
}
|
|
1512
|
+
setupMobileLifecycleHandlers() {
|
|
1513
|
+
this.removeMobileLifecycleHandlers();
|
|
1514
|
+
let e = this.lifecycleEpoch;
|
|
1515
|
+
this.lifecyclePageHidden = document.hidden, this.lifecycleOffline = navigator.onLine === !1;
|
|
1516
|
+
let t = navigator;
|
|
1517
|
+
if (this.networkState = t.connection ?? null, this.listenForLifecycle(document, "visibilitychange", () => {
|
|
1518
|
+
this.lifecyclePageHidden = document.hidden, this.refreshMobileLifecycle();
|
|
1519
|
+
}), this.listenForLifecycle(window, "offline", () => {
|
|
1520
|
+
this.lifecycleOffline = !0, this.refreshMobileLifecycle();
|
|
1521
|
+
}), this.listenForLifecycle(window, "online", () => {
|
|
1522
|
+
this.lifecycleOffline = !1, this.refreshMobileLifecycle();
|
|
1523
|
+
}), this.listenForLifecycle(window, "pagehide", () => {
|
|
1524
|
+
this.lifecyclePageHidden = !0, this.refreshMobileLifecycle();
|
|
1525
|
+
}), this.listenForLifecycle(window, "pageshow", () => {
|
|
1526
|
+
this.lifecyclePageHidden = !1, this.refreshMobileLifecycle();
|
|
1527
|
+
}), this.networkState && this.listenForLifecycle(this.networkState, "change", () => this.refreshMobileLifecycle()), typeof t.getBattery == "function") try {
|
|
1528
|
+
t.getBattery.call(navigator).then((t) => {
|
|
1529
|
+
if (this.destroyed || e !== this.lifecycleEpoch) return;
|
|
1530
|
+
this.batteryState = t;
|
|
1531
|
+
let n = () => this.refreshMobileLifecycle();
|
|
1532
|
+
this.listenForLifecycle(t, "levelchange", n), this.listenForLifecycle(t, "chargingchange", n), this.refreshMobileLifecycle();
|
|
1533
|
+
}).catch(() => {});
|
|
1534
|
+
} catch {}
|
|
1535
|
+
this.refreshMobileLifecycle();
|
|
1536
|
+
}
|
|
1537
|
+
removeMobileLifecycleHandlers() {
|
|
1538
|
+
this.lifecycleEpoch++;
|
|
1539
|
+
for (let e of this.lifecycleCleanup.splice(0)) e();
|
|
1540
|
+
this.batteryState = null, this.networkState = null;
|
|
1541
|
+
}
|
|
1542
|
+
mobileLifecycleDecision() {
|
|
1543
|
+
return Bt({
|
|
1544
|
+
hidden: document.hidden,
|
|
1545
|
+
pageHidden: this.lifecyclePageHidden,
|
|
1546
|
+
online: !this.lifecycleOffline && navigator.onLine !== !1,
|
|
1547
|
+
batteryLevel: this.batteryState?.level,
|
|
1548
|
+
batteryCharging: this.batteryState?.charging,
|
|
1549
|
+
effectiveType: this.networkState?.effectiveType,
|
|
1550
|
+
saveData: this.networkState?.saveData
|
|
1551
|
+
}, this.config.maxCpuLoad);
|
|
903
1552
|
}
|
|
904
|
-
|
|
905
|
-
this.
|
|
1553
|
+
effectiveMaxCpuLoad() {
|
|
1554
|
+
return this.mobileLifecycleDecision().maxCpuLoad;
|
|
906
1555
|
}
|
|
907
|
-
|
|
908
|
-
|
|
1556
|
+
refreshMobileLifecycle() {
|
|
1557
|
+
this.mobileLifecycleDecision().suspend ? this.suspend() : this.suspended && this.resume();
|
|
1558
|
+
}
|
|
1559
|
+
}, $ = "__flaxia_node_signal_client", Ut = "__flaxia_node_init_started", Wt = "__flaxia_node_controller", Gt = (e) => {
|
|
1560
|
+
if (z() !== "granted") {
|
|
909
1561
|
X("refusing to start the node without a granted consent record");
|
|
910
1562
|
return;
|
|
911
1563
|
}
|
|
912
|
-
let t = window[
|
|
913
|
-
t && t.disconnect(),
|
|
914
|
-
let n = new URL("./worker.js", "" + import.meta.url).href, r = new
|
|
915
|
-
i || (i =
|
|
916
|
-
let a = new
|
|
917
|
-
window[
|
|
918
|
-
},
|
|
1564
|
+
let t = window[$];
|
|
1565
|
+
t && t.disconnect(), Ge(Q);
|
|
1566
|
+
let n = new URL("./worker.js", "" + import.meta.url).href, r = new pt(n), i = Ue(Vt);
|
|
1567
|
+
i || (i = qe(), We(Vt, i));
|
|
1568
|
+
let a = new Ht(e, r, i);
|
|
1569
|
+
window[$] = a, a.connect();
|
|
1570
|
+
}, Kt = class {
|
|
919
1571
|
constructor(e) {
|
|
920
1572
|
this.config = e;
|
|
921
1573
|
}
|
|
922
1574
|
start() {
|
|
923
|
-
this.isRunning() || !
|
|
1575
|
+
this.isRunning() || !Ae() || Gt(this.config);
|
|
924
1576
|
}
|
|
925
1577
|
stop() {
|
|
926
|
-
let e = window[
|
|
927
|
-
e && e.disconnect(), delete window[
|
|
1578
|
+
let e = window[$];
|
|
1579
|
+
e && e.disconnect(), delete window[$], delete window[Ut];
|
|
928
1580
|
}
|
|
929
1581
|
isRunning() {
|
|
930
|
-
return !!window[
|
|
1582
|
+
return !!window[$];
|
|
931
1583
|
}
|
|
932
1584
|
getConsentState() {
|
|
933
|
-
return
|
|
1585
|
+
return z();
|
|
934
1586
|
}
|
|
935
1587
|
grant() {
|
|
936
|
-
|
|
1588
|
+
Re();
|
|
937
1589
|
}
|
|
938
1590
|
deny() {
|
|
939
|
-
|
|
1591
|
+
Ve(), this.stop(), Ge(Q);
|
|
940
1592
|
}
|
|
941
1593
|
clearConsent() {
|
|
942
|
-
|
|
1594
|
+
He(), this.stop(), Ge(Q);
|
|
943
1595
|
}
|
|
944
|
-
},
|
|
945
|
-
let t = window[
|
|
1596
|
+
}, qt = (e) => {
|
|
1597
|
+
let t = window[Wt];
|
|
946
1598
|
if (t) return t;
|
|
947
|
-
let n = new
|
|
948
|
-
window[
|
|
949
|
-
let r =
|
|
1599
|
+
let n = new Kt(e);
|
|
1600
|
+
window[Wt] = n, window[Ut] = !0;
|
|
1601
|
+
let r = z();
|
|
950
1602
|
if (r === "granted") return n.start(), n;
|
|
951
1603
|
if (r === "denied") return n;
|
|
952
1604
|
if (e.consent.onConsentRequired) return e.consent.onConsentRequired({
|
|
953
1605
|
state: r,
|
|
954
1606
|
accept: () => {
|
|
955
|
-
|
|
1607
|
+
Re(), n.start();
|
|
956
1608
|
},
|
|
957
1609
|
reject: () => {
|
|
958
|
-
|
|
1610
|
+
Ve();
|
|
959
1611
|
}
|
|
960
1612
|
}), n;
|
|
961
1613
|
let i = document.createElement("div");
|
|
962
|
-
return i.id = "flaxia-consent-container", document.body.appendChild(i), new
|
|
963
|
-
|
|
1614
|
+
return i.id = "flaxia-consent-container", document.body.appendChild(i), new ft(i, e.consent, () => {
|
|
1615
|
+
Re(), i.remove(), n.start();
|
|
964
1616
|
}, () => {
|
|
965
|
-
|
|
1617
|
+
Ve(), i.remove();
|
|
966
1618
|
}), n;
|
|
967
1619
|
};
|
|
968
1620
|
//#endregion
|
|
969
|
-
export {
|
|
1621
|
+
export { z as getFlaxiaNodeConsentState, qt as initFlaxiaNode, B as initFlaxiaNodeConsent, Be as setFlaxiaNodeHostManagedConsent };
|