@flaxia/node 0.3.7 → 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.
Files changed (113) hide show
  1. package/README.md +43 -19
  2. package/dist/__tests__/consent-policy.test.d.ts +2 -0
  3. package/dist/__tests__/consent-policy.test.d.ts.map +1 -0
  4. package/dist/assets/VectorStoreEngine.js +140 -85
  5. package/dist/assets/ai-inference.js +336 -40
  6. package/dist/assets/container.js +368 -260
  7. package/dist/assets/egress-guard.js +174 -0
  8. package/dist/assets/image-process.js +184 -19
  9. package/dist/assets/nudenet.js +2 -2
  10. package/dist/assets/webgpuProbe.js +357 -0
  11. package/dist/client/SignalingClient.d.ts +6 -0
  12. package/dist/client/SignalingClient.d.ts.map +1 -1
  13. package/dist/client/__tests__/mobile-lifecycle.test.d.ts +2 -0
  14. package/dist/client/__tests__/mobile-lifecycle.test.d.ts.map +1 -0
  15. package/dist/client/mobile-lifecycle.d.ts +20 -0
  16. package/dist/client/mobile-lifecycle.d.ts.map +1 -0
  17. package/dist/consent/ConsentUI.d.ts +44 -5
  18. package/dist/consent/ConsentUI.d.ts.map +1 -1
  19. package/dist/consent/notice.d.ts +29 -0
  20. package/dist/consent/notice.d.ts.map +1 -0
  21. package/dist/consent/storage.d.ts +91 -7
  22. package/dist/consent/storage.d.ts.map +1 -1
  23. package/dist/executor/WorkerPool.d.ts +42 -2
  24. package/dist/executor/WorkerPool.d.ts.map +1 -1
  25. package/dist/executor/__tests__/WorkerPool.swarm.test.d.ts +13 -0
  26. package/dist/executor/__tests__/WorkerPool.swarm.test.d.ts.map +1 -0
  27. package/dist/executor/__tests__/container-executor.test.d.ts +2 -0
  28. package/dist/executor/__tests__/container-executor.test.d.ts.map +1 -0
  29. package/dist/executor/__tests__/egress-guard.test.d.ts +2 -0
  30. package/dist/executor/__tests__/egress-guard.test.d.ts.map +1 -0
  31. package/dist/executor/__tests__/resourceReporter.test.d.ts +2 -0
  32. package/dist/executor/__tests__/resourceReporter.test.d.ts.map +1 -0
  33. package/dist/executor/__tests__/webgpuProbe.test.d.ts +2 -0
  34. package/dist/executor/__tests__/webgpuProbe.test.d.ts.map +1 -0
  35. package/dist/executor/container-executor.d.ts +49 -1
  36. package/dist/executor/container-executor.d.ts.map +1 -1
  37. package/dist/executor/egress-guard.d.ts +105 -0
  38. package/dist/executor/egress-guard.d.ts.map +1 -0
  39. package/dist/executor/memoryProbe.d.ts +30 -0
  40. package/dist/executor/memoryProbe.d.ts.map +1 -1
  41. package/dist/executor/resourceReporter.d.ts +15 -0
  42. package/dist/executor/resourceReporter.d.ts.map +1 -0
  43. package/dist/executor/throttle.d.ts +62 -4
  44. package/dist/executor/throttle.d.ts.map +1 -1
  45. package/dist/executor/webgpuProbe.d.ts +20 -0
  46. package/dist/executor/webgpuProbe.d.ts.map +1 -0
  47. package/dist/index.d.ts +2 -0
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +1423 -235
  50. package/dist/swarm/__tests__/adapter.test.d.ts +2 -0
  51. package/dist/swarm/__tests__/adapter.test.d.ts.map +1 -0
  52. package/dist/swarm/__tests__/controller.test.d.ts +2 -0
  53. package/dist/swarm/__tests__/controller.test.d.ts.map +1 -0
  54. package/dist/swarm/__tests__/defects.test.d.ts +16 -0
  55. package/dist/swarm/__tests__/defects.test.d.ts.map +1 -0
  56. package/dist/swarm/__tests__/hardening.test.d.ts +2 -0
  57. package/dist/swarm/__tests__/hardening.test.d.ts.map +1 -0
  58. package/dist/swarm/__tests__/peer-quality.test.d.ts +2 -0
  59. package/dist/swarm/__tests__/peer-quality.test.d.ts.map +1 -0
  60. package/dist/swarm/__tests__/peer-transport.test.d.ts +2 -0
  61. package/dist/swarm/__tests__/peer-transport.test.d.ts.map +1 -0
  62. package/dist/swarm/__tests__/runtime.test.d.ts +2 -0
  63. package/dist/swarm/__tests__/runtime.test.d.ts.map +1 -0
  64. package/dist/swarm/__tests__/session.test.d.ts +2 -0
  65. package/dist/swarm/__tests__/session.test.d.ts.map +1 -0
  66. package/dist/swarm/adapter.d.ts +115 -0
  67. package/dist/swarm/adapter.d.ts.map +1 -0
  68. package/dist/swarm/controller.d.ts +91 -0
  69. package/dist/swarm/controller.d.ts.map +1 -0
  70. package/dist/swarm/messages.d.ts +41 -0
  71. package/dist/swarm/messages.d.ts.map +1 -0
  72. package/dist/swarm/peer-quality.d.ts +14 -0
  73. package/dist/swarm/peer-quality.d.ts.map +1 -0
  74. package/dist/swarm/peer-transport.d.ts +81 -0
  75. package/dist/swarm/peer-transport.d.ts.map +1 -0
  76. package/dist/swarm/runtime.d.ts +20 -0
  77. package/dist/swarm/runtime.d.ts.map +1 -0
  78. package/dist/swarm/session.d.ts +73 -0
  79. package/dist/swarm/session.d.ts.map +1 -0
  80. package/dist/swarm-engine.js +7496 -0
  81. package/dist/vector-store/HNSWIndex.d.ts +30 -0
  82. package/dist/vector-store/HNSWIndex.d.ts.map +1 -1
  83. package/dist/vector-store/VectorStoreEngine.d.ts +43 -0
  84. package/dist/vector-store/VectorStoreEngine.d.ts.map +1 -1
  85. package/dist/vector-store/__tests__/HNSWIndex.test.d.ts +2 -0
  86. package/dist/vector-store/__tests__/HNSWIndex.test.d.ts.map +1 -0
  87. package/dist/vector-store/__tests__/VectorStoreEngine.test.d.ts +2 -0
  88. package/dist/vector-store/__tests__/VectorStoreEngine.test.d.ts.map +1 -0
  89. package/dist/worker/__tests__/main.worker.abort.test.d.ts +2 -0
  90. package/dist/worker/__tests__/main.worker.abort.test.d.ts.map +1 -0
  91. package/dist/worker/__tests__/main.worker.control.test.d.ts +2 -0
  92. package/dist/worker/__tests__/main.worker.control.test.d.ts.map +1 -0
  93. package/dist/worker.js +766 -67
  94. package/dist/workloads/__tests__/model-pipeline-cache.test.d.ts +2 -0
  95. package/dist/workloads/__tests__/model-pipeline-cache.test.d.ts.map +1 -0
  96. package/dist/workloads/__tests__/nudenet.test.d.ts +2 -0
  97. package/dist/workloads/__tests__/nudenet.test.d.ts.map +1 -0
  98. package/dist/workloads/ai-inference.d.ts +8 -1
  99. package/dist/workloads/ai-inference.d.ts.map +1 -1
  100. package/dist/workloads/ai-model-registry.d.ts +72 -0
  101. package/dist/workloads/ai-model-registry.d.ts.map +1 -0
  102. package/dist/workloads/container.d.ts +1 -1
  103. package/dist/workloads/container.d.ts.map +1 -1
  104. package/dist/workloads/image-process.d.ts +27 -0
  105. package/dist/workloads/image-process.d.ts.map +1 -1
  106. package/dist/workloads/model-pipeline-cache.d.ts +48 -0
  107. package/dist/workloads/model-pipeline-cache.d.ts.map +1 -0
  108. package/dist/workloads/nudenet.d.ts +8 -0
  109. package/dist/workloads/nudenet.d.ts.map +1 -1
  110. package/package.json +3 -2
  111. package/dist/assets/memoryProbe.js +0 -28
  112. package/dist/client/WebRTCPeer.d.ts +0 -8
  113. package/dist/client/WebRTCPeer.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -1,121 +1,331 @@
