@absolutejs/sync 1.7.3 → 1.7.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.
- package/dist/engine/index.js +25 -65
- package/dist/engine/index.js.map +3 -3
- package/dist/engine/sandbox.d.ts +28 -25
- package/dist/index.js +25 -65
- package/dist/index.js.map +3 -3
- package/package.json +3 -3
package/dist/engine/sandbox.d.ts
CHANGED
|
@@ -8,30 +8,30 @@
|
|
|
8
8
|
*
|
|
9
9
|
* - Handler must be a string. It evaluates inside the isolate's JSC VM, with
|
|
10
10
|
* no access to the host's modules, closures, or globals — only the
|
|
11
|
-
* `args` / `ctx` clones and the `actions`
|
|
12
|
-
* - First call per mutation pays
|
|
13
|
-
*
|
|
14
|
-
*
|
|
11
|
+
* `args` / `ctx` clones and the `actions` Reference we pass in.
|
|
12
|
+
* - First call per mutation pays an isolate spawn + compile (~3–25 ms
|
|
13
|
+
* depending on backend). Every subsequent call is a single
|
|
14
|
+
* `JSObjectCallAsFunction` (FFI) or one postMessage (Worker) — no
|
|
15
|
+
* per-call eval, no per-call `setGlobal`.
|
|
15
16
|
* - Timeout terminates the isolate (the sandbox runner detects this and
|
|
16
17
|
* lazily re-spawns on the next call). On the FFI backend timeouts throw
|
|
17
18
|
* a TerminationException without killing the isolate; sync's runner
|
|
18
19
|
* treats both shapes the same.
|
|
19
|
-
* - Each per-call context retains some JSC metadata until the isolate's
|
|
20
|
-
* next GC sweep. Empirically ~2 MB residual per call (Worker backend).
|
|
21
|
-
* For long-lived mutations choose `memoryLimit` ≥ 128 (the default 32
|
|
22
|
-
* trips after a few dozen calls without pressure for GC).
|
|
23
20
|
*
|
|
24
|
-
* **Backend default: `'auto'`** —
|
|
25
|
-
* pump on the FFI backend (alternates Bun event-loop yields with JSC
|
|
26
|
-
* microtask drains, bounded by `Script.run`'s `timeout`), so the
|
|
27
|
-
* `actions.insert/update/delete/change` async References settle on FFI
|
|
28
|
-
* just like they do on Worker. `'auto'` picks FFI when libJSC is reachable
|
|
21
|
+
* **Backend default: `'auto'`** — `'auto'` picks FFI when libJSC is reachable
|
|
29
22
|
* (~300 KB cold heap, interrupt-driven CPU timeouts) and falls back to
|
|
30
23
|
* Worker (~46 MB cold heap, postMessage round-trips) otherwise. Pin to
|
|
31
24
|
* `'worker'` if you specifically need Web APIs (`URL`, `TextEncoder`,
|
|
32
25
|
* `WebSocket`) inside your handler — those live in the Bun-Worker
|
|
33
26
|
* environment, not the bare JSC C API.
|
|
34
27
|
*
|
|
28
|
+
* **Per-call hot path (since 1.7.4 / isolated-jsc 0.6).** Each mutation is
|
|
29
|
+
* compiled to a {@link Callable} once — a precompiled function expression
|
|
30
|
+
* the sandbox owns by reference. Per call we invoke
|
|
31
|
+
* `callable.call([args, ctx, dispatch])` where `dispatch` is a Reference
|
|
32
|
+
* that bridges `actions.*` back to the host. No globals, no eval per call,
|
|
33
|
+
* no shared-slot serialization machinery.
|
|
34
|
+
*
|
|
35
35
|
* The runner is built lazily per-mutation: nothing is spawned until the
|
|
36
36
|
* mutation actually runs for the first time. No engine teardown hook is
|
|
37
37
|
* needed — the OS reaps the workers when the engine's host process exits.
|
|
@@ -45,27 +45,30 @@ export type SandboxConfig = {
|
|
|
45
45
|
timeout?: number;
|
|
46
46
|
/**
|
|
47
47
|
* isolated-jsc backend. Defaults to `'auto'` (FFI when libJSC is
|
|
48
|
-
* reachable, Worker otherwise)
|
|
49
|
-
*
|
|
50
|
-
*
|
|
48
|
+
* reachable, Worker otherwise). Both backends now run the same
|
|
49
|
+
* `Context.compileCallable`-based hot path; the choice trades cold
|
|
50
|
+
* spawn (FFI wins ~6×) against Web API availability (Worker only).
|
|
51
51
|
*
|
|
52
52
|
* Pin to `'worker'` if your handler needs Web APIs (`URL`,
|
|
53
53
|
* `TextEncoder`, `WebSocket`) — those live in the Bun-Worker
|
|
54
54
|
* environment, not the bare JSC C API.
|
|
55
55
|
*
|
|
56
|
-
* Pin to `'ffi'`
|
|
57
|
-
*
|
|
56
|
+
* Pin to `'ffi'` to bypass the auto-probe when you know libJSC is
|
|
57
|
+
* reachable (e.g. CI with a known image).
|
|
58
58
|
*/
|
|
59
59
|
backend?: 'auto' | 'ffi' | 'worker';
|
|
60
60
|
};
|
|
61
61
|
/**
|
|
62
62
|
* Build a lazy runner for one mutation's sandboxed source. The first call
|
|
63
|
-
* compiles +
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
63
|
+
* compiles the isolate + context + callable; subsequent calls reuse all
|
|
64
|
+
* three and only pack the per-call args (`args`, `ctx`, and a fresh
|
|
65
|
+
* dispatch Reference closed over this call's `actions`). If the isolate
|
|
66
|
+
* has been disposed (timeout, memory cap), the next call re-spawns
|
|
67
|
+
* transparently.
|
|
68
|
+
*
|
|
69
|
+
* Concurrency-safe by construction: every call gets its own fresh
|
|
70
|
+
* dispatch Reference closed over its own `actions`. No shared slot, no
|
|
71
|
+
* promise queue needed. (Reference allocation cost is ~0.003 ms per
|
|
72
|
+
* call — negligible.)
|
|
70
73
|
*/
|
|
71
74
|
export declare const makeSandboxedHandler: (source: string, config?: SandboxConfig) => ((args: unknown, ctx: unknown, actions: MutationActions) => Promise<unknown>);
|
package/dist/index.js
CHANGED
|
@@ -725,7 +725,7 @@ var loadIsolatedJsc = async () => {
|
|
|
725
725
|
}
|
|
726
726
|
};
|
|
727
727
|
var wrap = (source) => `
|
|
728
|
-
(
|
|
728
|
+
function (args, ctx, __dispatch) {
|
|
729
729
|
const userFn = (${source});
|
|
730
730
|
if (typeof userFn !== 'function') {
|
|
731
731
|
throw new Error(
|
|
@@ -734,55 +734,26 @@ var wrap = (source) => `
|
|
|
734
734
|
);
|
|
735
735
|
}
|
|
736
736
|
const actions = {
|
|
737
|
-
insert: (table, data) =>
|
|
738
|
-
update: (table, data) =>
|
|
739
|
-
delete: (table, row) =>
|
|
740
|
-
change: (collection, change) =>
|
|
737
|
+
insert: (table, data) => __dispatch('insert', table, data),
|
|
738
|
+
update: (table, data) => __dispatch('update', table, data),
|
|
739
|
+
delete: (table, row) => __dispatch('delete', table, row),
|
|
740
|
+
change: (collection, change) => __dispatch('change', collection, change)
|
|
741
741
|
};
|
|
742
742
|
return userFn(args, ctx, actions);
|
|
743
|
-
}
|
|
743
|
+
}
|
|
744
744
|
`;
|
|
745
|
-
var DEFAULT_RECYCLE_CONTEXT_AFTER = 256;
|
|
746
|
-
var installRouter = async (context, currentActions, Reference) => {
|
|
747
|
-
const router = new Reference((op, ...rest) => {
|
|
748
|
-
const a = currentActions.value;
|
|
749
|
-
if (a === undefined) {
|
|
750
|
-
throw new Error("__syncAction invoked outside an active sandboxed call (shared-slot router)");
|
|
751
|
-
}
|
|
752
|
-
switch (op) {
|
|
753
|
-
case "insert":
|
|
754
|
-
return a.insert(rest[0], rest[1]);
|
|
755
|
-
case "update":
|
|
756
|
-
return a.update(rest[0], rest[1]);
|
|
757
|
-
case "delete":
|
|
758
|
-
return a.delete(rest[0], rest[1]);
|
|
759
|
-
case "change":
|
|
760
|
-
return a.change(rest[0], rest[1]);
|
|
761
|
-
default:
|
|
762
|
-
throw new Error(`unknown sandbox action op: ${String(op)}`);
|
|
763
|
-
}
|
|
764
|
-
});
|
|
765
|
-
await context.setGlobal("__syncAction", router);
|
|
766
|
-
};
|
|
767
745
|
var compile = async (source, config) => {
|
|
768
|
-
const { createIsolate
|
|
746
|
+
const { createIsolate } = await loadIsolatedJsc();
|
|
769
747
|
const isolate = await createIsolate({
|
|
770
748
|
backend: config.backend ?? "auto",
|
|
771
749
|
memoryLimit: config.memoryLimit ?? 32
|
|
772
750
|
});
|
|
773
|
-
const script = await isolate.compileScript(wrap(source));
|
|
774
751
|
const context = await isolate.createContext();
|
|
775
|
-
const
|
|
776
|
-
value: undefined
|
|
777
|
-
};
|
|
778
|
-
await installRouter(context, currentActions, Reference);
|
|
752
|
+
const callable = await context.compileCallable(wrap(source));
|
|
779
753
|
return {
|
|
754
|
+
callable,
|
|
780
755
|
context,
|
|
781
|
-
currentActions,
|
|
782
756
|
isolate,
|
|
783
|
-
runQueue: Promise.resolve(undefined),
|
|
784
|
-
script,
|
|
785
|
-
servedCalls: 0,
|
|
786
757
|
timeoutMs: config.timeout ?? 5000
|
|
787
758
|
};
|
|
788
759
|
};
|
|
@@ -798,37 +769,26 @@ var makeSandboxedHandler = (source, config = {}) => {
|
|
|
798
769
|
pending = compile(source, config);
|
|
799
770
|
return pending;
|
|
800
771
|
};
|
|
801
|
-
const recycleContextIfNeeded = async (compiled) => {
|
|
802
|
-
if (compiled.servedCalls < DEFAULT_RECYCLE_CONTEXT_AFTER)
|
|
803
|
-
return;
|
|
804
|
-
const { Reference } = await loadIsolatedJsc();
|
|
805
|
-
await compiled.context.dispose().catch(() => {});
|
|
806
|
-
compiled.context = await compiled.isolate.createContext();
|
|
807
|
-
await installRouter(compiled.context, compiled.currentActions, Reference);
|
|
808
|
-
compiled.servedCalls = 0;
|
|
809
|
-
};
|
|
810
772
|
return async (args, ctx, actions) => {
|
|
773
|
+
const { Reference } = await loadIsolatedJsc();
|
|
811
774
|
const compiled = await getCompiled();
|
|
812
|
-
const
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
compiled.currentActions.value = undefined;
|
|
825
|
-
compiled.servedCalls += 1;
|
|
775
|
+
const dispatch = new Reference((op, ...rest) => {
|
|
776
|
+
switch (op) {
|
|
777
|
+
case "insert":
|
|
778
|
+
return actions.insert(rest[0], rest[1]);
|
|
779
|
+
case "update":
|
|
780
|
+
return actions.update(rest[0], rest[1]);
|
|
781
|
+
case "delete":
|
|
782
|
+
return actions.delete(rest[0], rest[1]);
|
|
783
|
+
case "change":
|
|
784
|
+
return actions.change(rest[0], rest[1]);
|
|
785
|
+
default:
|
|
786
|
+
throw new Error(`unknown sandbox action op: ${String(op)}`);
|
|
826
787
|
}
|
|
827
788
|
});
|
|
828
|
-
compiled.
|
|
829
|
-
|
|
789
|
+
return compiled.callable.call([args, ctx, dispatch], {
|
|
790
|
+
timeout: compiled.timeoutMs
|
|
830
791
|
});
|
|
831
|
-
return turn;
|
|
832
792
|
};
|
|
833
793
|
};
|
|
834
794
|
|
|
@@ -2350,5 +2310,5 @@ export {
|
|
|
2350
2310
|
createPresenceHub
|
|
2351
2311
|
};
|
|
2352
2312
|
|
|
2353
|
-
//# debugId=
|
|
2313
|
+
//# debugId=E4BD5E29981CFB6664756E2164756E21
|
|
2354
2314
|
//# sourceMappingURL=index.js.map
|