@flaxia/node 0.3.6 → 0.5.0

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 (95) hide show
  1. package/README.md +51 -15
  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/__tests__/public-api.test.d.ts +2 -0
  5. package/dist/__tests__/public-api.test.d.ts.map +1 -0
  6. package/dist/assets/VectorStoreEngine.js +140 -85
  7. package/dist/assets/ai-inference.js +173 -33
  8. package/dist/assets/container.js +368 -260
  9. package/dist/assets/dist.js +209 -0
  10. package/dist/assets/egress-guard.js +174 -0
  11. package/dist/assets/image-process.js +184 -19
  12. package/dist/assets/nudenet.js +2 -2
  13. package/dist/client/SignalingClient.d.ts +6 -0
  14. package/dist/client/SignalingClient.d.ts.map +1 -1
  15. package/dist/consent/ConsentUI.d.ts +44 -5
  16. package/dist/consent/ConsentUI.d.ts.map +1 -1
  17. package/dist/consent/notice.d.ts +29 -0
  18. package/dist/consent/notice.d.ts.map +1 -0
  19. package/dist/consent/storage.d.ts +91 -7
  20. package/dist/consent/storage.d.ts.map +1 -1
  21. package/dist/executor/WorkerPool.d.ts +35 -1
  22. package/dist/executor/WorkerPool.d.ts.map +1 -1
  23. package/dist/executor/__tests__/WorkerPool.swarm.test.d.ts +13 -0
  24. package/dist/executor/__tests__/WorkerPool.swarm.test.d.ts.map +1 -0
  25. package/dist/executor/__tests__/container-executor.test.d.ts +2 -0
  26. package/dist/executor/__tests__/container-executor.test.d.ts.map +1 -0
  27. package/dist/executor/__tests__/egress-guard.test.d.ts +2 -0
  28. package/dist/executor/__tests__/egress-guard.test.d.ts.map +1 -0
  29. package/dist/executor/__tests__/webgpuProbe.test.d.ts +2 -0
  30. package/dist/executor/__tests__/webgpuProbe.test.d.ts.map +1 -0
  31. package/dist/executor/container-executor.d.ts +49 -1
  32. package/dist/executor/container-executor.d.ts.map +1 -1
  33. package/dist/executor/egress-guard.d.ts +105 -0
  34. package/dist/executor/egress-guard.d.ts.map +1 -0
  35. package/dist/executor/memoryProbe.d.ts +25 -0
  36. package/dist/executor/memoryProbe.d.ts.map +1 -1
  37. package/dist/executor/throttle.d.ts +62 -4
  38. package/dist/executor/throttle.d.ts.map +1 -1
  39. package/dist/executor/webgpuProbe.d.ts +9 -0
  40. package/dist/executor/webgpuProbe.d.ts.map +1 -0
  41. package/dist/index.d.ts +3 -0
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +766 -230
  44. package/dist/swarm/__tests__/adapter.test.d.ts +2 -0
  45. package/dist/swarm/__tests__/adapter.test.d.ts.map +1 -0
  46. package/dist/swarm/__tests__/controller.test.d.ts +2 -0
  47. package/dist/swarm/__tests__/controller.test.d.ts.map +1 -0
  48. package/dist/swarm/__tests__/defects.test.d.ts +16 -0
  49. package/dist/swarm/__tests__/defects.test.d.ts.map +1 -0
  50. package/dist/swarm/__tests__/hardening.test.d.ts +2 -0
  51. package/dist/swarm/__tests__/hardening.test.d.ts.map +1 -0
  52. package/dist/swarm/__tests__/runtime.test.d.ts +2 -0
  53. package/dist/swarm/__tests__/runtime.test.d.ts.map +1 -0
  54. package/dist/swarm/__tests__/session.test.d.ts +2 -0
  55. package/dist/swarm/__tests__/session.test.d.ts.map +1 -0
  56. package/dist/swarm/adapter.d.ts +115 -0
  57. package/dist/swarm/adapter.d.ts.map +1 -0
  58. package/dist/swarm/controller.d.ts +87 -0
  59. package/dist/swarm/controller.d.ts.map +1 -0
  60. package/dist/swarm/messages.d.ts +41 -0
  61. package/dist/swarm/messages.d.ts.map +1 -0
  62. package/dist/swarm/runtime.d.ts +16 -0
  63. package/dist/swarm/runtime.d.ts.map +1 -0
  64. package/dist/swarm/session.d.ts +73 -0
  65. package/dist/swarm/session.d.ts.map +1 -0
  66. package/dist/swarm-engine.js +7477 -0
  67. package/dist/vector-store/HNSWIndex.d.ts +30 -0
  68. package/dist/vector-store/HNSWIndex.d.ts.map +1 -1
  69. package/dist/vector-store/VectorStoreEngine.d.ts +43 -0
  70. package/dist/vector-store/VectorStoreEngine.d.ts.map +1 -1
  71. package/dist/vector-store/__tests__/HNSWIndex.test.d.ts +2 -0
  72. package/dist/vector-store/__tests__/HNSWIndex.test.d.ts.map +1 -0
  73. package/dist/vector-store/__tests__/VectorStoreEngine.test.d.ts +2 -0
  74. package/dist/vector-store/__tests__/VectorStoreEngine.test.d.ts.map +1 -0
  75. package/dist/worker/__tests__/main.worker.abort.test.d.ts +2 -0
  76. package/dist/worker/__tests__/main.worker.abort.test.d.ts.map +1 -0
  77. package/dist/worker/__tests__/main.worker.control.test.d.ts +2 -0
  78. package/dist/worker/__tests__/main.worker.control.test.d.ts.map +1 -0
  79. package/dist/worker.js +643 -67
  80. package/dist/workloads/__tests__/nudenet.test.d.ts +2 -0
  81. package/dist/workloads/__tests__/nudenet.test.d.ts.map +1 -0
  82. package/dist/workloads/ai-inference.d.ts +2 -1
  83. package/dist/workloads/ai-inference.d.ts.map +1 -1
  84. package/dist/workloads/ai-model-registry.d.ts +72 -0
  85. package/dist/workloads/ai-model-registry.d.ts.map +1 -0
  86. package/dist/workloads/container.d.ts +1 -1
  87. package/dist/workloads/container.d.ts.map +1 -1
  88. package/dist/workloads/image-process.d.ts +27 -0
  89. package/dist/workloads/image-process.d.ts.map +1 -1
  90. package/dist/workloads/nudenet.d.ts +8 -0
  91. package/dist/workloads/nudenet.d.ts.map +1 -1
  92. package/package.json +3 -2
  93. package/dist/assets/memoryProbe.js +0 -28
  94. package/dist/client/WebRTCPeer.d.ts +0 -8
  95. 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 { d as e, f as t, m as n, p as r, r as i, u as a, v as o, x as s, y as c } from "./assets/dist.js";