1
- import { r as e, t } from "./assets/memoryProbe.js";
2
- //#region src/consent/ConsentUI.ts
3
- var n = class {
4
- constructor(e, t, n, r) {
5
- this.shadow = e.attachShadow({ mode: "open" }), this.render(t, n, r);
6
- }
7
- render(e, t, n) {
8
- let { brandName: r, position: i, accentColor: a = "#6366f1" } = e, [o, s] = i.split("-"), c = document.createElement("style");
9
- c.textContent = `
10
- .overlay {
11
- position: fixed;
12
- ${o}: 20px;
13
- ${s}: 20px;
14
- padding: 20px;
15
- background: #fff;
16
- color: #1f2937;
17
- border: 1px solid #ccc;
18
- box-shadow: 0 4px 6px rgba(0,0,0,0.1);
19
- z-index: 9999;
20
- border-radius: 8px;
21
- max-width: 300px;
22
- font-family: sans-serif;
23
- }
24
- .overlay h3 {
25
- margin: 0 0 8px;
26
- color: #111827;
27
- font-size: 16px;
28
- }
29
- .overlay p {
30
- margin: 0 0 12px;
31
- color: #4b5563;
32
- font-size: 14px;
33
- line-height: 1.4;
34
- }
35
- button {
36
- background: ${a};
37
- color: white;
38
- border: none;
39
- padding: 10px 15px;
40
- border-radius: 4px;
41
- cursor: pointer;
42
- margin-top: 10px;
43
- width: 100%;
44
- font-size: 14px;
45
- }
46
- button.reject {
47
- background: transparent;
48
- color: #4b5563;
49
- border: 1px solid #ccc;
50
- }
51
- @media (prefers-color-scheme: dark) {
52
- .overlay {
53
- background: #1f2937;
54
- color: #f9fafb;
55
- border-color: #374151;
56
- box-shadow: 0 4px 6px rgba(0,0,0,0.4);
57
- }
58
- .overlay h3 {
59
- color: #f9fafb;
60
- }
61
- .overlay p {
62
- color: #d1d5db;
63
- }
64
- button.reject {
65
- color: #d1d5db;
66
- border-color: #4b5563;
67
- }
68
- }
69
- `;
70
- let l = document.createElement("div");
71
- l.className = "overlay", l.innerHTML = `
72
- <h3>${r}</h3>
73
- <p>サイトのパフォーマンス向上にご協力ください。</p>
74
- <button id="consent-btn">同意して開始</button>
75
- <button id="reject-btn" class="reject">拒否</button>
76
- `, l.querySelector("#consent-btn")?.addEventListener("click", () => {
77
- l.remove(), t();
78
- }), l.querySelector("#reject-btn")?.addEventListener("click", () => {
79
- l.remove(), n?.();
80
- }), this.shadow.appendChild(c), this.shadow.appendChild(l);
81
- }
82
- }, r = "flaxia_consent_granted", i = "flaxia_consent_expiry", a = "flaxia_consent_denied", o = 720 * 60 * 60 * 1e3, s = /* @__PURE__ */ new Map();
83
- function c(e) {
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
+ //#region src/consent/notice.ts
4
+ var v = {
5
+ summary: "同意すると、このブラウザは第三者から依頼された処理をバックグラウンドで実行します。",
6
+ items: [
7
+ "実行する処理: 顧客(第三者)が依頼したワークロード。任意の WebAssembly コンテナの実行や、画像の NSFW(成人向け)判定などを含みます。",
8
+ "接続と登録: オーケストレーターへ WebSocket で常時接続し、端末の性能や対応ワークロードを登録します。",
9
+ "資源の使用: 待機中も接続を維持し、処理の実行中は CPU・GPU・通信・バッテリーを消費します。",
10
+ "タスクの出所: 処理はこのサイトの運営者ではなく、第三者(顧客)から割り当てられます。"
11
+ ],
12
+ acceptGateHint: "開示内容を確認できるよう、「同意して開始」はしばらくの間押せません。",
13
+ acceptLabel: "同意して開始",
14
+ rejectLabel: "拒否"
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) {
84
17
  try {
85
18
  return localStorage.getItem(e);
86
19
  } catch {
87
- return s.get(e) ?? null;
20
+ return ae.get(e) ?? null;
88
21
  }
89
22
  }
90
- function l(e, t) {
23
+ function se(e, t) {
91
24
  try {
92
25
  localStorage.setItem(e, t);
93
26
  } catch {
94
- s.set(e, t);
27
+ ae.set(e, t);
95
28
  }
96
29
  }
97
- function u(e) {
30
+ function D(e) {
98
31
  try {
99
32
  localStorage.removeItem(e);
100
33
  } catch {
101
- s.delete(e);
102
- }
103
- }
104
- var d = () => {
105
- if (c(r) !== "true") return !1;
106
- let e = c(i);
107
- if (e) {
108
- let t = parseInt(e, 10);
109
- if (!Number.isFinite(t) || Date.now() > t) return u(r), u(i), !1;
110
- }
111
- return !0;
112
- }, f = () => {
113
- u(a), l(r, "true"), l(i, String(Date.now() + o));
114
- }, p = () => c(a) === "true", m = () => {
115
- u(r), u(i), l(a, "true");
116
- }, h = () => {
117
- u(r), u(i), u(a);
118
- }, g = () => d() ? "granted" : p() ? "denied" : "unset", _ = c, v = l, y = u, b = () => {
34
+ ae.delete(e);
35
+ }
36
+ }
37
+ function ce(e) {
38
+ return new Promise((t, n) => {
39
+ e.onsuccess = () => t(e.result), e.onerror = () => n(e.error ?? /* @__PURE__ */ Error("IndexedDB request failed"));
40
+ });
41
+ }
42
+ function le() {
43
+ return new Promise((e, t) => {
44
+ let n;
45
+ try {
46
+ n = globalThis.indexedDB;
47
+ } catch {
48
+ n = void 0;
49
+ }
50
+ if (!n) {
51
+ t(/* @__PURE__ */ Error("IndexedDB is unavailable"));
52
+ return;
53
+ }
54
+ let r;
55
+ try {
56
+ r = n.open(ne, re);
57
+ } catch (e) {
58
+ t(e);
59
+ return;
60
+ }
61
+ r.onupgradeneeded = () => {
62
+ let e = r.result;
63
+ e.objectStoreNames.contains(T) || e.createObjectStore(T);
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
+ });
66
+ }
67
+ function ue(e) {
68
+ if (!e || typeof e != "object") return !1;
69
+ let t = e;
70
+ return t.type === "secret" && t.algorithm?.name === "HMAC";
71
+ }
72
+ var de = {
73
+ async load() {
74
+ let e = await le();
75
+ try {
76
+ let t = await ce(e.transaction(T, "readonly").objectStore(T).get(E));
77
+ return ue(t) ? t : null;
78
+ } finally {
79
+ e.close();
80
+ }
81
+ },
82
+ async save(e) {
83
+ let t = await le();
84
+ try {
85
+ let n = t.transaction(T, "readwrite");
86
+ n.objectStore(T).put(e, E), await new Promise((e, t) => {
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
+ });
89
+ } finally {
90
+ t.close();
91
+ }
92
+ },
93
+ async clear() {
94
+ let e = await le();
95
+ try {
96
+ let t = e.transaction(T, "readwrite");
97
+ t.objectStore(T).delete(E), await new Promise((e, n) => {
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
+ });
100
+ } finally {
101
+ e.close();
102
+ }
103
+ }
104
+ };
105
+ function fe(e, t, n) {
106
+ return new Promise((r) => {
107
+ let i = !1, a, o = (e) => {
108
+ i || (i = !0, a !== void 0 && clearTimeout(a), r(e));
109
+ };
110
+ a = setTimeout(() => o(t), n), e.then((e) => o(e), () => o(t));
111
+ });
112
+ }
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
+ try {
116
+ let e = globalThis.location?.origin;
117
+ if (typeof e == "string" && e.length > 0) return e;
118
+ } catch {}
119
+ return "unknown";
120
+ }
121
+ var ge = he, _e = () => ge(), ve = {
122
+ name: "HMAC",
123
+ hash: "SHA-256"
124
+ };
125
+ function I() {
126
+ try {
127
+ let e = globalThis.crypto?.subtle;
128
+ if (e && typeof e.generateKey == "function" && typeof e.sign == "function" && typeof e.verify == "function") return e;
129
+ } catch {}
130
+ return null;
131
+ }
132
+ function ye(e) {
133
+ let t = new TextEncoder().encode(JSON.stringify([
134
+ e.v,
135
+ e.noticeVersion,
136
+ e.origin,
137
+ e.grantedAt,
138
+ e.expiry
139
+ ])), n = new Uint8Array(t.byteLength);
140
+ return n.set(t), n;
141
+ }
142
+ function be(e) {
143
+ let t = "";
144
+ for (let n of e) t += String.fromCharCode(n);
145
+ return btoa(t).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
146
+ }
147
+ function xe(e) {
148
+ try {
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
+ for (let e = 0; e < r.length; e += 1) i[e] = r.charCodeAt(e);
151
+ return i;
152
+ } catch {
153
+ return null;
154
+ }
155
+ }
156
+ async function Se() {
157
+ let e = await fe(pe.load(), null, w);
158
+ if (e) return e;
159
+ let t = I();
160
+ if (!t) return null;
161
+ try {
162
+ let e = await t.generateKey(ve, !1, ["sign", "verify"]);
163
+ return await fe(pe.save(e), void 0, w), e;
164
+ } catch {
165
+ return null;
166
+ }
167
+ }
168
+ async function Ce(e) {
169
+ let t = I();
170
+ if (!t || !O) return null;
171
+ try {
172
+ let n = await t.sign("HMAC", O, ye(e));
173
+ return be(new Uint8Array(n));
174
+ } catch {
175
+ return null;
176
+ }
177
+ }
178
+ async function we(e) {
179
+ let t = I();
180
+ if (!t || !O || !e.mac) return !1;
181
+ let n = xe(e.mac);
182
+ if (!n) return !1;
183
+ try {
184
+ return await t.verify("HMAC", O, n, ye(e));
185
+ } catch {
186
+ return !1;
187
+ }
188
+ }
189
+ function Te(e) {
190
+ if (!e) return null;
191
+ try {
192
+ let t = JSON.parse(e);
193
+ if (!t || typeof t != "object") return null;
194
+ let n = t;
195
+ return typeof n.origin != "string" || typeof n.expiry != "number" || typeof n.grantedAt != "number" ? null : {
196
+ v: typeof n.v == "number" ? n.v : 0,
197
+ noticeVersion: typeof n.noticeVersion == "number" ? n.noticeVersion : 0,
198
+ origin: n.origin,
199
+ grantedAt: n.grantedAt,
200
+ expiry: n.expiry,
201
+ mac: typeof n.mac == "string" ? n.mac : ""
202
+ };
203
+ } catch {
204
+ return null;
205
+ }
206
+ }
207
+ function Ee(e, t) {
208
+ return !(!Number.isFinite(e.grantedAt) || !Number.isFinite(e.expiry) || e.expiry <= t || e.grantedAt > e.expiry || e.expiry - e.grantedAt > 15552e6);
209
+ }
210
+ function De(e) {
211
+ return e.v === C && e.noticeVersion === 2 && e.origin === _e();
212
+ }
213
+ function Oe() {
214
+ return Te(oe(b));
215
+ }
216
+ function ke(e) {
217
+ se(b, JSON.stringify(e));
218
+ }
219
+ function L() {
220
+ D(b);
221
+ }
222
+ function R() {
223
+ D(x), D(ee);
224
+ }
225
+ var Ae = () => {
226
+ let e = k;
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
+ let e = ++N, t = P, n = null;
231
+ try {
232
+ n = await Se();
233
+ } catch {
234
+ n = null;
235
+ }
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
+ }
241
+ function Ne() {
242
+ let e = F;
243
+ return F = null, e && Date.now() - e.at <= te ? {
244
+ noticeVersion: e.noticeVersion,
245
+ source: "user-gesture"
246
+ } : me ? {
247
+ noticeVersion: 2,
248
+ source: "host-managed"
249
+ } : null;
250
+ }
251
+ function Pe(e) {
252
+ return typeof e != "number" || !Number.isFinite(e) || e <= 0 ? y : Math.min(Math.floor(e), y);
253
+ }
254
+ function Fe(e, t) {
255
+ let n = Date.now();
256
+ return {
257
+ v: C,
258
+ noticeVersion: e,
259
+ origin: _e(),
260
+ grantedAt: n,
261
+ expiry: n + Pe(t),
262
+ mac: ""
263
+ };
264
+ }
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
+ }
270
+ async function Le(e) {
271
+ try {
272
+ if (await B(), k !== e) return;
273
+ let t = await Ce(e);
274
+ if (k !== e) return;
275
+ if (!t) {
276
+ L(), j = !1;
277
+ return;
278
+ }
279
+ let n = {
280
+ ...e,
281
+ mac: t
282
+ };
283
+ k = n, A = !0, ke(n), j = !1;
284
+ } catch {
285
+ k === e && (L(), j = !1);
286
+ }
287
+ }
288
+ var Re = () => {
289
+ let e = Ne();
290
+ if (!e) {
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
+ return;
293
+ }
294
+ Le(Ie(e));
295
+ }, ze = (e = 2) => {
296
+ F = {
297
+ noticeVersion: e,
298
+ at: Date.now()
299
+ };
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
+ if (!t) {
310
+ k = null, A = !1;
311
+ return;
312
+ }
313
+ if (!I()) return;
314
+ if (!O) {
315
+ M = null, await B();
316
+ return;
317
+ }
318
+ let n = await we(t), r = Oe();
319
+ if (e !== P || !r || JSON.stringify(r) !== JSON.stringify(t)) return;
320
+ let i = n && Ee(t, Date.now()) && De(t);
321
+ k = i ? t : null, A = i;
322
+ }
323
+ try {
324
+ typeof globalThis.addEventListener == "function" && globalThis.addEventListener("storage", (e) => {
325
+ e.key !== null && e.key !== b && e.key !== S || (P += 1, Ke());
326
+ });
327
+ } catch {}
328
+ var qe = () => {
119
329
  try {
120
330
  if (typeof crypto < "u" && typeof crypto.randomUUID == "function") return crypto.randomUUID();
121
331
  } catch {}
@@ -123,9 +333,116 @@ var d = () => {
123
333
  let t = Math.random() * 16 | 0;
124
334
  return (e === "x" ? t : t & 3 | 8).toString(16);
125
335
  });
126
- }, x = (...e) => console.log("[flaxia-node]", ...e), S = class {
336
+ };
337
+ B();
338
+ //#endregion
339
+ //#region src/consent/ConsentUI.ts
340
+ var V = "#6366f1", Je = 1500, Ye = 1500, Xe = 6e4, Ze = 80, Qe = 40, $e = [
341
+ "bottom-right",
342
+ "bottom-left",
343
+ "top-right",
344
+ "top-left"
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
+ let t = e.trim();
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
+ if (n) {
353
+ let [e, t, r] = n.slice(1).map(Number);
354
+ return e <= 255 && t <= 255 && r <= 255 ? `rgb(${e}, ${t}, ${r})` : V;
355
+ }
356
+ let r = rt.exec(t);
357
+ if (r) {
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})` : V;
360
+ }
361
+ return it.get(t.toLowerCase()) ?? V;
362
+ }
363
+ function ot(e, t, n) {
364
+ if (typeof e != "string") return t;
365
+ let r = e.replace(/[\u0000-\u001f\u007f-\u009f\u200b-\u200f\u202a-\u202e\u2066-\u2069]/g, "").replace(/\s+/g, " ").trim();
366
+ return r.length === 0 ? t : r.length > n ? `${r.slice(0, n)}…` : r;
367
+ }
368
+ function st(e) {
369
+ if (typeof e != "string" || e.trim().length === 0) return null;
370
+ try {
371
+ let t = new URL(e.trim());
372
+ return t.protocol !== "https:" && t.protocol !== "http:" ? null : t.toString();
373
+ } catch {
374
+ return null;
375
+ }
376
+ }
377
+ function ct(e) {
378
+ return {
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
+ };
387
+ }
388
+ function lt(e) {
389
+ return typeof e != "number" || !Number.isFinite(e) ? Je : Math.min(Math.max(Math.floor(e), Ye), Xe);
390
+ }
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
+ }
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
+ constructor(e, t, n, r, i) {
396
+ this.config = ct(t), this.options = i ?? {}, this.root = e.attachShadow({ mode: "closed" }), this.render(n, r);
397
+ }
398
+ shadowRootForTesting() {
399
+ return this.root;
400
+ }
401
+ render(e, t) {
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
+ let t = document.createElement("li");
413
+ t.textContent = e, m.appendChild(t);
414
+ }
415
+ if (d.append(f, p, m), s) {
416
+ let e = document.createElement("p");
417
+ e.className = "privacy";
418
+ let t = document.createElement("a");
419
+ t.href = s, t.target = "_blank", t.rel = "noopener noreferrer", t.textContent = "プライバシーポリシー", e.appendChild(t), d.appendChild(e);
420
+ }
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;
425
+ let _ = document.createElement("button");
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
+ };
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
+ }
440
+ }, H = (...e) => console.log("[flaxia-node]", ...e), pt = class e {
441
+ static {
442
+ this.MAX_PENDING_CONTROLS = 64;
443
+ }
127
444
  constructor(e, t = 3e5) {
128
- this.worker = null, this.queue = [], this.active = null, 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();
129
446
  }
130
447
  initWorker() {
131
448
  if (typeof Worker > "u") return;
@@ -136,79 +453,153 @@ var d = () => {
136
453
  this.handleWorkerError(/* @__PURE__ */ Error("Worker message error"));
137
454
  }, this.worker = e;
138
455
  }
139
- run(e, t, n, r, i, a) {
140
- return new Promise((o, s) => {
456
+ run(e, t, n, r, i, a, o) {
457
+ return new Promise((s, c) => {
141
458
  if (!this.worker) {
142
- s(/* @__PURE__ */ Error("Worker not available"));
459
+ c(/* @__PURE__ */ Error("Worker not available"));
143
460
  return;
144
461
  }
145
- let c = () => this.execute(e, t, n, r, i, a, o, s);
146
- this.active ? (x(`task queued id=${e} workload=${t} (active task running)`), this.queue.push(c)) : c();
462
+ let l = () => this.execute(e, t, n, r, i, a, s, c, o);
463
+ this.active ? (H(`task queued id=${e} workload=${t} (active task running)`), this.queue.push({
464
+ id: e,
465
+ job: l,
466
+ reject: c
467
+ })) : l();
147
468
  });
148
469
  }
149
- execute(e, t, n, r, i, a, o, s) {
150
- let c = this.worker;
151
- if (!c) {
470
+ execute(e, t, n, r, i, a, o, s, c) {
471
+ let l = this.worker;
472
+ if (!l) {
152
473
  s(/* @__PURE__ */ Error("Worker not available")), this.dequeue();
153
474
  return;
154
475
  }
155
- let l = r ?? this.defaultTimeoutMs, u = !1, d = performance.now();
156
- x(`task start id=${e} workload=${t} timeoutMs=${l}`);
157
- let f = (e) => {
158
- if (u) return;
159
- u = !0;
160
- let t = this.active;
161
- t && (clearTimeout(t.timer), t.removeListener()), this.active = null, e(), this.dequeue();
162
- }, p = (n) => {
163
- let { id: r, type: a, result: c, error: l, token: u, cpuLoad: p } = n.data;
476
+ let u = r ?? this.defaultTimeoutMs, d = !1, f = performance.now();
477
+ H(`task start id=${e} workload=${t} timeoutMs=${u}`);
478
+ let p = (t) => {
479
+ if (d) return;
480
+ d = !0;
481
+ let n = this.active;
482
+ n && (clearTimeout(n.timer), n.removeListener()), this.active = null, this.pendingControls = this.pendingControls.filter((t) => t.taskId !== e), t(), this.dequeue();
483
+ }, m = (n) => {
484
+ let { id: r, type: a, result: l, error: u, token: d, cpuLoad: m } = n.data;
164
485
  if (r === e) {
165
- if (a === "token") {
166
- i?.(u);
486
+ if (g(n.data.modelCache) && (this._modelCacheSnapshot = n.data.modelCache), a === "token") {
487
+ i?.(d);
167
488
  return;
168
489
  }
169
490
  if (a === "heartbeat") {
170
- typeof p == "number" && Number.isFinite(p) && (this._lastCpuLoad = Math.min(1, Math.max(0, p)));
491
+ typeof m == "number" && Number.isFinite(m) && (this._lastCpuLoad = Math.min(1, Math.max(0, m)), this._hasCpuLoadSample = !0);
171
492
  return;
172
493
  }
173
- a === "done" ? (x(`task done id=${e} workload=${t} durationMs=${Math.round(performance.now() - d)}`), f(() => o(c))) : a === "error" ? (x(`task failed id=${e} workload=${t} error=${l}`), f(() => s(Error(l)))) : (x(`task unknown-message id=${e} type=${String(a)}`), f(() => s(/* @__PURE__ */ Error(`Unknown message type: ${String(a)}`))));
494
+ if (a === "swarm-frame") {
495
+ c?.onFrame?.(n.data.frame);
496
+ return;
497
+ }
498
+ if (a === "swarm-message") {
499
+ c?.onMessage?.(n.data.message);
500
+ return;
501
+ }
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)}`))));
174
503
  }
