@endge/computation-sandbox 0.1.16 → 0.2.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/dist/QuickJSComputationSandbox.d.ts +7 -7
- package/dist/assets/{computation-sandbox.worker-D1PJv1Tp.js → computation-sandbox.worker-BX0goQiF.js} +12 -12
- package/dist/computation-sandbox.js +91 -83
- package/dist/modules/EndgeComputationSandbox_Module.d.ts +15 -0
- package/dist/worker/QuickJSComputationVM.d.ts +6 -6
- package/package.json +5 -5
|
@@ -3,16 +3,16 @@ export interface QuickJSComputationSandboxOptions {
|
|
|
3
3
|
workerCount?: number;
|
|
4
4
|
watchdogMs?: number;
|
|
5
5
|
}
|
|
6
|
-
/**
|
|
6
|
+
/** Адаптер пакетного пула Worker для runtime вычислений ядра. */
|
|
7
7
|
export declare class QuickJSComputationSandbox implements ComputationSandboxAdapter {
|
|
8
|
-
private readonly
|
|
9
|
-
private readonly
|
|
10
|
-
private
|
|
11
|
-
private
|
|
12
|
-
private
|
|
8
|
+
private readonly _workers;
|
|
9
|
+
private readonly _queue;
|
|
10
|
+
private _nextId;
|
|
11
|
+
private _scheduled;
|
|
12
|
+
private _disposed;
|
|
13
13
|
constructor(options?: QuickJSComputationSandboxOptions);
|
|
14
14
|
execute(request: ComputationSandboxRequest): Promise<unknown>;
|
|
15
15
|
dispose(): void;
|
|
16
|
-
private
|
|
16
|
+
private _flush;
|
|
17
17
|
}
|
|
18
18
|
export declare function createQuickJSComputationSandbox(options?: QuickJSComputationSandboxOptions): QuickJSComputationSandbox;
|
|
@@ -161794,20 +161794,20 @@ Additional information: BADCLIENT: Bad error code, ${h} not found in range ${o}.
|
|
|
161794
161794
|
var xft = Nft(), Hde = /* @__PURE__ */ Sft(xft);
|
|
161795
161795
|
class Tft {
|
|
161796
161796
|
constructor(Bt = {}) {
|
|
161797
|
-
dN(this, "
|
|
161798
|
-
dN(this, "
|
|
161799
|
-
dN(this, "
|
|
161800
|
-
dN(this, "
|
|
161801
|
-
dN(this, "
|
|
161802
|
-
this.
|
|
161797
|
+
dN(this, "_quickJs", vft(nft));
|
|
161798
|
+
dN(this, "_moduleSources", /* @__PURE__ */ new Map());
|
|
161799
|
+
dN(this, "_executionTimeoutMs");
|
|
161800
|
+
dN(this, "_memoryLimitBytes");
|
|
161801
|
+
dN(this, "_stackLimitBytes");
|
|
161802
|
+
this._executionTimeoutMs = Bt.executionTimeoutMs ?? 250, this._memoryLimitBytes = Bt.memoryLimitBytes ?? 32 * 1024 * 1024, this._stackLimitBytes = Bt.stackLimitBytes ?? 512 * 1024;
|
|
161803
161803
|
}
|
|
161804
161804
|
async execute(Bt) {
|
|
161805
|
-
Tz(Bt.inputs, "inputs"), this.
|
|
161806
|
-
const Lr = (await this.
|
|
161807
|
-
Lr.setMemoryLimit(this.
|
|
161805
|
+
Tz(Bt.inputs, "inputs"), this._moduleSources.has(Bt.moduleKey) || this._moduleSources.set(Bt.moduleKey, Rft(Bt.source));
|
|
161806
|
+
const Lr = (await this._quickJs).newRuntime();
|
|
161807
|
+
Lr.setMemoryLimit(this._memoryLimitBytes), Lr.setMaxStackSize(this._stackLimitBytes), Lr.setInterruptHandler(wft(Date.now() + this._executionTimeoutMs));
|
|
161808
161808
|
const Qn = Lr.newContext();
|
|
161809
161809
|
try {
|
|
161810
|
-
const JA = Qn.evalCode(Mft(this.
|
|
161810
|
+
const JA = Qn.evalCode(Mft(this._moduleSources.get(Bt.moduleKey), Bt.inputs));
|
|
161811
161811
|
if (JA.error) {
|
|
161812
161812
|
const ra = Qn.dump(JA.error);
|
|
161813
161813
|
throw JA.error.dispose(), new Error(Lft(ra));
|
|
@@ -161987,7 +161987,7 @@ function Lft(Ge) {
|
|
|
161987
161987
|
return typeof Ge == "object" && Ge && "message" in Ge ? String(Ge.message) : String(Ge);
|
|
161988
161988
|
}
|
|
161989
161989
|
const Pft = new Tft();
|
|
161990
|
-
|
|
161990
|
+
globalThis.onmessage = async (Ge) => {
|
|
161991
161991
|
var $e;
|
|
161992
161992
|
if ((($e = Ge.data) == null ? void 0 : $e.type) !== "execute-batch")
|
|
161993
161993
|
return;
|
|
@@ -161999,7 +161999,7 @@ self.onmessage = async (Ge) => {
|
|
|
161999
161999
|
} catch (Qn) {
|
|
162000
162000
|
Bt.push({ id: Lr.id, ok: !1, message: Qn instanceof Error ? Qn.message : String(Qn) });
|
|
162001
162001
|
}
|
|
162002
|
-
|
|
162002
|
+
globalThis.postMessage({ type: "execute-batch-result", results: Bt });
|
|
162003
162003
|
};
|
|
162004
162004
|
var Uft = class {
|
|
162005
162005
|
constructor(Ge) {
|
|
@@ -1,132 +1,140 @@
|
|
|
1
1
|
var a = Object.defineProperty;
|
|
2
|
-
var h = (
|
|
3
|
-
var s = (
|
|
4
|
-
import {
|
|
5
|
-
class
|
|
6
|
-
constructor(e = {}) {
|
|
7
|
-
s(this, "workers");
|
|
8
|
-
s(this, "queue", []);
|
|
9
|
-
s(this, "nextId", 1);
|
|
10
|
-
s(this, "scheduled", !1);
|
|
11
|
-
s(this, "disposed", !1);
|
|
12
|
-
const t = typeof navigator > "u" ? 2 : navigator.hardwareConcurrency || 2, r = e.workerCount ?? Math.min(4, Math.max(1, t - 1)), i = e.watchdogMs ?? 500;
|
|
13
|
-
this.workers = Array.from({ length: r }, () => new l(i));
|
|
14
|
-
}
|
|
15
|
-
execute(e) {
|
|
16
|
-
return this.disposed ? Promise.reject(new Error("Computation sandbox is disposed.")) : new Promise((t, r) => {
|
|
17
|
-
this.queue.push({ id: this.nextId++, request: e, resolve: t, reject: r }), this.scheduled || (this.scheduled = !0, queueMicrotask(() => this.flush()));
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
dispose() {
|
|
21
|
-
this.disposed = !0;
|
|
22
|
-
for (const e of this.queue)
|
|
23
|
-
e.reject(new Error("Computation sandbox is disposed."));
|
|
24
|
-
this.queue.splice(0);
|
|
25
|
-
for (const e of this.workers)
|
|
26
|
-
e.dispose();
|
|
27
|
-
}
|
|
28
|
-
flush() {
|
|
29
|
-
if (this.scheduled = !1, this.disposed || !this.queue.length)
|
|
30
|
-
return;
|
|
31
|
-
const e = Array.from({ length: this.workers.length }, () => []);
|
|
32
|
-
let t = 0;
|
|
33
|
-
for (; this.queue.length; )
|
|
34
|
-
e[t++ % e.length].push(this.queue.shift());
|
|
35
|
-
e.forEach((r, i) => {
|
|
36
|
-
r.length && this.workers[i].execute(r);
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
class l {
|
|
2
|
+
var h = (i, e, t) => e in i ? a(i, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : i[e] = t;
|
|
3
|
+
var s = (i, e, t) => h(i, typeof e != "symbol" ? e + "" : e, t);
|
|
4
|
+
import { EndgeModule as d, Endge as n } from "@endge/core";
|
|
5
|
+
class _ {
|
|
41
6
|
constructor(e) {
|
|
42
|
-
s(this, "
|
|
43
|
-
s(this, "
|
|
44
|
-
s(this, "
|
|
45
|
-
s(this, "
|
|
46
|
-
s(this, "
|
|
47
|
-
s(this, "
|
|
48
|
-
this.
|
|
7
|
+
s(this, "_worker", this._createWorker());
|
|
8
|
+
s(this, "_queued", []);
|
|
9
|
+
s(this, "_active", null);
|
|
10
|
+
s(this, "_timer", null);
|
|
11
|
+
s(this, "_busy", !1);
|
|
12
|
+
s(this, "_disposed", !1);
|
|
13
|
+
this._watchdogMs = e;
|
|
49
14
|
}
|
|
50
15
|
execute(e) {
|
|
51
|
-
if (this.
|
|
16
|
+
if (this._disposed) {
|
|
52
17
|
for (const t of e)
|
|
53
18
|
t.reject(new Error("Computation Worker was disposed."));
|
|
54
19
|
return;
|
|
55
20
|
}
|
|
56
|
-
this.
|
|
21
|
+
this._queued.push(e), this._pump();
|
|
57
22
|
}
|
|
58
23
|
dispose() {
|
|
59
|
-
this.
|
|
60
|
-
for (const e of this.
|
|
24
|
+
this._disposed = !0, this._timer && clearTimeout(this._timer), this._timer = null, this._worker.terminate();
|
|
25
|
+
for (const e of this._active ?? [])
|
|
61
26
|
e.reject(new Error("Computation Worker was disposed."));
|
|
62
|
-
for (const e of this.
|
|
27
|
+
for (const e of this._queued)
|
|
63
28
|
for (const t of e)
|
|
64
29
|
t.reject(new Error("Computation Worker was disposed."));
|
|
65
|
-
this.
|
|
30
|
+
this._active = null, this._queued.splice(0), this._busy = !1;
|
|
66
31
|
}
|
|
67
|
-
|
|
68
|
-
if (this.
|
|
32
|
+
_pump() {
|
|
33
|
+
if (this._disposed || this._busy || !this._queued.length)
|
|
69
34
|
return;
|
|
70
|
-
this.
|
|
71
|
-
const e = this.
|
|
72
|
-
this.
|
|
73
|
-
this.
|
|
35
|
+
this._busy = !0;
|
|
36
|
+
const e = this._queued.shift();
|
|
37
|
+
this._active = e, this._timer = setTimeout(() => {
|
|
38
|
+
this._worker.terminate(), this._worker = this._createWorker();
|
|
74
39
|
for (const t of e)
|
|
75
|
-
t.reject(new Error(`Computation Worker exceeded ${this.
|
|
76
|
-
this.
|
|
77
|
-
}, this.
|
|
78
|
-
this.
|
|
79
|
-
const r = new Map(t.data.results.map((
|
|
80
|
-
for (const
|
|
81
|
-
const u = r.get(
|
|
82
|
-
u ? u.ok ?
|
|
40
|
+
t.reject(new Error(`Computation Worker exceeded ${this._watchdogMs} ms watchdog.`));
|
|
41
|
+
this._active = null, this._timer = null, this._busy = !1, this._pump();
|
|
42
|
+
}, this._watchdogMs), this._worker.onmessage = (t) => {
|
|
43
|
+
this._timer && clearTimeout(this._timer), this._timer = null;
|
|
44
|
+
const r = new Map(t.data.results.map((o) => [o.id, o]));
|
|
45
|
+
for (const o of e) {
|
|
46
|
+
const u = r.get(o.id);
|
|
47
|
+
u ? u.ok ? o.resolve(u.value) : o.reject(new Error(u.message)) : o.reject(new Error("Computation Worker returned no result."));
|
|
83
48
|
}
|
|
84
|
-
this.
|
|
85
|
-
}, this.
|
|
86
|
-
this.
|
|
49
|
+
this._active = null, this._busy = !1, this._pump();
|
|
50
|
+
}, this._worker.onerror = (t) => {
|
|
51
|
+
this._timer && clearTimeout(this._timer), this._timer = null;
|
|
87
52
|
for (const r of e)
|
|
88
53
|
r.reject(new Error(t.message || "Computation Worker failed."));
|
|
89
|
-
this.
|
|
90
|
-
}, this.
|
|
54
|
+
this._worker.terminate(), this._worker = this._createWorker(), this._active = null, this._busy = !1, this._pump();
|
|
55
|
+
}, this._worker.postMessage({
|
|
91
56
|
type: "execute-batch",
|
|
92
57
|
requests: e.map(({ id: t, request: r }) => ({ id: t, request: r }))
|
|
93
58
|
});
|
|
94
59
|
}
|
|
95
|
-
|
|
60
|
+
_createWorker() {
|
|
96
61
|
return new Worker(new URL(
|
|
97
62
|
/* @vite-ignore */
|
|
98
|
-
"" + new URL("assets/computation-sandbox.worker-
|
|
63
|
+
"" + new URL("assets/computation-sandbox.worker-BX0goQiF.js", import.meta.url).href,
|
|
99
64
|
import.meta.url
|
|
100
65
|
), { type: "module" });
|
|
101
66
|
}
|
|
102
67
|
}
|
|
103
|
-
|
|
104
|
-
|
|
68
|
+
class c {
|
|
69
|
+
constructor(e = {}) {
|
|
70
|
+
s(this, "_workers");
|
|
71
|
+
s(this, "_queue", []);
|
|
72
|
+
s(this, "_nextId", 1);
|
|
73
|
+
s(this, "_scheduled", !1);
|
|
74
|
+
s(this, "_disposed", !1);
|
|
75
|
+
const t = typeof navigator > "u" ? 2 : navigator.hardwareConcurrency || 2, r = e.workerCount ?? Math.min(4, Math.max(1, t - 1)), o = e.watchdogMs ?? 500;
|
|
76
|
+
this._workers = Array.from({ length: r }, () => new _(o));
|
|
77
|
+
}
|
|
78
|
+
execute(e) {
|
|
79
|
+
return this._disposed ? Promise.reject(new Error("Computation sandbox is disposed.")) : new Promise((t, r) => {
|
|
80
|
+
this._queue.push({ id: this._nextId++, request: e, resolve: t, reject: r }), this._scheduled || (this._scheduled = !0, queueMicrotask(() => this._flush()));
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
dispose() {
|
|
84
|
+
this._disposed = !0;
|
|
85
|
+
for (const e of this._queue)
|
|
86
|
+
e.reject(new Error("Computation sandbox is disposed."));
|
|
87
|
+
this._queue.splice(0);
|
|
88
|
+
for (const e of this._workers)
|
|
89
|
+
e.dispose();
|
|
90
|
+
}
|
|
91
|
+
_flush() {
|
|
92
|
+
if (this._scheduled = !1, this._disposed || !this._queue.length)
|
|
93
|
+
return;
|
|
94
|
+
const e = Array.from({ length: this._workers.length }, () => []);
|
|
95
|
+
let t = 0;
|
|
96
|
+
for (; this._queue.length; )
|
|
97
|
+
e[t++ % e.length].push(this._queue.shift());
|
|
98
|
+
e.forEach((r, o) => {
|
|
99
|
+
r.length && this._workers[o].execute(r);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function l(i) {
|
|
104
|
+
return new c(i);
|
|
105
105
|
}
|
|
106
|
-
class
|
|
106
|
+
class m extends d {
|
|
107
107
|
constructor() {
|
|
108
108
|
super(...arguments);
|
|
109
|
-
|
|
109
|
+
/** Активный sandbox adapter текущего lifecycle. */
|
|
110
|
+
s(this, "_adapter", null);
|
|
110
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* ----------------------------------------
|
|
114
|
+
* PUBLIC
|
|
115
|
+
* ----------------------------------------
|
|
116
|
+
*/
|
|
117
|
+
/** Создаёт и подключает sandbox adapter перед запуском runtime. */
|
|
111
118
|
setup() {
|
|
112
|
-
this.
|
|
119
|
+
this._adapter = l(), n.computations.setSandboxAdapter(this._adapter);
|
|
113
120
|
}
|
|
121
|
+
/** Отключает adapter и освобождает ссылку текущего lifecycle. */
|
|
114
122
|
reset() {
|
|
115
|
-
n.
|
|
123
|
+
n.computations.setSandboxAdapter(null), this._adapter = null;
|
|
116
124
|
}
|
|
117
125
|
}
|
|
118
|
-
const
|
|
126
|
+
const w = {
|
|
119
127
|
id: "@endge/computation-sandbox",
|
|
120
128
|
install() {
|
|
121
129
|
n.defineModule({
|
|
122
130
|
key: "computationSandbox",
|
|
123
|
-
module: new
|
|
131
|
+
module: new m(),
|
|
124
132
|
before: "runtime"
|
|
125
133
|
});
|
|
126
134
|
}
|
|
127
135
|
};
|
|
128
136
|
export {
|
|
129
|
-
|
|
137
|
+
w as EndgeComputationSandboxPlugin,
|
|
130
138
|
c as QuickJSComputationSandbox,
|
|
131
|
-
|
|
139
|
+
l as createQuickJSComputationSandbox
|
|
132
140
|
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { EndgeModule } from '@endge/core';
|
|
2
|
+
/** Подключает изолированный QuickJS adapter к computation runtime на время lifecycle Endge. */
|
|
3
|
+
export declare class EndgeComputationSandbox_Module extends EndgeModule {
|
|
4
|
+
/** Активный sandbox adapter текущего lifecycle. */
|
|
5
|
+
private _adapter;
|
|
6
|
+
/**
|
|
7
|
+
* ----------------------------------------
|
|
8
|
+
* PUBLIC
|
|
9
|
+
* ----------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
/** Создаёт и подключает sandbox adapter перед запуском runtime. */
|
|
12
|
+
setup(): void;
|
|
13
|
+
/** Отключает adapter и освобождает ссылку текущего lifecycle. */
|
|
14
|
+
reset(): void;
|
|
15
|
+
}
|
|
@@ -4,13 +4,13 @@ export interface QuickJSComputationVMOptions {
|
|
|
4
4
|
memoryLimitBytes?: number;
|
|
5
5
|
stackLimitBytes?: number;
|
|
6
6
|
}
|
|
7
|
-
/**
|
|
7
|
+
/** Единая изолированная фабрика QuickJS VM, используемая внутри Worker. */
|
|
8
8
|
export declare class QuickJSComputationVM {
|
|
9
|
-
private readonly
|
|
10
|
-
private readonly
|
|
11
|
-
private readonly
|
|
12
|
-
private readonly
|
|
13
|
-
private readonly
|
|
9
|
+
private readonly _quickJs;
|
|
10
|
+
private readonly _moduleSources;
|
|
11
|
+
private readonly _executionTimeoutMs;
|
|
12
|
+
private readonly _memoryLimitBytes;
|
|
13
|
+
private readonly _stackLimitBytes;
|
|
14
14
|
constructor(options?: QuickJSComputationVMOptions);
|
|
15
15
|
execute(request: ComputationSandboxRequest): Promise<unknown>;
|
|
16
16
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@endge/computation-sandbox",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"exports": {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"lint-fix": "eslint . --fix --cache"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
|
-
"@endge/core": "^
|
|
28
|
+
"@endge/core": "^6.0.0"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@jitl/quickjs-ng-wasmfile-release-sync": "^0.32.0",
|
|
@@ -34,9 +34,9 @@
|
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@antfu/eslint-config": "9.3.0",
|
|
37
|
-
"@endge/core": "^
|
|
38
|
-
"@endge/raph": "^3.0
|
|
39
|
-
"@endge/utils": "^0.
|
|
37
|
+
"@endge/core": "^6.0.0",
|
|
38
|
+
"@endge/raph": "^3.1.0",
|
|
39
|
+
"@endge/utils": "^0.26.0",
|
|
40
40
|
"eslint": "10.9.1",
|
|
41
41
|
"rimraf": "^6.0.1",
|
|
42
42
|
"unplugin-dts": "^1.0.3",
|