2
+ import { t as l } from "./assets/egress-guard.js";
3
+ //#region src/consent/notice.ts
4
+ var u = {
5
+ summary: "同意すると、このブラウザは第三者から依頼された処理をバックグラウンドで実行します。",
6
+ items: [
7
+ "実行する処理: 顧客(第三者)が依頼したワークロード。任意の WebAssembly コンテナの実行や、画像の NSFW(成人向け)判定などを含みます。",
8
+ "接続と登録: オーケストレーターへ WebSocket で常時接続し、端末の性能や対応ワークロードを登録します。",
9
+ "資源の使用: 待機中も接続を維持し、処理の実行中は CPU・GPU・通信・バッテリーを消費します。",
10
+ "タスクの出所: 処理はこのサイトの運営者ではなく、第三者(顧客)から割り当てられます。"
11
+ ],
12
+ acceptGateHint: "開示内容を確認できるよう、「同意して開始」はしばらくの間押せません。",
13
+ acceptLabel: "同意して開始",
14
+ rejectLabel: "拒否"
15
+ }, d = 4320 * 60 * 60 * 1e3, f = "flaxia_consent_record", p = "flaxia_consent_granted", m = "flaxia_consent_expiry", h = "flaxia_consent_denied", g = 1, _ = 1e4, v = 2e3, ee = "flaxia-consent-integrity", te = 1, y = "keys", b = "consent-hmac-sha256-v1", x = (...e) => console.warn("[flaxia-node]", ...e), S = /* @__PURE__ */ new Map();
16
+ function C(e) {
84
17
  try {
85
18
  return localStorage.getItem(e);
86
19
  } catch {
87
- return s.get(e) ?? null;
20
+ return S.get(e) ?? null;
88
21
  }
89
22
  }