175
- }, m = () => c.removeEventListener("message", p), h = setTimeout(() => {
176
- x(`task timeout id=${e} workload=${t} (worker terminated after ${l}ms)`), this.cleanupWorker(), f(() => s(/* @__PURE__ */ Error("TIMEOUT")));
177
- }, l);
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
+ }, u);
178
507
  this.active = {
179
508
  id: e,
180
509
  resolve: o,
181
510
  reject: s,
182
- timer: h,
183
- worker: c,
184
- removeListener: m
185
- }, c.addEventListener("message", p);
511
+ timer: _,
512
+ worker: l,
513
+ removeListener: h
514
+ }, l.addEventListener("message", m);
186
515
  try {
187
- c.postMessage({
516
+ l.postMessage({
188
517
  id: e,
189
518
  workload: t,
190
519
  payload: n,
191
- timeoutMs: l,
520
+ timeoutMs: u,
192
521
  config: a
193
- });
522
+ }), this.flushControls();
194
523
  } catch (e) {
195
- f(() => s(e instanceof Error ? e : Error(String(e))));
524
+ p(() => s(e instanceof Error ? e : Error(String(e))));
525
+ }
526
+ }
527
+ flushControls() {
528
+ if (this.pendingControls.length === 0) return;
529
+ let e = this.pendingControls.filter((e) => e.taskId === this.active?.id);
530
+ this.pendingControls = this.pendingControls.filter((e) => e.taskId !== this.active?.id);
531
+ for (let t of e) this.postToActive({
532
+ type: "swarm-control",
533
+ message: t.message
534
+ });
535
+ }
536
+ postToActive(e, t) {
537
+ if (!this.worker || !this.active) return !1;
538
+ try {
539
+ return this.worker.postMessage({
540
+ id: this.active.id,
541
+ ...e
542
+ }, t ?? []), !0;
543
+ } catch {
544
+ return !1;
545
+ }
546
+ }
547
+ sendControl(t, n) {
548
+ let r = n ?? t?.taskId;
549
+ return typeof r == "string" && r !== this.active?.id ? this.worker ? (this.pendingControls.push({
550
+ taskId: r,
551
+ message: t
552
+ }), this.pendingControls.length > e.MAX_PENDING_CONTROLS && this.pendingControls.shift(), !1) : !1 : this.postToActive({
553
+ type: "swarm-control",
554
+ message: t
555
+ });
556
+ }
557
+ sendFrame(e) {
558
+ return this.postToActive({
559
+ type: "swarm-frame",
560
+ frame: e
561
+ }, [e]);
562
+ }
563
+ setTokenFlow(e, t) {
564
+ return this.active?.id === e ? this.postToActive({
565
+ type: "token-flow",
566
+ paused: t
567
+ }) : !1;
568
+ }
569
+ abort(e, t) {
570
+ let n = this.queue.findIndex((t) => t.id === e);
571
+ if (n >= 0) {
572
+ let [r] = this.queue.splice(n, 1);
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;
574
+ }
575
+ if (this.active?.id !== e || !this.worker) return !1;
576
+ try {
577
+ return this.worker.postMessage({
578
+ id: e,
579
+ type: "abort",
580
+ reason: t
581
+ }), H(`task abort sent id=${e} reason=${t}`), !0;
582
+ } catch {
583
+ return !1;
196
584
  }
197
585
  }
