@flaxia/node 0.3.7 → 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.
- package/README.md +43 -19
- package/dist/__tests__/consent-policy.test.d.ts +2 -0
- package/dist/__tests__/consent-policy.test.d.ts.map +1 -0
- package/dist/assets/VectorStoreEngine.js +140 -85
- package/dist/assets/ai-inference.js +173 -33
- package/dist/assets/container.js +368 -260
- package/dist/assets/dist.js +209 -0
- package/dist/assets/egress-guard.js +174 -0
- package/dist/assets/image-process.js +184 -19
- package/dist/assets/nudenet.js +2 -2
- package/dist/client/SignalingClient.d.ts +6 -0
- package/dist/client/SignalingClient.d.ts.map +1 -1
- package/dist/consent/ConsentUI.d.ts +44 -5
- package/dist/consent/ConsentUI.d.ts.map +1 -1
- package/dist/consent/notice.d.ts +29 -0
- package/dist/consent/notice.d.ts.map +1 -0
- package/dist/consent/storage.d.ts +91 -7
- package/dist/consent/storage.d.ts.map +1 -1
- package/dist/executor/WorkerPool.d.ts +35 -1
- package/dist/executor/WorkerPool.d.ts.map +1 -1
- package/dist/executor/__tests__/WorkerPool.swarm.test.d.ts +13 -0
- package/dist/executor/__tests__/WorkerPool.swarm.test.d.ts.map +1 -0
- package/dist/executor/__tests__/container-executor.test.d.ts +2 -0
- package/dist/executor/__tests__/container-executor.test.d.ts.map +1 -0
- package/dist/executor/__tests__/egress-guard.test.d.ts +2 -0
- package/dist/executor/__tests__/egress-guard.test.d.ts.map +1 -0
- package/dist/executor/__tests__/webgpuProbe.test.d.ts +2 -0
- package/dist/executor/__tests__/webgpuProbe.test.d.ts.map +1 -0
- package/dist/executor/container-executor.d.ts +49 -1
- package/dist/executor/container-executor.d.ts.map +1 -1
- package/dist/executor/egress-guard.d.ts +105 -0
- package/dist/executor/egress-guard.d.ts.map +1 -0
- package/dist/executor/memoryProbe.d.ts +25 -0
- package/dist/executor/memoryProbe.d.ts.map +1 -1
- package/dist/executor/throttle.d.ts +62 -4
- package/dist/executor/throttle.d.ts.map +1 -1
- package/dist/executor/webgpuProbe.d.ts +9 -0
- package/dist/executor/webgpuProbe.d.ts.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +766 -230
- package/dist/swarm/__tests__/adapter.test.d.ts +2 -0
- package/dist/swarm/__tests__/adapter.test.d.ts.map +1 -0
- package/dist/swarm/__tests__/controller.test.d.ts +2 -0
- package/dist/swarm/__tests__/controller.test.d.ts.map +1 -0
- package/dist/swarm/__tests__/defects.test.d.ts +16 -0
- package/dist/swarm/__tests__/defects.test.d.ts.map +1 -0
- package/dist/swarm/__tests__/hardening.test.d.ts +2 -0
- package/dist/swarm/__tests__/hardening.test.d.ts.map +1 -0
- package/dist/swarm/__tests__/runtime.test.d.ts +2 -0
- package/dist/swarm/__tests__/runtime.test.d.ts.map +1 -0
- package/dist/swarm/__tests__/session.test.d.ts +2 -0
- package/dist/swarm/__tests__/session.test.d.ts.map +1 -0
- package/dist/swarm/adapter.d.ts +115 -0
- package/dist/swarm/adapter.d.ts.map +1 -0
- package/dist/swarm/controller.d.ts +87 -0
- package/dist/swarm/controller.d.ts.map +1 -0
- package/dist/swarm/messages.d.ts +41 -0
- package/dist/swarm/messages.d.ts.map +1 -0
- package/dist/swarm/runtime.d.ts +16 -0
- package/dist/swarm/runtime.d.ts.map +1 -0
- package/dist/swarm/session.d.ts +73 -0
- package/dist/swarm/session.d.ts.map +1 -0
- package/dist/swarm-engine.js +7477 -0
- package/dist/vector-store/HNSWIndex.d.ts +30 -0
- package/dist/vector-store/HNSWIndex.d.ts.map +1 -1
- package/dist/vector-store/VectorStoreEngine.d.ts +43 -0
- package/dist/vector-store/VectorStoreEngine.d.ts.map +1 -1
- package/dist/vector-store/__tests__/HNSWIndex.test.d.ts +2 -0
- package/dist/vector-store/__tests__/HNSWIndex.test.d.ts.map +1 -0
- package/dist/vector-store/__tests__/VectorStoreEngine.test.d.ts +2 -0
- package/dist/vector-store/__tests__/VectorStoreEngine.test.d.ts.map +1 -0
- package/dist/worker/__tests__/main.worker.abort.test.d.ts +2 -0
- package/dist/worker/__tests__/main.worker.abort.test.d.ts.map +1 -0
- package/dist/worker/__tests__/main.worker.control.test.d.ts +2 -0
- package/dist/worker/__tests__/main.worker.control.test.d.ts.map +1 -0
- package/dist/worker.js +643 -67
- package/dist/workloads/__tests__/nudenet.test.d.ts +2 -0
- package/dist/workloads/__tests__/nudenet.test.d.ts.map +1 -0
- package/dist/workloads/ai-inference.d.ts +2 -1
- package/dist/workloads/ai-inference.d.ts.map +1 -1
- package/dist/workloads/ai-model-registry.d.ts +72 -0
- package/dist/workloads/ai-model-registry.d.ts.map +1 -0
- package/dist/workloads/container.d.ts +1 -1
- package/dist/workloads/container.d.ts.map +1 -1
- package/dist/workloads/image-process.d.ts +27 -0
- package/dist/workloads/image-process.d.ts.map +1 -1
- package/dist/workloads/nudenet.d.ts +8 -0
- package/dist/workloads/nudenet.d.ts.map +1 -1
- package/package.json +3 -2
- package/dist/assets/memoryProbe.js +0 -28
- package/dist/client/WebRTCPeer.d.ts +0 -8
- package/dist/client/WebRTCPeer.d.ts.map +0 -1
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version of the consent disclosure text below.
|
|
3
|
+
*
|
|
4
|
+
* Consent records are bound to this value: a record only counts as granted
|
|
5
|
+
* while it carries the *current* version, so bumping the version invalidates
|
|
6
|
+
* every existing grant and forces the visitor to see (and accept) the new
|
|
7
|
+
* wording. Increment it whenever `CONSENT_DISCLOSURE` changes in any way that
|
|
8
|
+
* a visitor would care about.
|
|
9
|
+
*
|
|
10
|
+
* - v1: legacy copy ("サイトのパフォーマンス向上にご協力ください。"), which never
|
|
11
|
+
* disclosed what actually runs on the device.
|
|
12
|
+
* - v2: the informed-consent copy below (third-party workloads, orchestrator
|
|
13
|
+
* registration, persistent connection, resource usage).
|
|
14
|
+
*/
|
|
15
|
+
export declare const CONSENT_NOTICE_VERSION = 2;
|
|
16
|
+
/**
|
|
17
|
+
* The disclosure shown in the built-in banner. Deliberately static: hosts may
|
|
18
|
+
* style the banner but must not be able to weaken the wording, otherwise the
|
|
19
|
+
* recorded notice version would no longer describe what the visitor saw.
|
|
20
|
+
*/
|
|
21
|
+
export declare const CONSENT_DISCLOSURE: {
|
|
22
|
+
readonly summary: "同意すると、このブラウザは第三者から依頼された処理をバックグラウンドで実行します。";
|
|
23
|
+
readonly items: readonly ["実行する処理: 顧客(第三者)が依頼したワークロード。任意の WebAssembly コンテナの実行や、画像の NSFW(成人向け)判定などを含みます。", "接続と登録: オーケストレーターへ WebSocket で常時接続し、端末の性能や対応ワークロードを登録します。", "資源の使用: 待機中も接続を維持し、処理の実行中は CPU・GPU・通信・バッテリーを消費します。", "タスクの出所: 処理はこのサイトの運営者ではなく、第三者(顧客)から割り当てられます。"];
|
|
24
|
+
/** Shown while the accept button is inside its minimum-visible window. */
|
|
25
|
+
readonly acceptGateHint: "開示内容を確認できるよう、「同意して開始」はしばらくの間押せません。";
|
|
26
|
+
readonly acceptLabel: "同意して開始";
|
|
27
|
+
readonly rejectLabel: "拒否";
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=notice.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notice.d.ts","sourceRoot":"","sources":["../../src/consent/notice.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC;;;;GAIG;AACH,eAAO,MAAM,kBAAkB;;;IAS7B,0EAA0E;;;;CAKlE,CAAC"}
|
|
@@ -1,20 +1,89 @@
|
|
|
1
1
|
import type { ConsentState } from '@flaxia/sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Maximum lifetime of a stored consent grant: 180 days.
|
|
4
|
+
*
|
|
5
|
+
* The lifetime is bounded on purpose — consent is not permanent, and the
|
|
6
|
+
* disclosure shown to the visitor describes what the node does *today*, so a
|
|
7
|
+
* grant must be renewed periodically. Records that claim a longer lifetime are
|
|
8
|
+
* rejected (see `isRecordFresh`).
|
|
9
|
+
*/
|
|
10
|
+
export declare const CONSENT_MAX_TTL_MS: number;
|
|
2
11
|
declare function safeGet(key: string): string | null;
|
|
3
12
|
declare function safeSet(key: string, value: string): void;
|
|
4
13
|
declare function safeRemove(key: string): void;
|
|
14
|
+
/**
|
|
15
|
+
* Persistent store for the non-extractable HMAC key. The key is a `CryptoKey`,
|
|
16
|
+
* so it cannot be exported as raw bytes; persisting it in IndexedDB (which
|
|
17
|
+
* structured-clones `CryptoKey` objects) keeps forgery out of reach of scripts
|
|
18
|
+
* that can only write strings into `localStorage`.
|
|
19
|
+
*/
|
|
20
|
+
export interface ConsentKeyStore {
|
|
21
|
+
load(): Promise<CryptoKey | null>;
|
|
22
|
+
save(key: CryptoKey): Promise<void>;
|
|
23
|
+
clear(): Promise<void>;
|
|
24
|
+
}
|
|
5
25
|
export declare const hasConsent: () => boolean;
|
|
6
|
-
/** Persist consent. Clears any previous denial so the two never co-exist. */
|
|
7
|
-
export declare const saveConsent: () => void;
|
|
8
26
|
export declare const hasDenial: () => boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Resolve the persisted consent state.
|
|
29
|
+
*
|
|
30
|
+
* Synchronous and fail-closed: until {@link initConsentIntegrity} has verified
|
|
31
|
+
* the stored record (or a grant is made in this document) the answer is not
|
|
32
|
+
* `'granted'`. A stored grant still wins over a stored denial, but the two are
|
|
33
|
+
* kept mutually exclusive by the save helpers.
|
|
34
|
+
*/
|
|
35
|
+
export declare const getConsentState: () => ConsentState;
|
|
36
|
+
/**
|
|
37
|
+
* Load (or create) the non-extractable HMAC key and verify the stored consent
|
|
38
|
+
* record. Idempotent and never rejects. Hosts should await this before relying
|
|
39
|
+
* on {@link getConsentState}; callers that cannot wait still fail closed.
|
|
40
|
+
*/
|
|
41
|
+
export declare const initConsentIntegrity: () => Promise<ConsentState>;
|
|
42
|
+
/**
|
|
43
|
+
* Persist consent (clears any previous denial). Synchronous, as required by the
|
|
44
|
+
* controller and by host consent callbacks.
|
|
45
|
+
*
|
|
46
|
+
* The grant is only accepted when it is authorized:
|
|
47
|
+
* - `ConsentUI` minted a one-shot gesture token from a click on the accept
|
|
48
|
+
* button (the visitor saw the banner and acted), or
|
|
49
|
+
* - the host explicitly opted in via {@link setHostManagedConsentAllowed}.
|
|
50
|
+
*
|
|
51
|
+
* Otherwise the call is refused with a warning and the state stays not-granted,
|
|
52
|
+
* so a host that calls `accept()` without rendering a banner cannot silently
|
|
53
|
+
* consent. When WebCrypto is unavailable the grant is limited to the current
|
|
54
|
+
* document (nothing unverifiable is written to storage).
|
|
55
|
+
*/
|
|
56
|
+
export declare const saveConsent: () => void;
|
|
57
|
+
/**
|
|
58
|
+
* Async variant of {@link saveConsent} that resolves once the record is sealed
|
|
59
|
+
* and readable again. Same authorization requirements.
|
|
60
|
+
*/
|
|
61
|
+
export declare const grantConsent: (options?: {
|
|
62
|
+
ttlMs?: number;
|
|
63
|
+
}) => Promise<ConsentState>;
|
|
64
|
+
/**
|
|
65
|
+
* Mint the one-shot authorization consumed by the next {@link saveConsent} /
|
|
66
|
+
* {@link grantConsent} call. Only the built-in `ConsentUI` accept button calls
|
|
67
|
+
* this, from a click handler that runs after the minimum-visible duration.
|
|
68
|
+
*/
|
|
69
|
+
export declare const markUserGestureConsent: (noticeVersion?: number) => void;
|
|
70
|
+
/**
|
|
71
|
+
* Opt in to host-managed consent (default: disabled).
|
|
72
|
+
*
|
|
73
|
+
* Disabled by default so a host-supplied `onConsentRequired` callback cannot
|
|
74
|
+
* grant consent headlessly. Hosts that render their own disclosure UI must call
|
|
75
|
+
* this before granting, and remain responsible for showing the current
|
|
76
|
+
* disclosure text to the visitor.
|
|
77
|
+
*/
|
|
78
|
+
export declare const setHostManagedConsentAllowed: (allowed: boolean) => void;
|
|
79
|
+
export declare const isHostManagedConsentAllowed: () => boolean;
|
|
9
80
|
/** Persist denial. Clears any previous consent/expiry so the two never co-exist. */
|
|
10
81
|
export declare const saveDenial: () => void;
|
|
11
|
-
/** Forget the consent decision entirely (granted + expiry + denial). */
|
|
12
|
-
export declare const clearConsent: () => void;
|
|
13
82
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
83
|
+
* Revoke consent: forget the decision entirely (granted + expiry + denial) and
|
|
84
|
+
* drop the HMAC key so copies of the old record can no longer verify.
|
|
16
85
|
*/
|
|
17
|
-
export declare const
|
|
86
|
+
export declare const clearConsent: () => void;
|
|
18
87
|
export declare const safeLocalStorageGet: typeof safeGet;
|
|
19
88
|
export declare const safeLocalStorageSet: typeof safeSet;
|
|
20
89
|
export declare const safeLocalStorageRemove: typeof safeRemove;
|
|
@@ -24,5 +93,20 @@ export declare const safeLocalStorageRemove: typeof safeRemove;
|
|
|
24
93
|
* is undefined on mobile Chrome). Never throws.
|
|
25
94
|
*/
|
|
26
95
|
export declare const safeRandomUUID: () => string;
|
|
96
|
+
/** @internal Drop every in-memory grant/key so the next read re-verifies. */
|
|
97
|
+
declare function resetIntegrityCache(): void;
|
|
98
|
+
/**
|
|
99
|
+
* @internal Test-only seams. Production code never calls these; they exist so
|
|
100
|
+
* unit tests can simulate a reload (key store), a foreign origin, or an
|
|
101
|
+
* integrity-cache reset without weakening any production default.
|
|
102
|
+
*/
|
|
103
|
+
export declare const __consentTestHooks: {
|
|
104
|
+
setKeyStore(store: ConsentKeyStore | null): void;
|
|
105
|
+
setOrigin(origin: string | null): void;
|
|
106
|
+
resetIntegrityCache: typeof resetIntegrityCache;
|
|
107
|
+
reset(): void;
|
|
108
|
+
/** Seed a valid grant as if the visitor had accepted the banner. */
|
|
109
|
+
seedGrantedConsent(noticeVersion?: number): void;
|
|
110
|
+
};
|
|
27
111
|
export {};
|
|
28
112
|
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/consent/storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/consent/storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,QAA4B,CAAC;AAoC5D,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;AA2BD;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IAClC,IAAI,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAwTD,eAAO,MAAM,UAAU,QAAO,OAI7B,CAAC;AAEF,eAAO,MAAM,SAAS,QAAO,OAE5B,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,QAAO,YAIlC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,QAAO,OAAO,CAAC,YAAY,CAG3D,CAAC;AAoHF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,WAAW,QAAO,IAU9B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAU,UAAU;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,KAAG,OAAO,CAAC,YAAY,CAWrF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,GACjC,gBAAe,MAA+B,KAC7C,IAEF,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,GAAI,SAAS,OAAO,KAAG,IAE/D,CAAC;AAEF,eAAO,MAAM,2BAA2B,QAAO,OAAoC,CAAC;AAEpF,oFAAoF;AACpF,eAAO,MAAM,UAAU,QAAO,IAQ7B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,YAAY,QAAO,IAa/B,CAAC;AAEF,eAAO,MAAM,mBAAmB,gBAAU,CAAC;AAC3C,eAAO,MAAM,mBAAmB,gBAAU,CAAC;AAC3C,eAAO,MAAM,sBAAsB,mBAAa,CAAC;AA6CjD;;;;GAIG;AACH,eAAO,MAAM,cAAc,QAAO,MAajC,CAAC;AAEF,6EAA6E;AAC7E,iBAAS,mBAAmB,IAAI,IAAI,CASnC;AAED;;;;GAIG;AACH,eAAO,MAAM,kBAAkB;uBACV,eAAe,GAAG,IAAI,GAAG,IAAI;sBAG9B,MAAM,GAAG,IAAI,GAAG,IAAI;;aAI7B,IAAI;IAMb,oEAAoE;uCAClC,MAAM,GAA4B,IAAI;CAIzE,CAAC"}
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import type { WorkloadType } from "@flaxia/sdk";
|
|
2
|
+
/** Swarm tasks exchange control messages and binary frames mid-task. */
|
|
3
|
+
export interface SwarmCallbacks {
|
|
4
|
+
onFrame?: (frame: ArrayBuffer) => void;
|
|
5
|
+
onMessage?: (message: unknown) => void;
|
|
6
|
+
}
|
|
2
7
|
/**
|
|
3
8
|
* Executes tasks against a single Web Worker.
|
|
4
9
|
*
|
|
@@ -16,13 +21,42 @@ export declare class WorkerPool {
|
|
|
16
21
|
private workerUrl;
|
|
17
22
|
private queue;
|
|
18
23
|
private active;
|
|
24
|
+
/** Control messages that arrived for a task that has not started yet. */
|
|
25
|
+
private pendingControls;
|
|
26
|
+
private static readonly MAX_PENDING_CONTROLS;
|
|
19
27
|
private _lastCpuLoad;
|
|
20
28
|
constructor(workerUrl?: string, timeoutMs?: number);
|
|
21
29
|
private initWorker;
|
|
22
30
|
run(id: string, workload: WorkloadType, payload: unknown, timeoutMs?: number, onToken?: (token: string) => void, config?: {
|
|
23
31
|
maxCpuLoad?: number;
|
|
24
|
-
|
|
32
|
+
fileSourceOrigins?: string[];
|
|
33
|
+
containerImageOrigins?: string[];
|
|
34
|
+
}, swarm?: SwarmCallbacks): Promise<unknown>;
|
|
25
35
|
private execute;
|
|
36
|
+
/** Hand over the control messages that were waiting for this task to start. */
|
|
37
|
+
private flushControls;
|
|
38
|
+
/**
|
|
39
|
+
* Post a message to the active task's worker. Used by the signaling client to
|
|
40
|
+
* push swarm control messages and hidden-state frames into a running session.
|
|
41
|
+
*/
|
|
42
|
+
private postToActive;
|
|
43
|
+
/**
|
|
44
|
+
* Deliver a swarm control message to the task it names. A message that
|
|
45
|
+
* arrives while that task is still queued is held until it starts; posting it
|
|
46
|
+
* into whichever task happens to be running would hand it to the wrong
|
|
47
|
+
* session (and drop the intended one).
|
|
48
|
+
*/
|
|
49
|
+
sendControl(message: unknown, executionId?: string): boolean;
|
|
50
|
+
sendFrame(frame: ArrayBuffer): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* The coordinator settled this task elsewhere (timeout, a peer failed, the
|
|
53
|
+
* plan was rejected): stop it.
|
|
54
|
+
*
|
|
55
|
+
* A queued task is dropped before it ever starts. A running task is asked to
|
|
56
|
+
* stop and the slot is released only when the worker itself reports done or
|
|
57
|
+
* error, so two tasks can never end up in the same worker.
|
|
58
|
+
*/
|
|
59
|
+
abort(id: string, reason: string): boolean;
|
|
26
60
|
private handleWorkerError;
|
|
27
61
|
private dequeue;
|
|
28
62
|
private cleanupWorker;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkerPool.d.ts","sourceRoot":"","sources":["../../src/executor/WorkerPool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"WorkerPool.d.ts","sourceRoot":"","sources":["../../src/executor/WorkerPool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAoBhD,wEAAwE;AACxE,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IACvC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACxC;AAED;;;;;;;;;;GAUG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,KAAK,CAAoB;IACjC,OAAO,CAAC,MAAM,CAA2B;IACzC,yEAAyE;IACzE,OAAO,CAAC,eAAe,CAAmD;IAC1E,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAM;IAClD,OAAO,CAAC,YAAY,CAAK;gBAEb,SAAS,CAAC,EAAE,MAAM,EAAE,SAAS,SAAS;IAMlD,OAAO,CAAC,UAAU;IAYlB,GAAG,CACD,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,OAAO,EAChB,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,EACjC,MAAM,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,EAChG,KAAK,CAAC,EAAE,cAAc,GACrB,OAAO,CAAC,OAAO,CAAC;IAgBnB,OAAO,CAAC,OAAO;IA6Ff,+EAA+E;IAC/E,OAAO,CAAC,aAAa;IAOrB;;;OAGG;IACH,OAAO,CAAC,YAAY;IAUpB;;;;;OAKG;IACH,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO;IAW5D,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO;IAItC;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO;IAmB1C,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,OAAO;IAKf,OAAO,CAAC,aAAa;IAQrB,SAAS;IAkBT,MAAM;IAMN,IAAI,WAAW,IAAI,MAAM,CAExB;CACF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression test for swarm control-message routing, written from the
|
|
3
|
+
* feature/swarm-inference quality review and kept after the fix landed.
|
|
4
|
+
*
|
|
5
|
+
* Do not weaken it to make the suite green — if it starts failing, the defect
|
|
6
|
+
* it documents has come back.
|
|
7
|
+
*
|
|
8
|
+
* M3 `sendControl` must post to the task the message names, never to
|
|
9
|
+
* whichever task happens to be running; a queued swarm session has to
|
|
10
|
+
* receive its control message when it starts.
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=WorkerPool.swarm.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkerPool.swarm.test.d.ts","sourceRoot":"","sources":["../../../src/executor/__tests__/WorkerPool.swarm.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container-executor.test.d.ts","sourceRoot":"","sources":["../../../src/executor/__tests__/container-executor.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"egress-guard.test.d.ts","sourceRoot":"","sources":["../../../src/executor/__tests__/egress-guard.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webgpuProbe.test.d.ts","sourceRoot":"","sources":["../../../src/executor/__tests__/webgpuProbe.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,3 +1,51 @@
|
|
|
1
1
|
import type { ContainerPayload, ContainerResult } from "@flaxia/sdk";
|
|
2
|
-
|
|
2
|
+
/** Maximum size of a container WASM image (128 MiB). */
|
|
3
|
+
export declare const MAX_CONTAINER_IMAGE_BYTES: number;
|
|
4
|
+
/** Aggregate decoded input-file ceiling; keeps reference downloads bounded. */
|
|
5
|
+
export declare const MAX_CONTAINER_INPUT_BYTES: number;
|
|
6
|
+
/** Memory bounds for `memoryLimitMb` (clamped): 32 MiB .. 4 GiB. */
|
|
7
|
+
export declare const MIN_CONTAINER_MEMORY_MB = 32;
|
|
8
|
+
export declare const MAX_CONTAINER_MEMORY_MB = 4096;
|
|
9
|
+
/** Default memory cap when the payload omits `memoryLimitMb`. */
|
|
10
|
+
export declare const DEFAULT_CONTAINER_MEMORY_MB = 512;
|
|
11
|
+
/**
|
|
12
|
+
* Replace the container image origin allowlist. Hosts/operators call this once
|
|
13
|
+
* at start-up; entries must be exact origins (`https://cdn.example.com`).
|
|
14
|
+
*/
|
|
15
|
+
export declare function configureContainerImageOrigins(origins: readonly string[]): void;
|
|
16
|
+
/** Origins currently allowed to serve container images (empty = disabled). */
|
|
17
|
+
export declare function getAllowedContainerImageOrigins(): readonly string[];
|
|
18
|
+
/**
|
|
19
|
+
* Validate a container image URL. The origin allowlist is the primary control;
|
|
20
|
+
* the shared egress guard additionally rejects loopback/private hosts,
|
|
21
|
+
* non-default ports, credentials, non-HTTPS schemes and non-`.wasm` paths.
|
|
22
|
+
*/
|
|
23
|
+
export declare function validateImageUrl(urlStr: string, origins?: readonly string[]): URL;
|
|
24
|
+
export interface WasmMemoryLimits {
|
|
25
|
+
/** Declared minimum memory in bytes (0 when the module does not declare any). */
|
|
26
|
+
initialBytes: number;
|
|
27
|
+
/** Declared maximum memory in bytes, or null when the module declares none. */
|
|
28
|
+
maximumBytes: number | null;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Read the memory section of a WASM binary.
|
|
32
|
+
*
|
|
33
|
+
* A WASI module exports its own `WebAssembly.Memory`, so the shim cannot inject
|
|
34
|
+
* a capped memory: the only pre-execution guarantee available in the browser is
|
|
35
|
+
* to inspect what the module *declares* and refuse to instantiate when it is
|
|
36
|
+
* allowed to exceed `memoryLimitMb`. See `docs/04-workloads.md` for the exact
|
|
37
|
+
* guarantee this does (and does not) provide.
|
|
38
|
+
*/
|
|
39
|
+
export declare function parseWasmMemoryLimits(binary: Uint8Array): WasmMemoryLimits;
|
|
40
|
+
/** Clamp `memoryLimitMb` into the supported range. */
|
|
41
|
+
export declare function resolveMemoryLimitMb(requested?: number): number;
|
|
42
|
+
/**
|
|
43
|
+
* Enforce the payload's memory cap against the module's declared memory limits.
|
|
44
|
+
* Rejects a module without an explicit maximum, one that could grow past the
|
|
45
|
+
* cap, or one that needs more than the cap just to start.
|
|
46
|
+
*/
|
|
47
|
+
export declare function assertWasmMemoryWithinLimit(binary: Uint8Array, limitMb: number): WasmMemoryLimits;
|
|
48
|
+
/** Decode inline files and download scoped references before mounting either. */
|
|
49
|
+
export declare function resolveContainerFiles(payload: Pick<ContainerPayload, 'files' | 'fileSources'>, allowedFileSourceOrigins?: readonly string[]): Promise<Map<string, Uint8Array>>;
|
|
50
|
+
export declare const runContainer: (payload: ContainerPayload, allowedFileSourceOrigins?: readonly string[], containerImageOrigins?: readonly string[]) => Promise<ContainerResult>;
|
|
3
51
|
//# sourceMappingURL=container-executor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"container-executor.d.ts","sourceRoot":"","sources":["../../src/executor/container-executor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"container-executor.d.ts","sourceRoot":"","sources":["../../src/executor/container-executor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAuB,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAc1F,wDAAwD;AACxD,eAAO,MAAM,yBAAyB,QAAoB,CAAC;AAK3D,+EAA+E;AAC/E,eAAO,MAAM,yBAAyB,QAAmB,CAAC;AAG1D,oEAAoE;AACpE,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAC1C,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAC5C,iEAAiE;AACjE,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAa/C;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAa/E;AAED,8EAA8E;AAC9E,wBAAgB,+BAA+B,IAAI,SAAS,MAAM,EAAE,CAEnE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,SAAS,MAAM,EAAwB,GAAG,GAAG,CAyBtG;AAED,MAAM,WAAW,gBAAgB;IAC/B,iFAAiF;IACjF,YAAY,EAAE,MAAM,CAAC;IACrB,+EAA+E;IAC/E,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,UAAU,GAAG,gBAAgB,CAmD1E;AAgBD,sDAAsD;AACtD,wBAAgB,oBAAoB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAM/D;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAiBjG;AA+CD,iFAAiF;AACjF,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,IAAI,CAAC,gBAAgB,EAAE,OAAO,GAAG,aAAa,CAAC,EACxD,wBAAwB,GAAE,SAAS,MAAM,EAAO,GAC/C,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAgElC;AAED,eAAO,MAAM,YAAY,GACvB,SAAS,gBAAgB,EACzB,2BAA0B,SAAS,MAAM,EAAO,EAChD,wBAAuB,SAAS,MAAM,EAAwB,KAC7D,OAAO,CAAC,eAAe,CA8FzB,CAAC"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node-side egress guard for every workload that fetches a customer-supplied
|
|
3
|
+
* URL (container WASM images, nudenet image URLs, ...).
|
|
4
|
+
*
|
|
5
|
+
* A volunteer node runs inside the visitor's browser, so a customer-supplied
|
|
6
|
+
* URL turns that visitor's residential IP into a request proxy (SSRF): the
|
|
7
|
+
* browser will happily reach loopback, the visitor's LAN, CGNAT/Tailscale
|
|
8
|
+
* addresses, cloud metadata endpoints and `.local`/`.internal` names. The guard
|
|
9
|
+
* below is the single place that decides whether a URL may be fetched at all.
|
|
10
|
+
*
|
|
11
|
+
* What it enforces:
|
|
12
|
+
* - `https:` only, no embedded credentials (`user:pass@host`);
|
|
13
|
+
* - the host may not be, or resolve syntactically to, loopback / private /
|
|
14
|
+
* link-local / CGNAT / ULA / IPv4-mapped-IPv6 / unspecified / `0.0.0.0/8` /
|
|
15
|
+
* multicast / reserved space, and may not end in `.local` or `.internal`;
|
|
16
|
+
* - only the default HTTPS port is allowed;
|
|
17
|
+
* - redirects are followed manually and every hop is re-validated (an
|
|
18
|
+
* environment that hides `Location` on a manual redirect gets the request
|
|
19
|
+
* rejected instead — fail closed);
|
|
20
|
+
* - `Content-Type` must be on the caller's allowlist;
|
|
21
|
+
* - the body is streamed and aborted once it passes the byte cap (the
|
|
22
|
+
* `Content-Length` header is never trusted);
|
|
23
|
+
* - an `AbortSignal` timeout bounds the whole exchange.
|
|
24
|
+
*
|
|
25
|
+
* Residual risk (documented, not silently ignored): the browser resolves the
|
|
26
|
+
* hostname, so a DNS name that only *later* resolves to a private address
|
|
27
|
+
* cannot be detected from JavaScript without a DNS API. IP literals and
|
|
28
|
+
* private-looking names are rejected here; public names are additionally
|
|
29
|
+
* protected by the browser's Private Network Access checks.
|
|
30
|
+
*/
|
|
31
|
+
/** Hard default response-size cap (8 MiB) when a caller does not set one. */
|
|
32
|
+
export declare const DEFAULT_MAX_EGRESS_BYTES: number;
|
|
33
|
+
/** Hard ceiling for any caller-provided cap (256 MiB). */
|
|
34
|
+
export declare const MAX_EGRESS_BYTES: number;
|
|
35
|
+
/** Default whole-exchange timeout. */
|
|
36
|
+
export declare const DEFAULT_EGRESS_TIMEOUT_MS = 30000;
|
|
37
|
+
/** Redirect hops we are willing to re-validate. */
|
|
38
|
+
export declare const MAX_EGRESS_REDIRECTS = 3;
|
|
39
|
+
/** Only the default HTTPS port is allowed: odd ports are a common SSRF pivot. */
|
|
40
|
+
export declare const ALLOWED_EGRESS_PORTS: number[];
|
|
41
|
+
export interface EgressRequest {
|
|
42
|
+
/** Absolute URL to fetch. */
|
|
43
|
+
url: string | URL;
|
|
44
|
+
/** `Content-Type` prefixes (or exact media types) accepted for the body. */
|
|
45
|
+
allowContentTypes: readonly string[];
|
|
46
|
+
/** Maximum response body size in bytes (clamped to `MAX_EGRESS_BYTES`). */
|
|
47
|
+
maxBytes?: number;
|
|
48
|
+
/** Whole-exchange timeout in ms (applied with `AbortSignal.timeout`). */
|
|
49
|
+
timeoutMs?: number;
|
|
50
|
+
/** Extra request headers (validated: hop-by-hop headers are not allowed). */
|
|
51
|
+
headers?: Record<string, string>;
|
|
52
|
+
/** HTTP method; only GET/HEAD are meaningful for these workloads. */
|
|
53
|
+
method?: 'GET' | 'HEAD';
|
|
54
|
+
}
|
|
55
|
+
export interface EgressResult {
|
|
56
|
+
/** Final URL after the (manually validated) redirect chain. */
|
|
57
|
+
url: string;
|
|
58
|
+
status: number;
|
|
59
|
+
ok: boolean;
|
|
60
|
+
/** `Content-Type` of the final response, lowercased without parameters. */
|
|
61
|
+
contentType: string;
|
|
62
|
+
/** Full body bytes; empty for HEAD or an error status. */
|
|
63
|
+
bytes: Uint8Array<ArrayBuffer>;
|
|
64
|
+
byteLength: number;
|
|
65
|
+
}
|
|
66
|
+
export interface EgressGuardOptions {
|
|
67
|
+
/** Override the accepted ports (tests / non-default deployments). */
|
|
68
|
+
allowedPorts?: readonly number[];
|
|
69
|
+
/** Allow `http:` as well as `https:`. Never enable in production. */
|
|
70
|
+
allowInsecure?: boolean;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* True when a dotted-decimal IPv4 literal belongs to a range a volunteer node
|
|
74
|
+
* must never reach.
|
|
75
|
+
*/
|
|
76
|
+
export declare function isBlockedIPv4(host: string): boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Expand an IPv6 literal to its eight 16-bit groups, or return null when the
|
|
79
|
+
* text is not a valid IPv6 address. Handles `::` compression, a trailing
|
|
80
|
+
* embedded IPv4 (`::ffff:10.0.0.5`) and IPv4-compatible forms.
|
|
81
|
+
*/
|
|
82
|
+
export declare function parseIPv6(host: string): number[] | null;
|
|
83
|
+
/**
|
|
84
|
+
* True when an IPv6 literal is an address a volunteer node must never reach:
|
|
85
|
+
* unspecified (`::`), loopback (`::1`), IPv4-mapped/compatible IPv6 (the
|
|
86
|
+
* browser connects to the embedded IPv4), ULA (`fc00::/7`), link-local
|
|
87
|
+
* (`fe80::/10`), multicast (`ff00::/8`) and reserved space.
|
|
88
|
+
*/
|
|
89
|
+
export declare function isBlockedIPv6(host: string): boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Validate a hostname (or IP literal) independently of the URL parser. Exported
|
|
92
|
+
* so workloads can pre-check a host and so the rules are unit-testable.
|
|
93
|
+
*/
|
|
94
|
+
export declare function assertPublicHostname(hostname: string, options?: EgressGuardOptions): void;
|
|
95
|
+
/**
|
|
96
|
+
* Validate an egress URL: protocol, credentials, port and host. Returns the
|
|
97
|
+
* parsed `URL` so callers can reuse it (and so redirect hops share one path).
|
|
98
|
+
*/
|
|
99
|
+
export declare function assertPublicUrl(input: string | URL, options?: EgressGuardOptions): URL;
|
|
100
|
+
/**
|
|
101
|
+
* Fetch a customer-supplied URL through the guard. Redirects are resolved
|
|
102
|
+
* manually so each hop is re-validated; the body is capped while streaming.
|
|
103
|
+
*/
|
|
104
|
+
export declare function fetchGuarded(request: EgressRequest, options?: EgressGuardOptions): Promise<EgressResult>;
|
|
105
|
+
//# sourceMappingURL=egress-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"egress-guard.d.ts","sourceRoot":"","sources":["../../src/executor/egress-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,6EAA6E;AAC7E,eAAO,MAAM,wBAAwB,QAAkB,CAAC;AACxD,0DAA0D;AAC1D,eAAO,MAAM,gBAAgB,QAAoB,CAAC;AAClD,sCAAsC;AACtC,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAChD,mDAAmD;AACnD,eAAO,MAAM,oBAAoB,IAAI,CAAC;AACtC,iFAAiF;AACjF,eAAO,MAAM,oBAAoB,UAAQ,CAAC;AAM1C,MAAM,WAAW,aAAa;IAC5B,6BAA6B;IAC7B,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;IAClB,4EAA4E;IAC5E,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,qEAAqE;IACrE,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,+DAA+D;IAC/D,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,OAAO,CAAC;IACZ,2EAA2E;IAC3E,WAAW,EAAE,MAAM,CAAC;IACpB,0DAA0D;IAC1D,KAAK,EAAE,UAAU,CAAC,WAAW,CAAC,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,qEAAqE;IACrE,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,qEAAqE;IACrE,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAaD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAyBnD;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,CAqDvD;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAgBnD;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,IAAI,CAoB7F;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,EAAE,OAAO,GAAE,kBAAuB,GAAG,GAAG,CAyB1F;AAmFD;;;GAGG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,aAAa,EACtB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,YAAY,CAAC,CAqEvB"}
|
|
@@ -1,4 +1,29 @@
|
|
|
1
1
|
export declare const HEAVY_WORKLOAD_WASM_MEMORY_BYTES: number;
|
|
2
|
+
/**
|
|
3
|
+
* Probe a bounded lower bound of memory this runtime can commit. The function
|
|
4
|
+
* stops at `targetBytes`; it deliberately does not explore the engine maximum.
|
|
5
|
+
* Only the first call per page allocates/touches memory. If a later caller asks
|
|
6
|
+
* for a higher target, return the already-proven lower bound instead of
|
|
7
|
+
* committing more memory during startup.
|
|
8
|
+
*/
|
|
2
9
|
export declare function probeMaxWasmMemoryBytes(targetBytes?: number, chunkBytes?: number): number;
|
|
10
|
+
/**
|
|
11
|
+
* The device's committed WebAssembly memory, probed at most once per page.
|
|
12
|
+
* This is the cheap accessor every call site (registration, reconnect,
|
|
13
|
+
* capability reporting) should use instead of `probeMaxWasmMemoryBytes()`.
|
|
14
|
+
*/
|
|
15
|
+
export declare function getWasmMemoryBytes(): number;
|
|
16
|
+
/**
|
|
17
|
+
* Whether the device can commit the memory a heavy (multi-GB model) workload
|
|
18
|
+
* needs. Uses the cached probe, so it never re-allocates.
|
|
19
|
+
*/
|
|
3
20
|
export declare function hasEnoughWasmMemoryForHeavy(): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Drop the memoized probe and reset the run counter. Only for tests that
|
|
23
|
+
* install a fake WebAssembly implementation; production code never needs to
|
|
24
|
+
* reset the cache.
|
|
25
|
+
*/
|
|
26
|
+
export declare function resetWasmMemoryProbeCache(): void;
|
|
27
|
+
/** How many times the real probe ran (diagnostics / tests). */
|
|
28
|
+
export declare function getWasmMemoryProbeRuns(): number;
|
|
4
29
|
//# sourceMappingURL=memoryProbe.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memoryProbe.d.ts","sourceRoot":"","sources":["../../src/executor/memoryProbe.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"memoryProbe.d.ts","sourceRoot":"","sources":["../../src/executor/memoryProbe.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,gCAAgC,QAAgB,CAAC;AA4B9D;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,GAAE,MAAyC,EACtD,UAAU,GAAE,MAA0B,GACrC,MAAM,CA4BR;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAG3C;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,IAAI,OAAO,CAErD;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAGhD;AAED,+DAA+D;AAC/D,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C"}
|
|
@@ -1,22 +1,80 @@
|
|
|
1
|
+
/** Rolling window over which the busy ratio is estimated. */
|
|
2
|
+
export declare const THROTTLE_WINDOW_MS = 30000;
|
|
3
|
+
/** How long `waitForSlot()` waits for the rolling load to drop. */
|
|
4
|
+
export declare const DEFAULT_WAIT_SLOT_MS = 30000;
|
|
5
|
+
/** Continuous work allowed between two mid-execution duty-cycle pauses. */
|
|
6
|
+
export declare const DUTY_CYCLE_BUDGET_MS = 200;
|
|
7
|
+
/**
|
|
8
|
+
* Thrown when `waitForSlot()` cannot find a slot within its budget.
|
|
9
|
+
*
|
|
10
|
+
* It replaces the old behaviour of starting the task anyway: a node that is
|
|
11
|
+
* already over its CPU budget must not force-start a heavy task at 100% CPU.
|
|
12
|
+
* The worker turns this into a retryable task error so the orchestrator can
|
|
13
|
+
* move the task to an idle node.
|
|
14
|
+
*/
|
|
15
|
+
export declare class ThrottleBusyError extends Error {
|
|
16
|
+
readonly load: number;
|
|
17
|
+
readonly maxLoad: number;
|
|
18
|
+
readonly waitedMs: number;
|
|
19
|
+
readonly retryable = true;
|
|
20
|
+
constructor(load: number, maxLoad: number, waitedMs: number);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Keeps the Worker's average CPU usage within `maxLoad` without busy-waiting.
|
|
24
|
+
*
|
|
25
|
+
* Load is estimated from the work the worker charges over a rolling window
|
|
26
|
+
* (`markTaskComplete` plus the duty-cycle pauses below) rather than from a
|
|
27
|
+
* calibrated busy-loop, which itself burned CPU on slow devices.
|
|
28
|
+
*
|
|
29
|
+
* Two controls exist:
|
|
30
|
+
* - `waitForSlot()` gates the *start* of a task. When the budget is exhausted
|
|
31
|
+
* it throws `ThrottleBusyError` instead of starting the task anyway.
|
|
32
|
+
* - `yieldIfOverloaded()` limits the *execution* of a long task. Workloads
|
|
33
|
+
* call it between streaming tokens/batches; after `DUTY_CYCLE_BUDGET_MS` of
|
|
34
|
+
* continuous work it sleeps for the time needed to hold the configured duty
|
|
35
|
+
* cycle, so a 10-minute generation cannot pin a core at 100%.
|
|
36
|
+
*/
|
|
1
37
|
export declare class CpuThrottle {
|
|
2
38
|
private readonly maxLoad;
|
|
3
39
|
private windowStart;
|
|
4
40
|
private windowBusyMs;
|
|
5
41
|
private lastLoad;
|
|
42
|
+
/** Timestamp of the first unpaused work unit of the current duty cycle. */
|
|
43
|
+
private dutyStartedAt;
|
|
6
44
|
constructor(maxLoad?: number);
|
|
7
45
|
/**
|
|
8
|
-
* Charge a completed task's wall-clock duration (in ms) against the CPU
|
|
9
|
-
* Call this from the worker once a workload has finished (incl.
|
|
46
|
+
* Charge a completed task's wall-clock duration (in ms) against the CPU
|
|
47
|
+
* budget. Call this from the worker once a workload has finished (incl.
|
|
48
|
+
* errors/timeouts).
|
|
10
49
|
*/
|
|
11
50
|
markTaskComplete(durationMs: number): void;
|
|
51
|
+
/** Start a fresh duty cycle before executing a task. */
|
|
52
|
+
beginWork(): void;
|
|
53
|
+
private resetDutyCycle;
|
|
54
|
+
private rollWindow;
|
|
55
|
+
/**
|
|
56
|
+
* Recompute the rolling busy ratio, treating `work` ms as the work charged
|
|
57
|
+
* into the current window. Returns the ratio (0..1).
|
|
58
|
+
*/
|
|
12
59
|
private estimate;
|
|
13
60
|
shouldPause(): Promise<boolean>;
|
|
14
61
|
/**
|
|
15
62
|
* Waits until the rolling busy ratio is back under `maxLoad`.
|
|
16
|
-
*
|
|
17
|
-
*
|
|
63
|
+
*
|
|
64
|
+
* @throws ThrottleBusyError when the budget is exhausted while the device is
|
|
65
|
+
* still over budget. Starting the task anyway is what made the previous
|
|
66
|
+
* implementation a no-op, so this is deliberately fail-closed.
|
|
18
67
|
*/
|
|
19
68
|
waitForSlot(maxWaitMs?: number): Promise<void>;
|
|
69
|
+
/**
|
|
70
|
+
* Cooperative mid-execution limiting: after a continuous burst of
|
|
71
|
+
* `DUTY_CYCLE_BUDGET_MS`, sleep long enough that the burst's share of wall
|
|
72
|
+
* time matches `maxLoad`. Call between streaming tokens or batch iterations.
|
|
73
|
+
*
|
|
74
|
+
* Returns the number of ms slept (0 when the caller is inside its duty
|
|
75
|
+
* cycle), which makes the behaviour directly testable.
|
|
76
|
+
*/
|
|
77
|
+
yieldIfOverloaded(): Promise<number>;
|
|
20
78
|
get lastMeasuredLoad(): number;
|
|
21
79
|
get maxLoadValue(): number;
|
|
22
80
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"throttle.d.ts","sourceRoot":"","sources":["../../src/executor/throttle.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"throttle.d.ts","sourceRoot":"","sources":["../../src/executor/throttle.ts"],"names":[],"mappings":"AAIA,6DAA6D;AAC7D,eAAO,MAAM,kBAAkB,QAAS,CAAC;AACzC,mEAAmE;AACnE,eAAO,MAAM,oBAAoB,QAAS,CAAC;AAG3C,2EAA2E;AAC3E,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC;;;;;;;GAOG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAGxC,QAAQ,CAAC,IAAI,EAAE,MAAM;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM;IAJ3B,QAAQ,CAAC,SAAS,QAAQ;gBAEf,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM;CAO5B;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,QAAQ,CAAK;IACrB,2EAA2E;IAC3E,OAAO,CAAC,aAAa,CAAuB;gBAEhC,OAAO,SAAO;IAI1B;;;;OAIG;IACH,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAK1C,wDAAwD;IACxD,SAAS,IAAI,IAAI;IAIjB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,UAAU;IAQlB;;;OAGG;IACH,OAAO,CAAC,QAAQ;IAWV,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAKrC;;;;;;OAMG;IACG,WAAW,CAAC,SAAS,SAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAclE;;;;;;;OAOG;IACG,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;IAkB1C,IAAI,gBAAgB,IAAI,MAAM,CAE7B;IAED,IAAI,YAAY,IAAI,MAAM,CAEzB;CACF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { SwarmNodeCapabilities } from '@flaxia/sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Probe WebGPU support so the orchestrator can decide whether a node may take
|
|
4
|
+
* part in `swarm-inference`. Never throws: any failure (no `navigator.gpu`,
|
|
5
|
+
* adapter request rejected, blocked by permissions policy) is reported as
|
|
6
|
+
* `{ webgpu: false }`.
|
|
7
|
+
*/
|
|
8
|
+
export declare function probeWebGpu(): Promise<SwarmNodeCapabilities>;
|
|
9
|
+
//# sourceMappingURL=webgpuProbe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webgpuProbe.d.ts","sourceRoot":"","sources":["../../src/executor/webgpuProbe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAoBzD;;;;;GAKG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,qBAAqB,CAAC,CA6BlE"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { initFlaxiaNode } from './client/SignalingClient';
|
|
2
2
|
export { getConsentState as getFlaxiaNodeConsentState } from './consent/storage';
|
|
3
|
+
export { initConsentIntegrity as initFlaxiaNodeConsent } from './consent/storage';
|
|
4
|
+
export { setHostManagedConsentAllowed as setFlaxiaNodeHostManagedConsent } from './consent/storage';
|
|
3
5
|
export { initFlaxiaNode };
|
|
4
6
|
export type { ConsentControls, ConsentState, FlaxiaNodeController } from '@flaxia/sdk';
|
|
5
7
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAO1D,OAAO,EAAE,eAAe,IAAI,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAGjF,OAAO,EAAE,oBAAoB,IAAI,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAIlF,OAAO,EAAE,4BAA4B,IAAI,+BAA+B,EAAE,MAAM,mBAAmB,CAAC;AACpG,OAAO,EAAE,cAAc,EAAE,CAAC;AAC1B,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC"}
|