90
- function l(e, t) {
23
+ function ne(e, t) {
91
24
  try {
92
25
  localStorage.setItem(e, t);
93
26
  } catch {
94
- s.set(e, t);
27
+ S.set(e, t);
95
28
  }
96
29
  }
97
- function u(e) {
30
+ function w(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
+ S.delete(e);
35
+ }
36
+ }
37
+ function re(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 T() {
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(ee, te);
57
+ } catch (e) {
58
+ t(e);
59
+ return;
60
+ }
61
+ r.onupgradeneeded = () => {
62
+ let e = r.result;
63
+ e.objectStoreNames.contains(y) || e.createObjectStore(y);
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 ie(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 ae = {
73
+ async load() {
74
+ let e = await T();
75
+ try {
76
+ let t = await re(e.transaction(y, "readonly").objectStore(y).get(b));
77
+ return ie(t) ? t : null;
78
+ } finally {
79
+ e.close();
80
+ }
81
+ },
82
+ async save(e) {
83
+ let t = await T();
84
+ try {
85
+ let n = t.transaction(y, "readwrite");
86
+ n.objectStore(y).put(e, b), 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 T();
95
+ try {
96
+ let t = e.transaction(y, "readwrite");
97
+ t.objectStore(y).delete(b), 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 E(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 D = ae, O = null, k = null, A = !1, j = !1, M = null, N = 0, P = 0, F = null, oe = !1;
114
+ function se() {
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 ce = se, le = () => ce(), ue = {
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 de(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 fe(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 pe(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 me() {
157
+ let e = await E(D.load(), null, v);
158
+ if (e) return e;
159
+ let t = I();
160
+ if (!t) return null;
161
+ try {
162
+ let e = await t.generateKey(ue, !1, ["sign", "verify"]);
163
+ return await E(D.save(e), void 0, v), e;
164
+ } catch {
165
+ return null;
166
+ }
167
+ }
168
+ async function he(e) {
169
+ let t = I();
170
+ if (!t || !O) return null;
171
+ try {
172
+ let n = await t.sign("HMAC", O, de(e));
173
+ return fe(new Uint8Array(n));
174
+ } catch {
175
+ return null;
176
+ }
177
+ }
178
+ async function ge(e) {
179
+ let t = I();
180
+ if (!t || !O || !e.mac) return !1;
181
+ let n = pe(e.mac);
182
+ if (!n) return !1;
183
+ try {
184
+ return await t.verify("HMAC", O, n, de(e));
185
+ } catch {
186
+ return !1;
187
+ }
188
+ }
189
+ function _e(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 L(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 R(e) {
211
+ return e.v === g && e.noticeVersion === 2 && e.origin === le();
212
+ }
213
+ function z() {
214
+ return _e(C(f));
215
+ }
216
+ function ve(e) {
217
+ ne(f, JSON.stringify(e));
218
+ }
219
+ function B() {
220
+ w(f);
221
+ }
222
+ function V() {
223
+ w(p), w(m);
224
+ }
225
+ var ye = () => {
226
+ let e = k;
227
+ return !e || !A ? !1 : L(e, Date.now()) && R(e);
228
+ }, be = () => C(h) === "true", H = () => ye() ? "granted" : be() ? "denied" : "unset", U = () => (M ||= xe(), M);
229
+ async function xe() {
230
+ let e = ++N, t = P, n = null;
231
+ try {
232
+ n = await me();
233
+ } catch {
234
+ n = null;
235
+ }
236
+ if (e !== N) return H();
237
+ O = n, V();
238
+ let r = z();
239
+ return r !== null && await ge(r) && L(r, Date.now()) && R(r) && r ? t === P && e === N && (k = r, A = !0) : r && !j && (B(), t === P && e === N && (k = null, A = !1)), H();
240
+ }
241
+ function Se() {
242
+ let e = F;
243
+ return F = null, e && Date.now() - e.at <= _ ? {
244
+ noticeVersion: e.noticeVersion,
245
+ source: "user-gesture"
246
+ } : oe ? {
247
+ noticeVersion: 2,
248
+ source: "host-managed"
249
+ } : null;
250
+ }
251
+ function Ce(e) {
252
+ return typeof e != "number" || !Number.isFinite(e) || e <= 0 ? d : Math.min(Math.floor(e), d);
253
+ }
254
+ function we(e, t) {
255
+ let n = Date.now();
256
+ return {
257
+ v: g,
258
+ noticeVersion: e,
259
+ origin: le(),
260
+ grantedAt: n,
261
+ expiry: n + Ce(t),
262
+ mac: ""
263
+ };
264
+ }
265
+ function Te(e, t) {
266
+ w(h), V();
267
+ let n = we(e.noticeVersion, t);
268
+ return k = n, A = !0, j = !0, P += 1, ve(n), n;
269
+ }
270
+ async function Ee(e) {
271
+ try {
272
+ if (await U(), k !== e) return;
273
+ let t = await he(e);
274
+ if (k !== e) return;
275
+ if (!t) {
276
+ B(), j = !1;
277
+ return;
278
+ }
279
+ let n = {
280
+ ...e,
281
+ mac: t
282
+ };
283
+ k = n, A = !0, ve(n), j = !1;
284
+ } catch {
285
+ k === e && (B(), j = !1);
286
+ }
287
+ }
288
+ var W = () => {
289
+ let e = Se();
290
+ if (!e) {
291
+ x("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
+ Ee(Te(e));
295
+ }, De = (e = 2) => {
296
+ F = {
297
+ noticeVersion: e,
298
+ at: Date.now()
299
+ };
300
+ }, Oe = (e) => {
301
+ oe = e === !0;
302
+ }, G = () => {
303
+ B(), V(), k = null, A = !1, j = !1, P += 1, ne(h, "true");
304
+ }, ke = () => {
305
+ B(), V(), w(h), k = null, A = !1, j = !1, F = null, O = null, N += 1, P += 1, M = null, E(D.clear(), void 0, v);
306
+ }, Ae = C, je = ne, K = w;
307
+ async function Me() {
308
+ let e = P, t = z();
309
+ if (!t) {
310
+ k = null, A = !1;
311
+ return;
312
+ }
313
+ if (!I()) return;
314
+ if (!O) {
315
+ M = null, await U();
316
+ return;
317
+ }
318
+ let n = await ge(t), r = z();
319
+ if (e !== P || !r || JSON.stringify(r) !== JSON.stringify(t)) return;
320
+ let i = n && L(t, Date.now()) && R(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 !== f && e.key !== h || (P += 1, Me());
326
+ });
327
+ } catch {}
328
+ var Ne = () => {
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
+ U();
338
+ //#endregion
339
+ //#region src/consent/ConsentUI.ts
340
+ var q = "#6366f1", Pe = 1500, Fe = 1500, Ie = 6e4, Le = 80, Re = 40, ze = [
341
+ "bottom-right",
342
+ "bottom-left",
343
+ "top-right",
344
+ "top-left"
345
+ ], Be = /^#[0-9a-f]{3}$/i, Ve = /^#[0-9a-f]{6}$/i, He = /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/i, Ue = /^rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(0|1|0?\.\d+)\s*\)$/i, We = 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 Ge(e) {
347
+ if (typeof e != "string") return q;
348
+ let t = e.trim();
349
+ if (t.length === 0 || t.length > 64) return q;
350
+ if (Be.test(t) || Ve.test(t)) return t.toLowerCase();
351
+ let n = He.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})` : q;
355
+ }
356
+ let r = Ue.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})` : q;
360
+ }
361
+ return We.get(t.toLowerCase()) ?? q;
362
+ }
363
+ function Ke(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 qe(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 Je(e) {
378
+ return {
379
+ brandName: Ke(e?.brandName, "Flaxia Crowd", Le),
380
+ position: ze.includes(e?.position) ? e.position : "bottom-right",
381
+ accentColor: Ge(e?.accentColor),
382
+ acceptLabel: Ke(e?.acceptLabel, u.acceptLabel, Re),
383
+ rejectLabel: Ke(e?.rejectLabel, u.rejectLabel, Re),
384
+ privacyPolicyUrl: qe(e?.privacyPolicyUrl),
385
+ minVisibleMs: Ye(e?.minVisibleMs)
386
+ };
387
+ }
388
+ function Ye(e) {
389
+ return typeof e != "number" || !Number.isFinite(e) ? Pe : Math.min(Math.max(Math.floor(e), Fe), Ie);
390
+ }
391
+ function Xe(e, t) {
392
+ return typeof t.minVisibleMs == "number" && Number.isFinite(t.minVisibleMs) ? Math.min(Math.max(Math.floor(t.minVisibleMs), 0), Ie) : e;
393
+ }
394
+ var Ze = "\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", Qe = class {
395
+ constructor(e, t, n, r, i) {
396
+ this.config = Je(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("-"), d = document.createElement("style");
403
+ d.textContent = Ze.replace(/__flaxia_accent__/g, i).replace("__flaxia_position__", `${c}: 20px; ${l}: 20px`);
404
+ let f = document.createElement("div");
405
+ f.className = "overlay", f.setAttribute("role", "dialog"), f.setAttribute("aria-labelledby", "flaxia-consent-title");
406
+ let p = document.createElement("h3");
407
+ p.id = "flaxia-consent-title", p.textContent = n;
408
+ let m = document.createElement("p");
409
+ m.textContent = u.summary;
410
+ let h = document.createElement("ul");
411
+ for (let e of u.items) {
412
+ let t = document.createElement("li");
413
+ t.textContent = e, h.appendChild(t);
414
+ }
415
+ if (f.append(p, m, h), 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), f.appendChild(e);
420
+ }
421
+ let g = document.createElement("p");
422
+ g.className = "hint", g.textContent = u.acceptGateHint;
423
+ let _ = document.createElement("button");
424
+ _.id = "consent-btn", _.type = "button", _.textContent = a;
425
+ let v = document.createElement("button");
426
+ v.id = "reject-btn", v.type = "button", v.className = "reject", v.textContent = o;
427
+ let ee = this.options.now ?? (() => Date.now()), te = this.options.schedule ?? ((e, t) => void setTimeout(e, t)), y = Xe(this.config.minVisibleMs, this.options), b = ee() + y, x = y <= 0, S = !1;
428
+ x || (_.disabled = !0, _.setAttribute("aria-disabled", "true"), te(() => {
429
+ x = !0, _.disabled = !1, _.removeAttribute("aria-disabled"), g.remove();
430
+ }, y));
431
+ let C = (e) => {
432
+ S || (S = !0, f.remove(), e?.());
433
+ };
434
+ _.addEventListener("click", () => {
435
+ !x || ee() < b || (De(2), C(e));
436
+ }), v.addEventListener("click", () => {
437
+ C(t);
438
+ }), x || f.appendChild(g), f.append(_, v), this.root.append(d, f);
439
+ }
440
+ }, J = (...e) => console.log("[flaxia-node]", ...e), $e = 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.workerUrl = e || "/worker.js", this.defaultTimeoutMs = t, this.initWorker();
129
446
  }
130
447
  initWorker() {
131
448
  if (typeof Worker > "u") return;
@@ -136,79 +453,147 @@ 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 ? (J(`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
+ J(`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
486
  if (a === "token") {
166
- i?.(u);
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)));
492
+ return;
493
+ }
494
+ if (a === "swarm-frame") {
495
+ c?.onFrame?.(n.data.frame);
171
496
  return;
172
497
  }
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)}`))));
498
+ if (a === "swarm-message") {
499
+ c?.onMessage?.(n.data.message);
500
+ return;
501
+ }
502
+ a === "done" ? (J(`task done id=${e} workload=${t} durationMs=${Math.round(performance.now() - f)}`), p(() => o(l))) : a === "error" ? (J(`task failed id=${e} workload=${t} error=${u}`), p(() => s(Error(u)))) : (J(`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), g = setTimeout(() => {
505
+ J(`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: g,
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
+ abort(e, t) {
564
+ let n = this.queue.findIndex((t) => t.id === e);
565
+ if (n >= 0) {
566
+ let [r] = this.queue.splice(n, 1);
567
+ return this.pendingControls = this.pendingControls.filter((t) => t.taskId !== e), J(`task aborted before start id=${e} reason=${t}`), r.reject(Error(t)), !0;
568
+ }
569
+ if (this.active?.id !== e || !this.worker) return !1;
570
+ try {
571
+ return this.worker.postMessage({
572
+ id: e,
573
+ type: "abort",
574
+ reason: t
575
+ }), J(`task abort sent id=${e} reason=${t}`), !0;
576
+ } catch {
577
+ return !1;
196
578
  }
197
579
  }
198
580
  handleWorkerError(e) {
199
- x(`worker error error=${e.message}`);
581
+ J(`worker error error=${e.message}`);
200
582
  let t = this.active;
201
583
  this.cleanupWorker(), t && (clearTimeout(t.timer), this.active = null, t.reject(e), this.dequeue());
202
584
  }
203
585
  dequeue() {
204
586
  let e = this.queue.shift();
205
- e && e();
587
+ e && e.job();
206
588
  }
207
589
  cleanupWorker() {
208
590
  this.worker &&= (this.worker.terminate(), null), this.initWorker();
209
591
  }
210
592
  terminate() {
211
- this.queue = [], this.active &&= (clearTimeout(this.active.timer), this.active.reject(/* @__PURE__ */ Error("TERMINATED")), null), this.worker &&= (this.worker.terminate(), null);
593
+ let e = this.queue;
594
+ this.queue = [], this.pendingControls = [];
595
+ 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);
212
597
  }
213
598
  resume() {
214
599
  this.worker || this.initWorker();
@@ -216,13 +601,30 @@ var d = () => {
216
601
  get lastCpuLoad() {
217
602
  return this._lastCpuLoad;
218
603
  }
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 {
604
+ }, Y = (...e) => console.log("[flaxia-node]", ...e), X = (...e) => console.error("[flaxia-node]", ...e);
605
+ function Z(e) {
606
+ let t = /* @__PURE__ */ new Set();
607
+ if (!Array.isArray(e)) return [];
608
+ for (let n of e.slice(0, 32)) try {
609
+ let e = l(n);
610
+ e.origin === n && t.add(e.origin);
611
+ } catch {}
612
+ return [...t];
613
+ }
614
+ var et = "flaxia_node_id", tt = "flaxia_node_token", nt = class {
615
+ retireSwarmSession(e) {
616
+ this.swarmHopKeys.delete(e), this.retiredSwarmSessions.add(e), this.retiredSwarmSessions.size > 64 && this.retiredSwarmSessions.delete(this.retiredSwarmSessions.values().next().value);
617
+ }
220
618
  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();
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.visibilityHandler = 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.swarmInboundChain = Promise.resolve(), this.swarmOutboundChain = Promise.resolve(), this.attempts = /* @__PURE__ */ new Map(), this.cachedToken = null;
222
620
  }
223
621
  async connect() {
224
622
  if (this.destroyed) return;
225
- if (C(`connect nodeId=${this.nodeId}`), this.ws) {
623
+ if (H() !== "granted") {
624
+ this.disconnect();
625
+ return;
626
+ }
627
+ if (Y(`connect nodeId=${this.nodeId}`), this.ws) {
226
628
  let e = this.ws;
227
629
  e.onclose = null;
228
630
  try {
@@ -231,48 +633,111 @@ var d = () => {
231
633
  this.ws = null;
232
634
  }
233
635
  this.setupVisibilityHandler();
234
- let e = await this.obtainToken();
235
- if (!e) {
236
- w("token acquisition failed; scheduling reconnect"), this.scheduleReconnect();
636
+ let r = await this.obtainToken();
637
+ if (H() !== "granted") {
638
+ Y("connect cancelled because consent was revoked while obtaining a token");
237
639
  return;
238
640
  }
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) => {
245
- let t;
641
+ if (!r) {
642
+ X("token acquisition failed; scheduling reconnect"), this.scheduleReconnect();
643
+ return;
644
+ }
645
+ let i = e(this.config.orchestratorUrl, "/crowd/signal"), o = new WebSocket(i, a(r.token));
646
+ o.binaryType = "arraybuffer", this.ws = o;
647
+ let s = !1;
648
+ o.onopen = () => {
649
+ s = !0, this.reconnectAttempts = 0, Y(`signal connected ${i}`);
650
+ }, o.onmessage = async (e) => {
651
+ if (this.ws !== o) return;
652
+ if (typeof e.data != "string") {
653
+ let r = n(e.data);
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(() => {});
666
+ return;
667
+ }
668
+ let r;
246
669
  try {
247
- t = JSON.parse(e.data);
670
+ r = JSON.parse(e.data);
248
671
  } catch {
249
672
  return;
250
673
  }
251
- if (t.type === "ping") {
674
+ if (r.type === "ping") {
252
675
  this.send({
253
676
  type: "pong",
254
677
  cpuLoad: this.workerPool.lastCpuLoad
255
678
  });
256
679
  return;
257
680
  }
258
- if (t.type === "task") {
259
- let e = t;
260
- C(`task received taskId=${e.taskId} workload=${e.workload} timeoutMs=${e.timeoutMs ?? "default"}`);
681
+ if (r.type === "task") {
682
+ let e = r;
683
+ 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 t = e.attemptId ?? this.attempts.get(e.taskId);
261
685
  try {
262
686
  await this.handleTask(e);
263
687
  } 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({
688
+ let i = n instanceof Error ? n.message : String(n);
689
+ if (this.abortedTasks.delete(e.taskId)) {
690
+ Y(`task stopped on coordinator abort taskId=${e.taskId} error=${i}`);
691
+ return;
692
+ }
693
+ X(`task failed taskId=${e.taskId} workload=${e.workload} error=${i}`), this.send({
266
694
  type: "error",
267
- taskId: String(t.taskId ?? ""),
268
- error: r
695
+ taskId: String(r.taskId ?? ""),
696
+ error: i,
697
+ attemptId: t
269
698
  });
270
699
  }
700
+ return;
701
+ }
702
+ if (r.type === "swarm-init" || r.type === "swarm-slice") {
703
+ let e = String(r.taskId ?? "");
704
+ if (!e || typeof r.sessionId != "string" || this.retiredSwarmSessions.has(r.sessionId)) return;
705
+ if (r.type === "swarm-slice" && this.swarmHopKeys.set(r.sessionId, {
706
+ inboundKey: typeof r.inboundKey == "string" ? r.inboundKey : void 0,
707
+ outboundKey: typeof r.outboundKey == "string" ? r.outboundKey : void 0,
708
+ chainLength: typeof r.chainLength == "number" ? r.chainLength : 1
709
+ }), typeof r.attemptId == "string" && this.attempts.set(e, r.attemptId), this.swarmSessions.get(e) === r.sessionId) {
710
+ this.workerPool.sendControl(r, r.sessionId);
711
+ return;
712
+ }
713
+ this.startSwarm(e, r);
714
+ return;
715
+ }
716
+ if (r.type === "swarm-start") {
717
+ this.swarmSessions.get(String(r.taskId)) === r.sessionId && this.workerPool.sendControl(r, r.sessionId);
718
+ return;
719
+ }
720
+ if (r.type === "swarm-error") {
721
+ let e = String(r.taskId ?? "");
722
+ e && this.swarmSessions.get(e) === r.sessionId && this.workerPool.sendControl(r, r.sessionId);
723
+ return;
724
+ }
725
+ if (r.type === "abort") {
726
+ this.handleAbort(r);
727
+ return;
271
728
  }
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()));
729
+ }, o.onclose = () => {
730
+ o.onclose = null, this.ws === o && (this.ws = null, s || (this.cachedToken = null), !this.destroyed && (Y(`signal disconnected; scheduling reconnect attempt=${this.reconnectAttempts + 1}`), this.scheduleReconnect()));
274
731
  };
275
732
  }
733
+ handleAbort(e) {
734
+ let t = String(e.taskId ?? "");
735
+ if (!t || !this.inflightTasks.has(t)) return;
736
+ let n = typeof e.error == "string" && e.error ? e.error : "aborted by the coordinator", r = this.swarmSessions.get(t);
737
+ if (r && r !== e.sessionId) return;
738
+ let i = r ?? t;
739
+ r && this.retireSwarmSession(r), this.workerPool.abort(i, n) && this.abortedTasks.add(i), Y(`task abort received taskId=${t} error=${n}`);
740
+ }
276
741
  scheduleReconnect() {
277
742
  let e = Math.min(1e3 * 2 ** this.reconnectAttempts, this.MAX_RECONNECT_DELAY);
278
743
  setTimeout(() => {
@@ -280,13 +745,13 @@ var d = () => {
280
745
  }, e);
281
746
  }
282
747
  disconnect() {
283
- C(`disconnect nodeId=${this.nodeId}`), this.destroyed = !0, this.suspended = !1, this.removeVisibilityHandler();
748
+ Y(`disconnect nodeId=${this.nodeId}`), this.destroyed = !0, this.suspended = !1, this.removeVisibilityHandler();
284
749
  try {
285
750
  this.ws?.close();
286
751
  } catch {}
287
752
  this.ws = null;
288
753
  try {
289
- delete window[k];
754
+ delete window[$];
290
755
  } catch {}
291
756
  try {
292
757
  this.workerPool.terminate();
@@ -294,7 +759,7 @@ var d = () => {
294
759
  }
295
760
  suspend() {
296
761
  if (!(this.suspended || this.destroyed)) {
297
- if (C("suspended (visibility or manual)"), this.suspended = !0, this.ws) {
762
+ if (Y("suspended (visibility or manual)"), this.suspended = !0, this.ws) {
298
763
  let e = this.ws;
299
764
  e.onclose = null;
300
765
  try {
@@ -306,62 +771,129 @@ var d = () => {
306
771
  }
307
772
  }
308
773
  resume() {
309
- !this.suspended || this.destroyed || (C("resumed"), this.suspended = !1, this.workerPool.resume(), this.connect());
774
+ !this.suspended || this.destroyed || (Y("resumed"), this.suspended = !1, this.workerPool.resume(), this.connect());
310
775
  }
311
776
  async obtainToken() {
777
+ let e = () => H() === "granted";
778
+ if (!e()) return null;
312
779
  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`, {
780
+ 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 = s(), n = t >= c, r = this.config.capabilities ?? ["ai-inference", "image-process"], i = n ? [...r] : [];
782
+ Z(this.config.containerImageOrigins).length === 0 && (i = i.filter((e) => e !== "container"));
783
+ let a;
784
+ if (n && r.includes("swarm-inference") && this.config.allowModelDownload === !0) {
785
+ if (a = await o(), !e()) return null;
786
+ a.webgpu || (i = i.filter((e) => e !== "swarm-inference"), a = void 0);
787
+ } else i = i.filter((e) => e !== "swarm-inference");
788
+ Y(`register capability probe capable=${n} wasmMemoryBytes=${t} capabilities=${JSON.stringify(i)} webgpu=${a?.webgpu ?? !1}`);
789
+ let l = this.config.orchestratorUrl.replace(/\/+$/, "");
790
+ if (!e()) return null;
791
+ let u = await fetch(`${l}/crowd/nodes/register`, {
321
792
  method: "POST",
322
793
  headers: { "Content-Type": "application/json" },
323
794
  body: JSON.stringify({
324
795
  siteId: this.config.siteId,
325
- nodeId: this.nodeId,
326
- capabilities: a,
327
- wasmMemoryBytes: e(),
328
- deviceMemory: typeof navigator.deviceMemory == "number" ? navigator.deviceMemory : null
796
+ capabilities: i,
797
+ fileSources: Z(this.config.fileSourceOrigins).length > 0,
798
+ wasmMemoryBytes: s(),
799
+ deviceMemory: typeof navigator.deviceMemory == "number" ? navigator.deviceMemory : null,
800
+ swarm: a
329
801
  })
330
802
  });
331
- if (!s.ok) return w(`node register failed HTTP ${s.status} (${o}/crowd/nodes/register)`), null;
332
- 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;
803
+ if (!e()) return null;
804
+ if (!u.ok) return X(`node register failed HTTP ${u.status} (${l}/crowd/nodes/register)`), null;
805
+ let d = await u.json();
806
+ return e() ? d.token ? (typeof d.nodeId == "string" && d.nodeId && (this.nodeId = d.nodeId), this.cachedToken = d, Y(`node registered nodeId=${this.nodeId} expiresIn=${Math.round((d.expiresAt - Date.now()) / 1e3)}s`), d) : (X("node register returned no token"), null) : null;
339
807
  } catch (e) {
340
- return w("node register threw", e instanceof Error ? e.message : e), null;
808
+ return X("node register threw", e instanceof Error ? e.message : e), null;
341
809
  }
342
810
  }
343
811
  send(e) {
344
812
  this.ws && this.ws.readyState === WebSocket.OPEN && this.ws.send(JSON.stringify(e));
345
813
  }
814
+ sendBinary(e) {
815
+ this.ws && this.ws.readyState === WebSocket.OPEN && this.ws.send(e);
816
+ }
817
+ queueSwarmFrame(e, t) {
818
+ this.swarmOutboundChain = this.swarmOutboundChain.then(async () => {
819
+ let n = this.swarmHopKeys.get(e);
820
+ if (n && n.chainLength > 1) {
821
+ if (!n.outboundKey) {
822
+ X(`swarm frame not sent: no hop key sessionId=${e}`);
823
+ return;
824
+ }
825
+ this.sendBinary(await r(n.outboundKey, e, t));
826
+ return;
827
+ }
828
+ this.sendBinary(i(e, t));
829
+ }).catch(() => {});
830
+ }
831
+ async startSwarm(e, t) {
832
+ let n = t.sessionId;
833
+ if (typeof n != "string" || !n || this.swarmSessions.get(e) === n) return;
834
+ this.swarmSessions.set(e, n), this.inflightTasks.add(e);
835
+ let r = performance.now(), i = typeof t.timeoutMs == "number" ? t.timeoutMs + 3e4 : void 0, a = this.attempts.get(e);
836
+ try {
837
+ let o = await this.workerPool.run(n, "swarm-inference", t, i, (t) => {
838
+ this.send({
839
+ type: "progress",
840
+ taskId: e,
841
+ sessionId: n,
842
+ token: t,
843
+ attemptId: a
844
+ });
845
+ }, { maxCpuLoad: this.config.maxCpuLoad }, {
846
+ onFrame: (e) => this.queueSwarmFrame(n, e),
847
+ onMessage: (e) => this.send(e && typeof e == "object" && !("attemptId" in e) ? {
848
+ ...e,
849
+ attemptId: a
850
+ } : e)
851
+ });
852
+ this.abortedTasks.delete(n) || this.send({
853
+ type: "result",
854
+ taskId: e,
855
+ sessionId: n,
856
+ payload: o,
857
+ attemptId: a
858
+ }), Y(`swarm result sent taskId=${e} durationMs=${Math.round(performance.now() - r)}`);
859
+ } catch (t) {
860
+ let r = t instanceof Error ? t.message : String(t);
861
+ this.abortedTasks.delete(n) ? Y(`swarm stopped on coordinator abort taskId=${e} error=${r}`) : (X(`swarm failed taskId=${e} error=${r}`), this.send({
862
+ type: "error",
863
+ taskId: e,
864
+ sessionId: n,
865
+ error: r,
866
+ attemptId: a
867
+ }));
868
+ } finally {
869
+ this.retireSwarmSession(n), this.swarmSessions.get(e) === n && (this.swarmSessions.delete(e), this.inflightTasks.delete(e), this.attempts.delete(e));
870
+ }
871
+ }
346
872
  async handleTask(e) {
347
873
  if (this.inflightTasks.has(e.taskId)) return;
348
874
  this.inflightTasks.add(e.taskId);
349
- let t = performance.now();
875
+ let t = performance.now(), n = e.attemptId ?? this.attempts.get(e.taskId);
350
876
  try {
351
- let n = e.timeoutMs ? e.timeoutMs + 3e4 : void 0, r = await this.workerPool.run(e.taskId, e.workload, e.payload, n, (t) => {
877
+ let r = e.timeoutMs ? e.timeoutMs + 3e4 : void 0, i = await this.workerPool.run(e.taskId, e.workload, e.payload, r, (t) => {
352
878
  this.send({
353
879
  type: "progress",
354
880
  taskId: e.taskId,
355
- token: t
881
+ token: t,
882
+ attemptId: n
356
883
  });
357
- }, { maxCpuLoad: this.config.maxCpuLoad });
884
+ }, {
885
+ maxCpuLoad: this.config.maxCpuLoad,
886
+ fileSourceOrigins: Z(this.config.fileSourceOrigins),
887
+ containerImageOrigins: Z(this.config.containerImageOrigins)
888
+ });
358
889
  this.send({
359
890
  type: "result",
360
891
  taskId: e.taskId,
361
- payload: r
362
- }), C(`task result sent taskId=${e.taskId} workload=${e.workload} durationMs=${Math.round(performance.now() - t)}`);
892
+ payload: i,
893
+ attemptId: n
894
+ }), Y(`task result sent taskId=${e.taskId} workload=${e.workload} durationMs=${Math.round(performance.now() - t)}`);
363
895
  } finally {
364
- this.inflightTasks.delete(e.taskId);
896
+ this.inflightTasks.delete(e.taskId), this.attempts.delete(e.taskId);
365
897
  }
366
898
  }
367
899
  setupVisibilityHandler() {
@@ -372,62 +904,66 @@ var d = () => {
372
904
  removeVisibilityHandler() {
373
905
  this.visibilityHandler &&= (document.removeEventListener("visibilitychange", this.visibilityHandler), null);
374
906
  }
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 {
907
+ }, Q = "__flaxia_node_signal_client", $ = "__flaxia_node_init_started", rt = "__flaxia_node_controller", it = (e) => {
908
+ if (H() !== "granted") {
909
+ X("refusing to start the node without a granted consent record");
910
+ return;
911
+ }
912
+ let t = window[Q];
913
+ t && t.disconnect(), K(tt);
914
+ let n = new URL("./worker.js", "" + import.meta.url).href, r = new $e(n), i = Ae(et);
915
+ i || (i = Ne(), je(et, i));
916
+ let a = new nt(e, r, i);
917
+ window[Q] = a, a.connect();
918
+ }, at = class {
383
919
  constructor(e) {
384
920
  this.config = e;
385
921
  }
386
922
  start() {
387
- this.isRunning() || j(this.config);
923
+ this.isRunning() || !ye() || it(this.config);
388
924
  }
389
925
  stop() {
390
- let e = window[O];
391
- e && e.disconnect(), delete window[O], delete window[k];
926
+ let e = window[Q];
927
+ e && e.disconnect(), delete window[Q], delete window[$];
392
928
  }
393
929
  isRunning() {
394
- return !!window[O];
930
+ return !!window[Q];
395
931
  }
396
932
  getConsentState() {
397
- return g();
933
+ return H();
398
934
  }
399
935
  grant() {
400
- f();
936
+ W();
401
937
  }
402
938
  deny() {
403
- m(), this.stop(), y(E);
939
+ G(), this.stop(), K(tt);
404
940
  }
405
941
  clearConsent() {
406
- h(), this.stop(), y(E);
942
+ ke(), this.stop(), K(tt);
407
943
  }
408
- }, N = (e) => {
409
- let t = window[A];
944
+ }, ot = (e) => {
945
+ let t = window[rt];
410
946
  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;
947
+ let n = new at(e);
948
+ window[rt] = n, window[$] = !0;
949
+ let r = H();
950
+ if (r === "granted") return n.start(), n;
951
+ if (r === "denied") return n;
416
952
  if (e.consent.onConsentRequired) return e.consent.onConsentRequired({
417
- state: i,
953
+ state: r,
418
954
  accept: () => {
419
- f(), r.start();
955
+ W(), n.start();
420
956
  },
421
957
  reject: () => {
422
- m();
958
+ G();
423
959
  }
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();
960
+ }), n;
961
+ let i = document.createElement("div");
962
+ return i.id = "flaxia-consent-container", document.body.appendChild(i), new Qe(i, e.consent, () => {
963
+ W(), i.remove(), n.start();
428
964
  }, () => {
429
- m(), a.remove();
430
- }), r;
965
+ G(), i.remove();
966
+ }), n;
431
967
  };
432
968
  //#endregion
433
- export { N as initFlaxiaNode };
969
+ export { H as getFlaxiaNodeConsentState, ot as initFlaxiaNode, U as initFlaxiaNodeConsent, Oe as setFlaxiaNodeHostManagedConsent };