@flaxia/node 0.3.2 → 0.3.4

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.
@@ -36,43 +36,41 @@ var r = [
36
36
  return (e) => {
37
37
  n += e, r ||= setTimeout(a, i);
38
38
  };
39
- }, c = async (o, c) => {
40
- let { task: l, model: u, input: d, options: f = {} } = o;
41
- if (!r.includes(l)) throw Error(`Invalid or unsupported task: ${l}. Supported tasks are: ${r.join(", ")}`);
42
- if (self.crossOriginIsolated) {
43
- let e = f.numThreads ?? navigator.hardwareConcurrency;
44
- t.backends.onnx?.wasm && (t.backends.onnx.wasm.numThreads = Math.max(1, Math.min(e, navigator.hardwareConcurrency || 4)));
45
- }
46
- let p = `${l}:${u}`, m = i.get(p);
47
- if (!m) {
39
+ };
40
+ t.backends?.onnx?.wasm && (t.backends.onnx.wasm.numThreads = 1, t.backends.onnx.wasm.proxy = !1);
41
+ var c = async (t, o) => {
42
+ let { task: c, model: l, input: u, options: d = {} } = t;
43
+ if (!r.includes(c)) throw Error(`Invalid or unsupported task: ${c}. Supported tasks are: ${r.join(", ")}`);
44
+ let f = `${c}:${l}`, p = i.get(f);
45
+ if (!p) {
48
46
  if (i.size >= a) {
49
47
  let e = i.keys().next().value;
50
48
  i.delete(e);
51
49
  }
52
50
  let e = {
53
- dtype: f.dtype ?? "q4f16",
54
- device: f.device
51
+ dtype: d.dtype ?? "q4f16",
52
+ device: d.device
55
53
  }, t = performance.now();
56
- console.log(`[flaxia-node] ai-inference: loading pipeline task=${l} model=${u} dtype=${e.dtype} device=${e.device ?? "wasm"}`);
54
+ console.log(`[flaxia-node] ai-inference: loading pipeline task=${c} model=${l} dtype=${e.dtype} device=${e.device ?? "wasm"}`);
57
55
  try {
58
- m = await n(l, u, e);
56
+ p = await n(c, l, e);
59
57
  } catch (t) {
60
- if (f.device && f.device !== "wasm") console.warn(`[AiInference] ${f.device} failed, falling back to wasm:`, t), e.device = "wasm", m = await n(l, u, e);
61
- else throw console.error(`[flaxia-node] ai-inference: pipeline load FAILED task=${l} model=${u} error=${t instanceof Error ? t.message : String(t)}`), t;
58
+ if (d.device && d.device !== "wasm") console.warn(`[AiInference] ${d.device} failed, falling back to wasm:`, t), e.device = "wasm", p = await n(c, l, e);
59
+ else throw console.error(`[flaxia-node] ai-inference: pipeline load FAILED task=${c} model=${l} error=${t instanceof Error ? t.message : String(t)}`), t;
62
60
  }
63
- console.log(`[flaxia-node] ai-inference: pipeline ready task=${l} model=${u} loadMs=${Math.round(performance.now() - t)}`), i.set(p, m);
61
+ console.log(`[flaxia-node] ai-inference: pipeline ready task=${c} model=${l} loadMs=${Math.round(performance.now() - t)}`), i.set(f, p);
64
62
  }
65
- let h = {
66
- max_new_tokens: f.max_new_tokens ?? 128,
67
- do_sample: f.do_sample ?? !1
63
+ let m = {
64
+ max_new_tokens: d.max_new_tokens ?? 128,
65
+ do_sample: d.do_sample ?? !1
68
66
  };
69
- f.temperature != null && (h.temperature = f.temperature), f.top_p != null && (h.top_p = f.top_p), f.top_k != null && (h.top_k = f.top_k), f.repetition_penalty != null && (h.repetition_penalty = f.repetition_penalty), f.src_lang != null && (h.src_lang = f.src_lang), f.tgt_lang != null && (h.tgt_lang = f.tgt_lang), c && m.tokenizer && (h.streamer = new e(m.tokenizer, {
67
+ d.temperature != null && (m.temperature = d.temperature), d.top_p != null && (m.top_p = d.top_p), d.top_k != null && (m.top_k = d.top_k), d.repetition_penalty != null && (m.repetition_penalty = d.repetition_penalty), d.src_lang != null && (m.src_lang = d.src_lang), d.tgt_lang != null && (m.tgt_lang = d.tgt_lang), o && p.tokenizer && (m.streamer = new e(p.tokenizer, {
70
68
  skip_prompt: !0,
71
69
  skip_special_tokens: !0,
72
- callback_function: s(c, f)
70
+ callback_function: s(o, d)
73
71
  }));
74
- let g = performance.now(), _ = await m(d, h);
75
- return console.log(`[flaxia-node] ai-inference: done task=${l} model=${u} execMs=${Math.round(performance.now() - g)} inputLen=${String(d).length}`), { output: _ };
72
+ let h = performance.now(), g = await p(u, m);
73
+ return console.log(`[flaxia-node] ai-inference: done task=${c} model=${l} execMs=${Math.round(performance.now() - h)} inputLen=${String(u).length}`), { output: g };
76
74
  };
77
75
  //#endregion
78
76
  export { c as handleAiInference, o as releaseCache };
@@ -0,0 +1,28 @@
1
+ //#region src/executor/memoryProbe.ts
2
+ var e = 2 * 1024 ** 3, t = 65536, n = 16 * 1024 * 1024;
3
+ function r(r = e, i = n) {
4
+ let a;
5
+ try {
6
+ a = new WebAssembly.Memory({ initial: 0 });
7
+ } catch {
8
+ return 0;
9
+ }
10
+ let o = 0;
11
+ for (; o < r;) {
12
+ let e = r - o, n = Math.ceil(Math.min(i, e) / t);
13
+ try {
14
+ a.grow(n);
15
+ } catch {
16
+ break;
17
+ }
18
+ let s = new Uint8Array(a.buffer);
19
+ for (let e = 0; e < n; e++) s[o + e * t] = 0;
20
+ o += n * t;
21
+ }
22
+ return o;
23
+ }
24
+ function i() {
25
+ return r() >= e;
26
+ }
27
+ //#endregion
28
+ export { i as n, r, e as t };
@@ -13947,7 +13947,7 @@ var yd = 320, bd = "1.26.0", xd = "https://huggingface.co/deepghs/nudenet_onnx/r
13947
13947
  "BUTTOCKS_COVERED"
13948
13948
  ], wd = !1;
13949
13949
  function Td() {
13950
- wd ||= (S.wasm.wasmPaths = `https://cdn.jsdelivr.net/npm/onnxruntime-web@${bd}/dist/`, !0);
13950
+ wd ||= (S.wasm.wasmPaths = `https://cdn.jsdelivr.net/npm/onnxruntime-web@${bd}/dist/`, S.wasm.numThreads = 1, S.wasm.proxy = !1, !0);
13951
13951
  }
13952
13952
  var Ed = /* @__PURE__ */ new Map();
13953
13953
  function Dd(e) {
@@ -7,7 +7,8 @@ async function n(t) {
7
7
  if (!e) {
8
8
  let t = performance.now();
9
9
  console.log("[flaxia-node] vector-embed: loading pipeline model=onnx-community/Qwen3-Embedding-0.6B-ONNX device=wasm");
10
- let { pipeline: n } = await import("./transformers.web.js");
10
+ let { pipeline: n, env: r } = await import("./transformers.web.js");
11
+ r?.backends?.onnx?.wasm && (r.backends.onnx.wasm.numThreads = 1, r.backends.onnx.wasm.proxy = !1);
11
12
  try {
12
13
  e = await n("feature-extraction", "onnx-community/Qwen3-Embedding-0.6B-ONNX", { device: "wasm" });
13
14
  } catch (e) {
@@ -1 +1 @@
1
- {"version":3,"file":"SignalingClient.d.ts","sourceRoot":"","sources":["../../src/client/SignalingClient.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAK5D,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,YAAY,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAqQD,eAAO,MAAM,cAAc,GAAI,QAAQ,UAAU,SAehD,CAAC"}
1
+ {"version":3,"file":"SignalingClient.d.ts","sourceRoot":"","sources":["../../src/client/SignalingClient.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAK5D,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,YAAY,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA2RD,eAAO,MAAM,cAAc,GAAI,QAAQ,UAAU,SAsBhD,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=SignalingClient.incapable.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SignalingClient.incapable.test.d.ts","sourceRoot":"","sources":["../../../src/client/__tests__/SignalingClient.incapable.test.ts"],"names":[],"mappings":""}
@@ -1,3 +1,16 @@
1
+ declare function safeGet(key: string): string | null;
2
+ declare function safeSet(key: string, value: string): void;
3
+ declare function safeRemove(key: string): void;
1
4
  export declare const hasConsent: () => boolean;
2
5
  export declare const saveConsent: () => void;
6
+ export declare const safeLocalStorageGet: typeof safeGet;
7
+ export declare const safeLocalStorageSet: typeof safeSet;
8
+ export declare const safeLocalStorageRemove: typeof safeRemove;
9
+ /**
10
+ * Returns a UUID, falling back to a random v4 when `crypto.randomUUID` is
11
+ * unavailable (older browsers, or non-secure contexts where `crypto.randomUUID`
12
+ * is undefined on mobile Chrome). Never throws.
13
+ */
14
+ export declare const safeRandomUUID: () => string;
15
+ export {};
3
16
  //# sourceMappingURL=storage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/consent/storage.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,UAAU,QAAO,OAe7B,CAAC;AAEF,eAAO,MAAM,WAAW,QAAO,IAG9B,CAAC"}
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/consent/storage.ts"],"names":[],"mappings":"AAWA,iBAAS,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM3C;AAED,iBAAS,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAMjD;AAED,iBAAS,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAMrC;AAED,eAAO,MAAM,UAAU,QAAO,OAgB7B,CAAC;AAEF,eAAO,MAAM,WAAW,QAAO,IAG9B,CAAC;AAEF,eAAO,MAAM,mBAAmB,gBAAU,CAAC;AAC3C,eAAO,MAAM,mBAAmB,gBAAU,CAAC;AAC3C,eAAO,MAAM,sBAAsB,mBAAa,CAAC;AAEjD;;;;GAIG;AACH,eAAO,MAAM,cAAc,QAAO,MAajC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=memoryProbe.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memoryProbe.test.d.ts","sourceRoot":"","sources":["../../../src/executor/__tests__/memoryProbe.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ export declare const HEAVY_WORKLOAD_WASM_MEMORY_BYTES: number;
2
+ export declare function probeMaxWasmMemoryBytes(targetBytes?: number, chunkBytes?: number): number;
3
+ export declare function hasEnoughWasmMemoryForHeavy(): boolean;
4
+ //# sourceMappingURL=memoryProbe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memoryProbe.d.ts","sourceRoot":"","sources":["../../src/executor/memoryProbe.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,gCAAgC,QAAgB,CAAC;AAI9D,wBAAgB,uBAAuB,CACrC,WAAW,GAAE,MAAyC,EACtD,UAAU,GAAE,MAA0B,GACrC,MAAM,CA4BR;AAED,wBAAgB,2BAA2B,IAAI,OAAO,CAErD"}
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
+ import { r as e, t } from "./assets/memoryProbe.js";
1
2
  //#region src/consent/ConsentUI.ts
2
- var e = class {
3
+ var n = class {
3
4
  constructor(e, t, n) {
4
5
  this.shadow = e.attachShadow({ mode: "open" }), this.render(t, n);
5
6
  }
@@ -39,17 +40,47 @@ var e = class {
39
40
  c.remove(), t();
40
41
  }), this.shadow.appendChild(s), this.shadow.appendChild(c);
41
42
  }
42
- }, t = "flaxia_consent_granted", n = "flaxia_consent_expiry", r = 720 * 60 * 60 * 1e3, i = () => {
43
- if (localStorage.getItem(t) !== "true") return !1;
44
- let e = localStorage.getItem(n);
43
+ }, r = "flaxia_consent_granted", i = "flaxia_consent_expiry", a = 720 * 60 * 60 * 1e3, o = /* @__PURE__ */ new Map();
44
+ function s(e) {
45
+ try {
46
+ return localStorage.getItem(e);
47
+ } catch {
48
+ return o.get(e) ?? null;
49
+ }
50
+ }
51
+ function c(e, t) {
52
+ try {
53
+ localStorage.setItem(e, t);
54
+ } catch {
55
+ o.set(e, t);
56
+ }
57
+ }
58
+ function l(e) {
59
+ try {
60
+ localStorage.removeItem(e);
61
+ } catch {
62
+ o.delete(e);
63
+ }
64
+ }
65
+ var u = () => {
66
+ if (s(r) !== "true") return !1;
67
+ let e = s(i);
45
68
  if (e) {
46
- let r = parseInt(e, 10);
47
- if (Date.now() > r) return localStorage.removeItem(t), localStorage.removeItem(n), !1;
69
+ let t = parseInt(e, 10);
70
+ if (!Number.isFinite(t) || Date.now() > t) return l(r), l(i), !1;
48
71
  }
49
72
  return !0;
50
- }, a = () => {
51
- localStorage.setItem(t, "true"), localStorage.setItem(n, String(Date.now() + r));
52
- }, o = (...e) => console.log("[flaxia-node]", ...e), s = class {
73
+ }, d = () => {
74
+ c(r, "true"), c(i, String(Date.now() + a));
75
+ }, f = s, p = c, m = () => {
76
+ try {
77
+ if (typeof crypto < "u" && typeof crypto.randomUUID == "function") return crypto.randomUUID();
78
+ } catch {}
79
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (e) => {
80
+ let t = Math.random() * 16 | 0;
81
+ return (e === "x" ? t : t & 3 | 8).toString(16);
82
+ });
83
+ }, h = (...e) => console.log("[flaxia-node]", ...e), g = class {
53
84
  constructor(e, t = 3e5) {
54
85
  this.worker = null, this.queue = [], this.active = null, this._lastCpuLoad = 0, this.workerUrl = e || "/worker.js", this.defaultTimeoutMs = t, this.initWorker();
55
86
  }
@@ -63,66 +94,66 @@ var e = class {
63
94
  }, this.worker = e;
64
95
  }
65
96
  run(e, t, n, r, i, a) {
66
- return new Promise((s, c) => {
97
+ return new Promise((o, s) => {
67
98
  if (!this.worker) {
68
- c(/* @__PURE__ */ Error("Worker not available"));
99
+ s(/* @__PURE__ */ Error("Worker not available"));
69
100
  return;
70
101
  }
71
- let l = () => this.execute(e, t, n, r, i, a, s, c);
72
- this.active ? (o(`task queued id=${e} workload=${t} (active task running)`), this.queue.push(l)) : l();
102
+ let c = () => this.execute(e, t, n, r, i, a, o, s);
103
+ this.active ? (h(`task queued id=${e} workload=${t} (active task running)`), this.queue.push(c)) : c();
73
104
  });
74
105
  }
75
- execute(e, t, n, r, i, a, s, c) {
76
- let l = this.worker;
77
- if (!l) {
78
- c(/* @__PURE__ */ Error("Worker not available")), this.dequeue();
106
+ execute(e, t, n, r, i, a, o, s) {
107
+ let c = this.worker;
108
+ if (!c) {
109
+ s(/* @__PURE__ */ Error("Worker not available")), this.dequeue();
79
110
  return;
80
111
  }
81
- let u = r ?? this.defaultTimeoutMs, d = !1, f = performance.now();
82
- o(`task start id=${e} workload=${t} timeoutMs=${u}`);
83
- let p = (e) => {
84
- if (d) return;
85
- d = !0;
112
+ let l = r ?? this.defaultTimeoutMs, u = !1, d = performance.now();
113
+ h(`task start id=${e} workload=${t} timeoutMs=${l}`);
114
+ let f = (e) => {
115
+ if (u) return;
116
+ u = !0;
86
117
  let t = this.active;
87
118
  t && (clearTimeout(t.timer), t.removeListener()), this.active = null, e(), this.dequeue();
88
- }, m = (n) => {
89
- let { id: r, type: a, result: l, error: u, token: d, cpuLoad: m } = n.data;
119
+ }, p = (n) => {
120
+ let { id: r, type: a, result: c, error: l, token: u, cpuLoad: p } = n.data;
90
121
  if (r === e) {
91
122
  if (a === "token") {
92
- i?.(d);
123
+ i?.(u);
93
124
  return;
94
125
  }
95
126
  if (a === "heartbeat") {
96
- typeof m == "number" && Number.isFinite(m) && (this._lastCpuLoad = Math.min(1, Math.max(0, m)));
127
+ typeof p == "number" && Number.isFinite(p) && (this._lastCpuLoad = Math.min(1, Math.max(0, p)));
97
128
  return;
98
129
  }
99
- a === "done" ? (o(`task done id=${e} workload=${t} durationMs=${Math.round(performance.now() - f)}`), p(() => s(l))) : a === "error" ? (o(`task failed id=${e} workload=${t} error=${u}`), p(() => c(Error(u)))) : (o(`task unknown-message id=${e} type=${String(a)}`), p(() => c(/* @__PURE__ */ Error(`Unknown message type: ${String(a)}`))));
130
+ a === "done" ? (h(`task done id=${e} workload=${t} durationMs=${Math.round(performance.now() - d)}`), f(() => o(c))) : a === "error" ? (h(`task failed id=${e} workload=${t} error=${l}`), f(() => s(Error(l)))) : (h(`task unknown-message id=${e} type=${String(a)}`), f(() => s(/* @__PURE__ */ Error(`Unknown message type: ${String(a)}`))));
100
131
  }
101
- }, h = () => l.removeEventListener("message", m), g = setTimeout(() => {
102
- o(`task timeout id=${e} workload=${t} (worker terminated after ${u}ms)`), this.cleanupWorker(), p(() => c(/* @__PURE__ */ Error("TIMEOUT")));
103
- }, u);
132
+ }, m = () => c.removeEventListener("message", p), g = setTimeout(() => {
133
+ h(`task timeout id=${e} workload=${t} (worker terminated after ${l}ms)`), this.cleanupWorker(), f(() => s(/* @__PURE__ */ Error("TIMEOUT")));
134
+ }, l);
104
135
  this.active = {
105
136
  id: e,
106
- resolve: s,
107
- reject: c,
137
+ resolve: o,
138
+ reject: s,
108
139
  timer: g,
109
- worker: l,
110
- removeListener: h
111
- }, l.addEventListener("message", m);
140
+ worker: c,
141
+ removeListener: m
142
+ }, c.addEventListener("message", p);
112
143
  try {
113
- l.postMessage({
144
+ c.postMessage({
114
145
  id: e,
115
146
  workload: t,
116
147
  payload: n,
117
- timeoutMs: u,
148
+ timeoutMs: l,
118
149
  config: a
119
150
  });
120
151
  } catch (e) {
121
- p(() => c(e instanceof Error ? e : Error(String(e))));
152
+ f(() => s(e instanceof Error ? e : Error(String(e))));
122
153
  }
123
154
  }
124
155
  handleWorkerError(e) {
125
- o(`worker error error=${e.message}`);
156
+ h(`worker error error=${e.message}`);
126
157
  let t = this.active;
127
158
  this.cleanupWorker(), t && (clearTimeout(t.timer), this.active = null, t.reject(e), this.dequeue());
128
159
  }
@@ -142,13 +173,13 @@ var e = class {
142
173
  get lastCpuLoad() {
143
174
  return this._lastCpuLoad;
144
175
  }
145
- }, c = (...e) => console.log("[flaxia-node]", ...e), l = (...e) => console.error("[flaxia-node]", ...e), u = "flaxia_node_id", d = "flaxia_node_token", f = class {
176
+ }, _ = (...e) => console.log("[flaxia-node]", ...e), v = (...e) => console.error("[flaxia-node]", ...e), y = "flaxia_node_id", b = "flaxia_node_token", x = class {
146
177
  constructor(e, t, n) {
147
178
  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();
148
179
  }
149
180
  async connect() {
150
181
  if (this.destroyed) return;
151
- if (c(`connect nodeId=${this.nodeId}`), this.ws) {
182
+ if (_(`connect nodeId=${this.nodeId}`), this.ws) {
152
183
  let e = this.ws;
153
184
  e.onclose = null;
154
185
  try {
@@ -159,14 +190,14 @@ var e = class {
159
190
  this.setupVisibilityHandler();
160
191
  let e = await this.obtainToken();
161
192
  if (!e) {
162
- l("token acquisition failed; scheduling reconnect"), this.scheduleReconnect();
193
+ v("token acquisition failed; scheduling reconnect"), this.scheduleReconnect();
163
194
  return;
164
195
  }
165
196
  let t = this.config.orchestratorUrl.replace(/\/+$/, "").replace(/^http/, "ws"), n = new URL(`${t}/crowd/signal`);
166
197
  n.searchParams.set("token", e.token);
167
198
  let r = new WebSocket(n.toString());
168
199
  this.ws = r, r.onopen = () => {
169
- this.reconnectAttempts = 0, c(`signal connected ${n.toString()}`);
200
+ this.reconnectAttempts = 0, _(`signal connected ${n.toString()}`);
170
201
  }, r.onmessage = async (e) => {
171
202
  let t;
172
203
  try {
@@ -183,12 +214,12 @@ var e = class {
183
214
  }
184
215
  if (t.type === "task") {
185
216
  let e = t;
186
- c(`task received taskId=${e.taskId} workload=${e.workload} timeoutMs=${e.timeoutMs ?? "default"}`);
217
+ _(`task received taskId=${e.taskId} workload=${e.workload} timeoutMs=${e.timeoutMs ?? "default"}`);
187
218
  try {
188
219
  await this.handleTask(e);
189
220
  } catch (n) {
190
221
  let r = n instanceof Error ? n.message : String(n);
191
- l(`task failed taskId=${e.taskId} workload=${e.workload} error=${r}`), this.send({
222
+ v(`task failed taskId=${e.taskId} workload=${e.workload} error=${r}`), this.send({
192
223
  type: "error",
193
224
  taskId: String(t.taskId ?? ""),
194
225
  error: r
@@ -196,7 +227,7 @@ var e = class {
196
227
  }
197
228
  }
198
229
  }, r.onclose = () => {
199
- r.onclose = null, this.ws === r && (this.ws = null, !this.destroyed && (c(`signal disconnected; scheduling reconnect attempt=${this.reconnectAttempts + 1}`), this.scheduleReconnect()));
230
+ r.onclose = null, this.ws === r && (this.ws = null, !this.destroyed && (_(`signal disconnected; scheduling reconnect attempt=${this.reconnectAttempts + 1}`), this.scheduleReconnect()));
200
231
  };
201
232
  }
202
233
  scheduleReconnect() {
@@ -206,15 +237,21 @@ var e = class {
206
237
  }, e);
207
238
  }
208
239
  disconnect() {
209
- c(`disconnect nodeId=${this.nodeId}`), this.destroyed = !0, this.suspended = !1, this.removeVisibilityHandler();
240
+ _(`disconnect nodeId=${this.nodeId}`), this.destroyed = !0, this.suspended = !1, this.removeVisibilityHandler();
210
241
  try {
211
242
  this.ws?.close();
212
243
  } catch {}
213
244
  this.ws = null;
245
+ try {
246
+ delete window[C];
247
+ } catch {}
248
+ try {
249
+ this.workerPool.terminate();
250
+ } catch {}
214
251
  }
215
252
  suspend() {
216
253
  if (!(this.suspended || this.destroyed)) {
217
- if (c("suspended (visibility or manual)"), this.suspended = !0, this.ws) {
254
+ if (_("suspended (visibility or manual)"), this.suspended = !0, this.ws) {
218
255
  let e = this.ws;
219
256
  e.onclose = null;
220
257
  try {
@@ -226,35 +263,38 @@ var e = class {
226
263
  }
227
264
  }
228
265
  resume() {
229
- !this.suspended || this.destroyed || (c("resumed"), this.suspended = !1, this.workerPool.resume(), this.connect());
266
+ !this.suspended || this.destroyed || (_("resumed"), this.suspended = !1, this.workerPool.resume(), this.connect());
230
267
  }
231
268
  async obtainToken() {
232
269
  try {
233
- let e = localStorage.getItem(d);
234
- if (e) try {
235
- let t = JSON.parse(e);
236
- if (t.token && t.nodeId && t.expiresAt > Date.now() + 6e4) return c(`token cached nodeId=${t.nodeId} expiresIn=${Math.round((t.expiresAt - Date.now()) / 1e3)}s`), t;
270
+ let n = f(b);
271
+ if (n) try {
272
+ let e = JSON.parse(n);
273
+ if (e.token && e.nodeId && e.expiresAt > Date.now() + 6e4) return _(`token cached nodeId=${e.nodeId} expiresIn=${Math.round((e.expiresAt - Date.now()) / 1e3)}s`), e;
237
274
  } catch {}
238
- let t = this.config.orchestratorUrl.replace(/\/+$/, ""), n = await fetch(`${t}/crowd/nodes/register`, {
275
+ let r = e(), i = r >= t, a = i ? this.config.capabilities ?? ["ai-inference", "image-process"] : [];
276
+ _(`register capability probe capable=${i} wasmMemoryBytes=${r} capabilities=${JSON.stringify(a)}`);
277
+ let o = this.config.orchestratorUrl.replace(/\/+$/, ""), s = await fetch(`${o}/crowd/nodes/register`, {
239
278
  method: "POST",
240
279
  headers: { "Content-Type": "application/json" },
241
280
  body: JSON.stringify({
242
281
  siteId: this.config.siteId,
243
282
  nodeId: this.nodeId,
244
- capabilities: this.config.capabilities ?? ["ai-inference", "image-process"],
283
+ capabilities: a,
284
+ wasmMemoryBytes: e(),
245
285
  deviceMemory: typeof navigator.deviceMemory == "number" ? navigator.deviceMemory : null
246
286
  })
247
287
  });
248
- if (!n.ok) return l(`node register failed HTTP ${n.status} (${t}/crowd/nodes/register)`), null;
249
- let r = await n.json();
250
- if (!r.token) return l("node register returned no token"), null;
251
- c(`node registered nodeId=${this.nodeId} expiresIn=${Math.round((r.expiresAt - Date.now()) / 1e3)}s`);
288
+ if (!s.ok) return v(`node register failed HTTP ${s.status} (${o}/crowd/nodes/register)`), null;
289
+ let c = await s.json();
290
+ if (!c.token) return v("node register returned no token"), null;
291
+ _(`node registered nodeId=${this.nodeId} expiresIn=${Math.round((c.expiresAt - Date.now()) / 1e3)}s`);
252
292
  try {
253
- localStorage.setItem(d, JSON.stringify(r));
293
+ p(b, JSON.stringify(c));
254
294
  } catch {}
255
- return r;
295
+ return c;
256
296
  } catch (e) {
257
- return l("node register threw", e instanceof Error ? e.message : e), null;
297
+ return v("node register threw", e instanceof Error ? e.message : e), null;
258
298
  }
259
299
  }
260
300
  send(e) {
@@ -276,7 +316,7 @@ var e = class {
276
316
  type: "result",
277
317
  taskId: e.taskId,
278
318
  payload: r
279
- }), c(`task result sent taskId=${e.taskId} workload=${e.workload} durationMs=${Math.round(performance.now() - t)}`);
319
+ }), _(`task result sent taskId=${e.taskId} workload=${e.workload} durationMs=${Math.round(performance.now() - t)}`);
280
320
  } finally {
281
321
  this.inflightTasks.delete(e.taskId);
282
322
  }
@@ -289,22 +329,23 @@ var e = class {
289
329
  removeVisibilityHandler() {
290
330
  this.visibilityHandler &&= (document.removeEventListener("visibilitychange", this.visibilityHandler), null);
291
331
  }
292
- }, p = "__flaxia_node_signal_client", m = (e) => {
293
- let t = window[p];
332
+ }, S = "__flaxia_node_signal_client", C = "__flaxia_node_init_started", w = (e) => {
333
+ let t = window[S];
294
334
  t && t.disconnect();
295
- let n = new URL("./worker.js", "" + import.meta.url).href, r = new s(n), i = localStorage.getItem(u);
296
- i || (i = crypto.randomUUID(), localStorage.setItem(u, i));
297
- let a = new f(e, r, i);
298
- window[p] = a, a.connect();
299
- }, h = (t) => {
300
- if (i()) {
301
- m(t);
335
+ let n = new URL("./worker.js", "" + import.meta.url).href, r = new g(n), i = f(y);
336
+ i || (i = m(), p(y, i));
337
+ let a = new x(e, r, i);
338
+ window[S] = a, a.connect();
339
+ }, T = (e) => {
340
+ if (window[C]) return;
341
+ if (window[C] = !0, u()) {
342
+ w(e);
302
343
  return;
303
344
  }
304
- let n = document.createElement("div");
305
- n.id = "flaxia-consent-container", document.body.appendChild(n), new e(n, t.consent, () => {
306
- a(), n.remove(), m(t);
345
+ let t = document.createElement("div");
346
+ t.id = "flaxia-consent-container", document.body.appendChild(t), new n(t, e.consent, () => {
347
+ d(), t.remove(), w(e);
307
348
  });
308
349
  };
309
350
  //#endregion
310
- export { h as initFlaxiaNode };
351
+ export { T as initFlaxiaNode };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=main.worker.capable.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.worker.capable.test.d.ts","sourceRoot":"","sources":["../../../src/worker/__tests__/main.worker.capable.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=main.worker.incapable.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.worker.incapable.test.d.ts","sourceRoot":"","sources":["../../../src/worker/__tests__/main.worker.incapable.test.ts"],"names":[],"mappings":""}
package/dist/worker.js CHANGED
@@ -1,14 +1,15 @@
1
+ import { n as e, r as t, t as n } from "./assets/memoryProbe.js";
1
2
  //#region src/executor/throttle.ts
2
- function e(e) {
3
+ function r(e) {
3
4
  return new Promise((t) => setTimeout(t, e));
4
5
  }
5
- var t = 3e4, n = 3e4, r = class {
6
+ var i = 3e4, a = 3e4, o = class {
6
7
  constructor(e = .15) {
7
8
  this.windowStart = performance.now(), this.windowBusyMs = 0, this.lastLoad = 0, this.maxLoad = Math.max(.05, Math.min(.3, e));
8
9
  }
9
10
  markTaskComplete(e) {
10
- let n = performance.now();
11
- n - this.windowStart > t && (this.windowStart = n, this.windowBusyMs = 0), this.windowBusyMs += Math.max(0, e), this.lastLoad = this.estimate();
11
+ let t = performance.now();
12
+ t - this.windowStart > i && (this.windowStart = t, this.windowBusyMs = 0), this.windowBusyMs += Math.max(0, e), this.lastLoad = this.estimate();
12
13
  }
13
14
  estimate() {
14
15
  let e = performance.now() - this.windowStart;
@@ -17,9 +18,9 @@ var t = 3e4, n = 3e4, r = class {
17
18
  async shouldPause() {
18
19
  return this.estimate() > this.maxLoad;
19
20
  }
20
- async waitForSlot(t = n) {
21
- let r = performance.now();
22
- for (; await this.shouldPause() && !(performance.now() - r > t);) await e(500);
21
+ async waitForSlot(e = a) {
22
+ let t = performance.now();
23
+ for (; await this.shouldPause() && !(performance.now() - t > e);) await r(500);
23
24
  }
24
25
  get lastMeasuredLoad() {
25
26
  return this.lastLoad;
@@ -27,69 +28,67 @@ var t = 3e4, n = 3e4, r = class {
27
28
  get maxLoadValue() {
28
29
  return this.maxLoad;
29
30
  }
30
- }, i = null, a = new Set([
31
+ }, s = null, c = new Set([
31
32
  "ai-inference",
32
33
  "vector-embed",
33
34
  "vector-query",
34
35
  "nudenet",
35
36
  "image-process",
36
37
  "container"
37
- ]), o = 6e4;
38
- function s() {
39
- let e = navigator.deviceMemory;
40
- return typeof e == "number" && e >= 4;
38
+ ]), l = 6e4, u = t(), d = u >= n;
39
+ console.log(`[flaxia-node:worker] startup memory probe wasmMemoryBytes=${u} capable=${d}`);
40
+ function f() {
41
+ return e();
41
42
  }
42
- var c = /* @__PURE__ */ new Map(), l = null;
43
- function u() {
44
- for (let e of c.values()) try {
43
+ var p = /* @__PURE__ */ new Map(), m = null;
44
+ function h() {
45
+ for (let e of p.values()) try {
45
46
  e();
46
47
  } catch {}
47
- c.clear();
48
+ p.clear();
48
49
  }
49
- function d() {
50
- l && clearTimeout(l), l = setTimeout(() => {
51
- l = null, u();
52
- }, o);
50
+ function g() {
51
+ m && clearTimeout(m), m = setTimeout(() => {
52
+ m = null, h();
53
+ }, l);
53
54
  }
54
- async function f(e, t, n) {
55
+ async function _(e, t, n) {
55
56
  switch (e) {
56
57
  case "ai-inference":
57
58
  let r = await import("./assets/ai-inference.js");
58
- return c.set(e, r.releaseCache), await r.handleAiInference(t, n);
59
+ return p.set(e, r.releaseCache), await r.handleAiInference(t, n);
59
60
  case "image-process": return await (await import("./assets/image-process.js")).handleImageProcess(t);
60
61
  case "container": return await (await import("./assets/container.js")).handleContainer(t);
61
62
  case "vector-embed":
62
63
  let i = await import("./assets/vector-embed.js");
63
- return c.set(e, i.releaseCache), await i.handleVectorEmbed(t);
64
+ return p.set(e, i.releaseCache), await i.handleVectorEmbed(t);
64
65
  case "vector-store":
65
66
  let a = await import("./assets/vector-store.js");
66
- return c.set(e, a.releaseCache), await a.handleVectorStore(t);
67
+ return p.set(e, a.releaseCache), await a.handleVectorStore(t);
67
68
  case "vector-query":
68
69
  let o = await import("./assets/vector-query.js");
69
- return c.set(e, o.releaseCache), await o.handleVectorQuery(t);
70
+ return p.set(e, o.releaseCache), await o.handleVectorQuery(t);
70
71
  case "nudenet":
71
72
  let s = await import("./assets/nudenet.js");
72
- return c.set(e, s.releaseCache), await s.handleNudeNet(t);
73
+ return p.set(e, s.releaseCache), await s.handleNudeNet(t);
73
74
  default: throw Error(`Unknown workload type: ${e}`);
74
75
  }
75
76
  }
76
77
  self.onmessage = async (e) => {
77
- let { id: t, workload: n, payload: o, config: c } = e.data, l = performance.now();
78
+ let { id: t, workload: r, payload: i, config: a } = e.data, l = performance.now();
78
79
  try {
79
- if (i ||= new r(c?.maxCpuLoad), console.log(`[flaxia-node:worker] task start id=${t} workload=${n}`), a.has(n) && !s()) {
80
- let e = navigator.deviceMemory;
81
- throw Error(`${n}: insufficient device memory (deviceMemory=${e ?? "unknown"})`);
82
- }
83
- await i.waitForSlot();
80
+ if (s ||= new o(a?.maxCpuLoad), console.log(`[flaxia-node:worker] task start id=${t} workload=${r}`), !d) throw Error(`node incapable: insufficient WASM memory (${u} bytes < ${n}); rejecting all tasks`);
81
+ if (c.has(r) && !f()) throw Error(`${r}: insufficient WASM memory (${u} bytes < ${n})`);
82
+ await s.waitForSlot();
84
83
  let e = setInterval(() => {
85
84
  self.postMessage({
86
85
  id: t,
87
86
  type: "heartbeat",
88
- cpuLoad: i?.lastMeasuredLoad ?? 0
87
+ cpuLoad: s?.lastMeasuredLoad ?? 0
89
88
  });
90
- }, 1e4), u = performance.now();
89
+ }, 1e4), p = performance.now();
91
90
  try {
92
- let e = await f(n, o, (e) => {
91
+ let e = await _(r, i, (e) => {
93
92
  self.postMessage({
94
93
  id: t,
95
94
  type: "token",
@@ -100,16 +99,16 @@ self.onmessage = async (e) => {
100
99
  id: t,
101
100
  type: "done",
102
101
  result: e
103
- }), console.log(`[flaxia-node:worker] task done id=${t} workload=${n} durationMs=${Math.round(performance.now() - l)}`);
102
+ }), console.log(`[flaxia-node:worker] task done id=${t} workload=${r} durationMs=${Math.round(performance.now() - l)}`);
104
103
  } finally {
105
- clearInterval(e), i.markTaskComplete(performance.now() - u), d();
104
+ clearInterval(e), s.markTaskComplete(performance.now() - p), g();
106
105
  }
107
106
  } catch (e) {
108
- let r = e instanceof Error ? e.message : String(e);
109
- console.error(`[flaxia-node:worker] task error id=${t} workload=${n} error=${r}`), self.postMessage({
107
+ let n = e instanceof Error ? e.message : String(e);
108
+ console.error(`[flaxia-node:worker] task error id=${t} workload=${r} error=${n}`), self.postMessage({
110
109
  id: t,
111
110
  type: "error",
112
- error: r
111
+ error: n
113
112
  });
114
113
  }
115
114
  };
@@ -0,0 +1,2 @@
1
+ import '../ai-inference';
2
+ //# sourceMappingURL=wasm-threads.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wasm-threads.test.d.ts","sourceRoot":"","sources":["../../../src/workloads/__tests__/wasm-threads.test.ts"],"names":[],"mappings":"AAuBA,OAAO,iBAAiB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ai-inference.d.ts","sourceRoot":"","sources":["../../src/workloads/ai-inference.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAsB,MAAM,aAAa,CAAC;AAe7F;;;;GAIG;AACH,eAAO,MAAM,YAAY,QAAO,IAE/B,CAAC;AA4BF,eAAO,MAAM,iBAAiB,GAC5B,SAAS,kBAAkB,EAC3B,UAAU,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,KAChC,OAAO,CAAC,iBAAiB,CA2E3B,CAAC"}
1
+ {"version":3,"file":"ai-inference.d.ts","sourceRoot":"","sources":["../../src/workloads/ai-inference.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAsB,MAAM,aAAa,CAAC;AAe7F;;;;GAIG;AACH,eAAO,MAAM,YAAY,QAAO,IAE/B,CAAC;AAuCF,eAAO,MAAM,iBAAiB,GAC5B,SAAS,kBAAkB,EAC3B,UAAU,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,KAChC,OAAO,CAAC,iBAAiB,CAoE3B,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import type { NudeNetPayload, NudeNetResult } from '@flaxia/sdk';
2
+ export declare function configureOrt(): void;
2
3
  export declare const handleNudeNet: (payload: NudeNetPayload) => Promise<NudeNetResult>;
3
4
  export declare function releaseCache(): void;
4
5
  //# sourceMappingURL=nudenet.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"nudenet.d.ts","sourceRoot":"","sources":["../../src/workloads/nudenet.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoB,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA+KnF,eAAO,MAAM,aAAa,GAAU,SAAS,cAAc,KAAG,OAAO,CAAC,aAAa,CA6BlF,CAAC;AAEF,wBAAgB,YAAY,IAAI,IAAI,CAEnC"}
1
+ {"version":3,"file":"nudenet.d.ts","sourceRoot":"","sources":["../../src/workloads/nudenet.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoB,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAoCnF,wBAAgB,YAAY,IAAI,IAAI,CAUnC;AAuID,eAAO,MAAM,aAAa,GAAU,SAAS,cAAc,KAAG,OAAO,CAAC,aAAa,CA6BlF,CAAC;AAEF,wBAAgB,YAAY,IAAI,IAAI,CAEnC"}
@@ -1 +1 @@
1
- {"version":3,"file":"vector-embed.d.ts","sourceRoot":"","sources":["../../src/workloads/vector-embed.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAIzE,eAAO,MAAM,YAAY,QAAO,IAE/B,CAAC;AAEF,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA2C/F"}
1
+ {"version":3,"file":"vector-embed.d.ts","sourceRoot":"","sources":["../../src/workloads/vector-embed.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAIzE,eAAO,MAAM,YAAY,QAAO,IAE/B,CAAC;AAEF,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAiD/F"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flaxia/node",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "private": false,
5
5
  "main": "dist/index.js",
6
6
  "types": "./dist/index.d.ts",