198
586
  handleWorkerError(e) {
199
- x(`worker error error=${e.message}`);
587
+ H(`worker error error=${e.message}`);
200
588
  let t = this.active;
201
589
  this.cleanupWorker(), t && (clearTimeout(t.timer), this.active = null, t.reject(e), this.dequeue());
202
590
  }
203
591
  dequeue() {
204
592
  let e = this.queue.shift();
205
- e && e();
593
+ e && e.job();
206
594
  }
207
595
  cleanupWorker() {
208
- this.worker &&= (this.worker.terminate(), null), this.initWorker();
596
+ this.worker &&= (this.worker.terminate(), null), this._modelCacheSnapshot = null, this.initWorker();
209
597
  }
210
598
  terminate() {
211
- this.queue = [], this.active &&= (clearTimeout(this.active.timer), this.active.reject(/* @__PURE__ */ Error("TERMINATED")), null), this.worker &&= (this.worker.terminate(), null);
599
+ let e = this.queue;
600
+ this.queue = [], this.pendingControls = [];
601
+ for (let t of e) t.reject(/* @__PURE__ */ Error("TERMINATED"));
602
+ this.active &&= (clearTimeout(this.active.timer), this.active.reject(/* @__PURE__ */ Error("TERMINATED")), null), this.worker &&= (this.worker.terminate(), null), this._modelCacheSnapshot = null;
212
603
  }
213
604
  resume() {
214
605
  this.worker || this.initWorker();
@@ -216,13 +607,581 @@ var d = () => {
216
607
  get lastCpuLoad() {
217
608
  return this._lastCpuLoad;
218
609
  }
219
- }, C = (...e) => console.log("[flaxia-node]", ...e), w = (...e) => console.error("[flaxia-node]", ...e), T = "flaxia_node_id", E = "flaxia_node_token", D = class {
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);
1096
+ function Z(e) {
1097
+ let t = /* @__PURE__ */ new Set();
1098
+ if (!Array.isArray(e)) return [];
1099
+ for (let n of e.slice(0, 32)) try {
1100
+ let e = _(n);
1101
+ e.origin === n && t.add(e.origin);
1102
+ } catch {}
1103
+ return [...t];
1104
+ }
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
+ }
1172
+ retireSwarmSession(e) {
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);
1174
+ }
220
1175
  constructor(e, t, n) {
221
- 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.visibilityHandler = null, this.inflightTasks = /* @__PURE__ */ new Set();
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;
222
1177
  }
223
1178
  async connect() {
224
1179
  if (this.destroyed) return;
225
- if (C(`connect nodeId=${this.nodeId}`), this.ws) {
1180
+ if (z() !== "granted") {
1181
+ this.disconnect();
1182
+ return;
1183
+ }
1184
+ if (Y(`connect nodeId=${this.nodeId}`), this.ws) {
226
1185
  let e = this.ws;
227
1186
  e.onclose = null;
228
1187
  try {
@@ -230,18 +1189,28 @@ var d = () => {
230
1189
  } catch {}
231
1190
  this.ws = null;
232
1191
  }
233
- this.setupVisibilityHandler();
1192
+ if (this.setupMobileLifecycleHandlers(), this.suspended) return;
234
1193
  let e = await this.obtainToken();
1194
+ if (this.destroyed || this.suspended) return;
1195
+ if (z() !== "granted") {
1196
+ Y("connect cancelled because consent was revoked while obtaining a token");
1197
+ return;
1198
+ }
235
1199
  if (!e) {
236
- w("token acquisition failed; scheduling reconnect"), this.scheduleReconnect();
1200
+ X("token acquisition failed; scheduling reconnect"), this.scheduleReconnect();
237
1201
  return;
238
1202
  }
239
- let t = this.config.orchestratorUrl.replace(/\/+$/, "").replace(/^http/, "ws"), n = new URL(`${t}/crowd/signal`);
240
- n.searchParams.set("token", e.token);
241
- let r = new WebSocket(n.toString());
242
- this.ws = r, r.onopen = () => {
243
- this.reconnectAttempts = 0, C(`signal connected ${n.toString()}`);
244
- }, r.onmessage = async (e) => {
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;
1210
+ if (typeof e.data != "string") {
1211
+ this.receiveSwarmEnvelope(e.data);
1212
+ return;
1213
+ }
245
1214
  let t;
246
1215
  try {
247
1216
  t = JSON.parse(e.data);
@@ -249,30 +1218,104 @@ var d = () => {
249
1218
  return;
250
1219
  }
251
1220
  if (t.type === "ping") {
252
- this.send({
253
- type: "pong",
254
- cpuLoad: this.workerPool.lastCpuLoad
255
- });
1221
+ this.sendHeartbeat(n);
256
1222
  return;
257
1223
  }
258
1224
  if (t.type === "task") {
259
1225
  let e = t;
260
- C(`task received taskId=${e.taskId} workload=${e.workload} timeoutMs=${e.timeoutMs ?? "default"}`);
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);
1227
+ let n = e.attemptId ?? this.attempts.get(e.taskId);
261
1228
  try {
262
1229
  await this.handleTask(e);
263
- } catch (n) {
264
- let r = n instanceof Error ? n.message : String(n);
265
- w(`task failed taskId=${e.taskId} workload=${e.workload} error=${r}`), this.send({
1230
+ } catch (r) {
1231
+ let i = r instanceof Error ? r.message : String(r);
1232
+ if (this.abortedTasks.delete(e.taskId)) {
1233
+ Y(`task stopped on coordinator abort taskId=${e.taskId} error=${i}`);
1234
+ return;
1235
+ }
1236
+ X(`task failed taskId=${e.taskId} workload=${e.workload} error=${i}`), this.send({
266
1237
  type: "error",
267
1238
  taskId: String(t.taskId ?? ""),
268
- error: r
1239
+ error: i,
1240
+ attemptId: n
269
1241
  });
270
1242
  }
1243
+ return;
1244
+ }
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);
1254
+ return;
1255
+ }
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);
1271
+ return;
1272
+ }
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);
1276
+ return;
271
1277
  }
272
- }, r.onclose = () => {
273
- r.onclose = null, this.ws === r && (this.ws = null, !this.destroyed && (C(`signal disconnected; scheduling reconnect attempt=${this.reconnectAttempts + 1}`), this.scheduleReconnect()));
1278
+ if (t.type === "swarm-start") {
1279
+ this.swarmSessions.get(String(t.taskId)) === t.sessionId && this.workerPool.sendControl(t, t.sessionId);
1280
+ return;
1281
+ }
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);
1285
+ return;
1286
+ }
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()));
274
1295
  };
275
1296
  }
1297
+ handleAbort(e) {
1298
+ let t = String(e.taskId ?? "");
1299
+ if (!t || !this.inflightTasks.has(t)) return;
1300
+ let n = typeof e.error == "string" && e.error ? e.error : "aborted by the coordinator", r = this.swarmSessions.get(t);
1301
+ if (r && r !== e.sessionId) return;
1302
+ let i = r ?? t;
1303
+ r && this.retireSwarmSession(r), this.workerPool.abort(i, n) && this.abortedTasks.add(i), Y(`task abort received taskId=${t} error=${n}`);
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
+ }
276
1319
  scheduleReconnect() {
277
1320
  let e = Math.min(1e3 * 2 ** this.reconnectAttempts, this.MAX_RECONNECT_DELAY);
278
1321
  setTimeout(() => {
@@ -280,13 +1323,15 @@ var d = () => {
280
1323
  }, e);
281
1324
  }
282
1325
  disconnect() {
283
- C(`disconnect nodeId=${this.nodeId}`), this.destroyed = !0, this.suspended = !1, this.removeVisibilityHandler();
1326
+ Y(`disconnect nodeId=${this.nodeId}`), this.destroyed = !0, this.suspended = !1, this.removeMobileLifecycleHandlers();
284
1327
  try {
285
1328
  this.ws?.close();
286
1329
  } catch {}
287
1330
  this.ws = null;
1331
+ for (let e of this.swarmPeerTransports.values()) e.close();
1332
+ this.swarmPeerTransports.clear(), this.swarmPeerMetadata.clear();
288
1333
  try {
289
- delete window[k];
1334
+ delete window[Ut];
290
1335
  } catch {}
291
1336
  try {
292
1337
  this.workerPool.terminate();
@@ -294,7 +1339,7 @@ var d = () => {
294
1339
  }
295
1340
  suspend() {
296
1341
  if (!(this.suspended || this.destroyed)) {
297
- if (C("suspended (visibility or manual)"), this.suspended = !0, this.ws) {
1342
+ if (Y("suspended (visibility or manual)"), this.suspended = !0, this.ws) {
298
1343
  let e = this.ws;
299
1344
  e.onclose = null;
300
1345
  try {
@@ -306,128 +1351,271 @@ var d = () => {
306
1351
  }
307
1352
  }
308
1353
  resume() {
309
- !this.suspended || this.destroyed || (C("resumed"), this.suspended = !1, this.workerPool.resume(), this.connect());
1354
+ !this.suspended || this.destroyed || (Y("resumed"), this.suspended = !1, this.workerPool.resume(), this.connect());
310
1355
  }
311
1356
  async obtainToken() {
1357
+ let e = () => z() === "granted";
1358
+ if (!e()) return null;
312
1359
  try {
313
- let n = _(E);
314
- if (n) try {
315
- let e = JSON.parse(n);
316
- if (e.token && e.nodeId && e.expiresAt > Date.now() + 6e4) return C(`token cached nodeId=${e.nodeId} expiresIn=${Math.round((e.expiresAt - Date.now()) / 1e3)}s`), e;
317
- } catch {}
318
- let r = e(), i = r >= t, a = i ? this.config.capabilities ?? ["ai-inference", "image-process"] : [];
319
- C(`register capability probe capable=${i} wasmMemoryBytes=${r} capabilities=${JSON.stringify(a)}`);
320
- let o = this.config.orchestratorUrl.replace(/\/+$/, ""), s = await fetch(`${o}/crowd/nodes/register`, {
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;
1361
+ let t = f(), n = t >= m, r = this.config.capabilities ?? ["ai-inference", "image-process"], i = n ? [...r] : [];
1362
+ Z(this.config.containerImageOrigins).length === 0 && (i = i.filter((e) => e !== "container"));
1363
+ let a;
1364
+ if (n && r.includes("swarm-inference") && this.config.allowModelDownload === !0) {
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");
1372
+ } else i = i.filter((e) => e !== "swarm-inference");
1373
+ Y(`register capability probe capable=${n} wasmMemoryBytes=${t} capabilities=${JSON.stringify(i)} webgpu=${a?.webgpu ?? !1}`);
1374
+ let o = this.config.orchestratorUrl.replace(/\/+$/, "");
1375
+ if (!e()) return null;
1376
+ let s = await fetch(`${o}/crowd/nodes/register`, {
321
1377
  method: "POST",
322
1378
  headers: { "Content-Type": "application/json" },
323
1379
  body: JSON.stringify({
324
1380
  siteId: this.config.siteId,
325
- nodeId: this.nodeId,
326
- capabilities: a,
327
- wasmMemoryBytes: e(),
328
- deviceMemory: typeof navigator.deviceMemory == "number" ? navigator.deviceMemory : null
1381
+ capabilities: i,
1382
+ fileSources: Z(this.config.fileSourceOrigins).length > 0,
1383
+ wasmMemoryBytes: f(),
1384
+ deviceMemory: typeof navigator.deviceMemory == "number" ? navigator.deviceMemory : null,
1385
+ swarm: a
329
1386
  })
330
1387
  });
331
- if (!s.ok) return w(`node register failed HTTP ${s.status} (${o}/crowd/nodes/register)`), null;
1388
+ if (!e()) return null;
1389
+ if (!s.ok) return X(`node register failed HTTP ${s.status} (${o}/crowd/nodes/register)`), null;
332
1390
  let c = await s.json();
333
- if (!c.token) return w("node register returned no token"), null;
334
- C(`node registered nodeId=${this.nodeId} expiresIn=${Math.round((c.expiresAt - Date.now()) / 1e3)}s`);
335
- try {
336
- v(E, JSON.stringify(c));
337
- } catch {}
338
- return c;
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;
339
1392
  } catch (e) {
340
- return w("node register threw", e instanceof Error ? e.message : e), null;
1393
+ return X("node register threw", e instanceof Error ? e.message : e), null;
341
1394
  }
342
1395
  }
343
1396
  send(e) {
344
1397
  this.ws && this.ws.readyState === WebSocket.OPEN && this.ws.send(JSON.stringify(e));
345
1398
  }
1399
+ sendBinary(e) {
1400
+ this.ws && this.ws.readyState === WebSocket.OPEN && this.ws.send(e);
1401
+ }
1402
+ queueSwarmFrame(e, t) {
1403
+ this.swarmOutboundChain = this.swarmOutboundChain.then(async () => {
1404
+ let n = this.swarmHopKeys.get(e);
1405
+ if (n && n.chainLength > 1) {
1406
+ if (!n.outboundKey) {
1407
+ X(`swarm frame not sent: no hop key sessionId=${e}`);
1408
+ return;
1409
+ }
1410
+ let i = await r(n.outboundKey, e, t), a = this.swarmPeerTransports.get(e);
1411
+ (!a || !await a.sendFrame(i)) && this.sendBinary(i);
1412
+ return;
1413
+ }
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
+ });
1426
+ }
1427
+ async startSwarm(e, t) {
1428
+ let n = t.sessionId;
1429
+ if (typeof n != "string" || !n || this.swarmSessions.get(e) === n) return;
1430
+ this.swarmSessions.set(e, n), this.inflightTasks.add(e);
1431
+ let r = performance.now(), i = typeof t.timeoutMs == "number" ? t.timeoutMs + 3e4 : void 0, a = this.attempts.get(e);
1432
+ try {
1433
+ let o = await this.workerPool.run(n, "swarm-inference", t, i, (t) => {
1434
+ this.send({
1435
+ type: "progress",
1436
+ taskId: e,
1437
+ sessionId: n,
1438
+ token: t,
1439
+ attemptId: a
1440
+ });
1441
+ }, { maxCpuLoad: this.effectiveMaxCpuLoad() }, {
1442
+ onFrame: (e) => this.queueSwarmFrame(n, e),
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
+ }
1461
+ });
1462
+ this.abortedTasks.delete(n) || this.send({
1463
+ type: "result",
1464
+ taskId: e,
1465
+ sessionId: n,
1466
+ payload: o,
1467
+ attemptId: a
1468
+ }), Y(`swarm result sent taskId=${e} durationMs=${Math.round(performance.now() - r)}`);
1469
+ } catch (t) {
1470
+ let r = t instanceof Error ? t.message : String(t);
1471
+ this.abortedTasks.delete(n) ? Y(`swarm stopped on coordinator abort taskId=${e} error=${r}`) : (X(`swarm failed taskId=${e} error=${r}`), this.send({
1472
+ type: "error",
1473
+ taskId: e,
1474
+ sessionId: n,
1475
+ error: r,
1476
+ attemptId: a
1477
+ }));
1478
+ } finally {
1479
+ this.retireSwarmSession(n), this.swarmSessions.get(e) === n && (this.swarmSessions.delete(e), this.inflightTasks.delete(e), this.attempts.delete(e));
1480
+ }
1481
+ }
346
1482
  async handleTask(e) {
347
1483
  if (this.inflightTasks.has(e.taskId)) return;
348
1484
  this.inflightTasks.add(e.taskId);
349
- let t = performance.now();
1485
+ let t = performance.now(), n = e.attemptId ?? this.attempts.get(e.taskId);
350
1486
  try {
351
- let n = e.timeoutMs ? e.timeoutMs + 3e4 : void 0, r = await this.workerPool.run(e.taskId, e.workload, e.payload, n, (t) => {
1487
+ let r = e.timeoutMs ? e.timeoutMs + 3e4 : void 0, i = await this.workerPool.run(e.taskId, e.workload, e.payload, r, (t) => {
352
1488
  this.send({
353
1489
  type: "progress",
354
1490
  taskId: e.taskId,
355
- token: t
1491
+ token: t,
1492
+ attemptId: n
356
1493
  });
357
- }, { maxCpuLoad: this.config.maxCpuLoad });
1494
+ }, {
1495
+ maxCpuLoad: this.effectiveMaxCpuLoad(),
1496
+ fileSourceOrigins: Z(this.config.fileSourceOrigins),
1497
+ containerImageOrigins: Z(this.config.containerImageOrigins)
1498
+ });
358
1499
  this.send({
359
1500
  type: "result",
360
1501
  taskId: e.taskId,
361
- payload: r
362
- }), C(`task result sent taskId=${e.taskId} workload=${e.workload} durationMs=${Math.round(performance.now() - t)}`);
1502
+ payload: i,
1503
+ attemptId: n
1504
+ }), Y(`task result sent taskId=${e.taskId} workload=${e.workload} durationMs=${Math.round(performance.now() - t)}`);
363
1505
  } finally {
364
- this.inflightTasks.delete(e.taskId);
1506
+ this.inflightTasks.delete(e.taskId), this.attempts.delete(e.taskId);
365
1507
  }
366
1508
  }
367
- setupVisibilityHandler() {
368
- this.removeVisibilityHandler(), this.visibilityHandler = () => {
369
- document.hidden ? this.suspend() : this.suspended && this.resume();
370
- }, document.addEventListener("visibilitychange", this.visibilityHandler);
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);
1552
+ }
1553
+ effectiveMaxCpuLoad() {
1554
+ return this.mobileLifecycleDecision().maxCpuLoad;
1555
+ }
1556
+ refreshMobileLifecycle() {
1557
+ this.mobileLifecycleDecision().suspend ? this.suspend() : this.suspended && this.resume();
371
1558
  }
372
- removeVisibilityHandler() {
373
- this.visibilityHandler &&= (document.removeEventListener("visibilitychange", this.visibilityHandler), null);
1559
+ }, $ = "__flaxia_node_signal_client", Ut = "__flaxia_node_init_started", Wt = "__flaxia_node_controller", Gt = (e) => {
1560
+ if (z() !== "granted") {
1561
+ X("refusing to start the node without a granted consent record");
1562
+ return;
374
1563
  }
375
- }, O = "__flaxia_node_signal_client", k = "__flaxia_node_init_started", A = "__flaxia_node_controller", j = (e) => {
376
- let t = window[O];
377
- t && t.disconnect();
378
- let n = new URL("./worker.js", "" + import.meta.url).href, r = new S(n), i = _(T);
379
- i || (i = b(), v(T, i));
380
- let a = new D(e, r, i);
381
- window[O] = a, a.connect();
382
- }, M = class {
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 {
383
1571
  constructor(e) {
384
1572
  this.config = e;
385
1573
  }
386
1574
  start() {
387
- this.isRunning() || j(this.config);
1575
+ this.isRunning() || !Ae() || Gt(this.config);
388
1576
  }
389
1577
  stop() {
390
- let e = window[O];
391
- e && e.disconnect(), delete window[O], delete window[k];
1578
+ let e = window[$];
1579
+ e && e.disconnect(), delete window[$], delete window[Ut];
392
1580
  }
393
1581
  isRunning() {
394
- return !!window[O];
1582
+ return !!window[$];
395
1583
  }
396
1584
  getConsentState() {
397
- return g();
1585
+ return z();
398
1586
  }
399
1587
  grant() {
400
- f();
1588
+ Re();
401
1589
  }
402
1590
  deny() {
403
- m(), this.stop(), y(E);
1591
+ Ve(), this.stop(), Ge(Q);
404
1592
  }
405
1593
  clearConsent() {
406
- h(), this.stop(), y(E);
1594
+ He(), this.stop(), Ge(Q);
407
1595
  }
408
- }, N = (e) => {
409
- let t = window[A];
1596
+ }, qt = (e) => {
1597
+ let t = window[Wt];
410
1598
  if (t) return t;
411
- let r = new M(e);
412
- window[A] = r, window[k] = !0;
413
- let i = g();
414
- if (i === "granted") return r.start(), r;
415
- if (i === "denied") return r;
1599
+ let n = new Kt(e);
1600
+ window[Wt] = n, window[Ut] = !0;
1601
+ let r = z();
1602
+ if (r === "granted") return n.start(), n;
1603
+ if (r === "denied") return n;
416
1604
  if (e.consent.onConsentRequired) return e.consent.onConsentRequired({
417
- state: i,
1605
+ state: r,
418
1606
  accept: () => {
419
- f(), r.start();
1607
+ Re(), n.start();
420
1608
  },
421
1609
  reject: () => {
422
- m();
1610
+ Ve();
423
1611
  }
424
- }), r;
425
- let a = document.createElement("div");
426
- return a.id = "flaxia-consent-container", document.body.appendChild(a), new n(a, e.consent, () => {
427
- f(), a.remove(), r.start();
1612
+ }), n;
1613
+ let i = document.createElement("div");
1614
+ return i.id = "flaxia-consent-container", document.body.appendChild(i), new ft(i, e.consent, () => {
1615
+ Re(), i.remove(), n.start();
428
1616
  }, () => {
429
- m(), a.remove();
430
- }), r;
1617
+ Ve(), i.remove();
1618
+ }), n;
431
1619
  };
432
1620
  //#endregion
433
- export { g as getFlaxiaNodeConsentState, N as initFlaxiaNode };
1621
+ export { z as getFlaxiaNodeConsentState, qt as initFlaxiaNode, B as initFlaxiaNodeConsent, Be as setFlaxiaNodeHostManagedConsent };