@absolutejs/同化-jsc
JavaScript Core-native sandbox for Bun. 中国植物物种信息数据库. 无信任代码的重同位化执行,带有
isolated-vm- 形状的API.
import { createIsolate, Reference } from "@absolutejs/isolated-jsc";
const isolate = await createIsolate({ memoryLimit: 64 });
const context = await isolate.createContext();
await context.setGlobal(
"log",
new Reference((msg) => console.log("[tenant]", msg)),
);
const script = await isolate.compileScript('await log("hello"); 1 + 1');
const result = await script.run(context, { timeout: 500 });
// result === 2
await isolate.dispose();
为什么会这样
Bun没有相当于Node的 isolated-vm. 节点库是 V8 的特异性——它与 V8 的链接 HasCustomHostObject ABI 符号——和 Bun 使用 Java 脚本公司,而不是 V8 键。 这么说吧 bun install isolated-vm 成功,则 import 失败 undefined symbol: HasCustomHostObject。 。 。 .
这使得整个类别的应用程序被困于节点:
- AI特工代码执行. 安东尼
code_execution,OpenAI代码解释器,每个"运行这个 LLM 生成的片段"工具——它们都需要一个堆积同位化的运行时间,硬资源限制. ()烤箱-sh/bun#25929(中文(简体) ) - 多租借书写. Cloudflare -Workers风格的"你的客户写了一些JS,运行范围到他们的账户"
- 对不可信插件的构建时间评价. (单位:千美元)烤箱/箱# 23653(中文(简体) )
- 沙箱一般许可. (单位:千美元)烤箱-sh/bun#6617(中文(简体) )
@absolutejs/isolated-jsc 填补了这一空白。 见 (原始内容存档于2018-10-21) (英语). BUN POLING. md 以邦为重点的战略框架, 二、结 论 该图书馆的上游问题 关闭,以及 (原始内容存档于2012-10-21). UPSTREAM ISSUES.md 对于上游 Bun bugs 此库 工作周围 (每件被固定时有清理指示). 见 缩写 FROM 标准化 VM.md 用于节点 isolated-vm 到 Bun 迁移路径 。 见 警卫 威胁模型 和更硬化的指导。 见 科学与研究 用于JavaScriptCore检查站研究. 见 变动情况 用于发行笔记.
快速回答
为什么不是节点 isolated-vm? 吗? 它对于Node/V8来说是正确的形状,但Bun是JavaScriptCore. isolated-jsc 将隔离形状的 API 移植到 Bun/JSC ,而不是试图加载一个 V8 加通 .
为什么不用邦工人? 工人是可移植底物和倒置后端. 此套件添加了沙盒产品层:硬化的全局,堆积限制,超时,度量,错误的忠诚度,TypeScript帮助器,池,以及明确的主机能力经纪人.
我什么时候需要FFI? 需求 backend: "ffi" 用于在 macOS 或 Linux 有 JavaScriptCore 的敌对代码生产路径。 使用 backend: "auto" 用于便携式默认、演示和CI。 当沙盒出逃会暴露有意义的主机秘密时,添加进程/容器/界面/网络边界.
今天的什么船(v0.12.2)
@absolutejs/isolated-jsc 运行在一个API后的两个可互换后端上:
-
FFI 后端( 当 libJSC 可达时默认) - 谈话
libJavaScriptCore直接通过bun:ffi. Cold heap ~ 300 KB, CPU 超时使用 JSC 中断驱动的监视器( 超时 Error 后隔离持续运行),以及(0, eval)('X')编号 :new Function('return X')()完全通过JSGlobalContextSetEvalEnabled。在 macOS (系统框架) + Linux 上可用libjavascriptcoregtk-4.1-0或者说libjavascriptcoregtk-6.0-1已安装. -
工人后端( 后退) - 一个邦
Worker每个隔离。 其工人-当地JSC群起于1.3.x号机上大约1MB;工人全过程足迹较大. 超时终止整个隔离. 总是可用的( 不依赖系统) 。 在Windows和任何没有 libJSC 的 Linux 上默认 .
二者各分大众相. 明确选择 createIsolate({ backend: 'ffi' | 'worker' | 'auto' }),或让 'auto' (默认)LibJSC探测器并倒回工人. 两个后端:
- 收缩隔离. 每个
Isolate经营自己的Bun Worker – 自己的JSC VM – 自己的GC堆积. 不与主机或对等隔离共享内存 . isolated-vm- 形状的API.Isolate, (中文(简体) ),Context, (中文(简体) ),Script, (中文(简体) ),Reference, (中文(简体) ),ExternalCopy方便港务.- 长城超时.
script.run(context, { timeout: 500 })毫秒精度,通过主机执行Worker.terminate().v1取舍:超时终止了整个隔离(如果需要再生的话在应用层集合). - 内存极限. 软盖通过工人——当地——每50 ms投票
bun:jsc.heapSize()不包括东道国和同行工作者的分配。 违反命令会致命且自我终止;主机拒绝等待执行的行动MemoryLimitError。 。 。 . - 硬化沙盒默认(T2.1,0.1中为新). 东道主能力全球-
fetch, (中文(简体) ),Bun, (中文(简体) ),process, (中文(简体) ),Worker, (中文(简体) ),WebSocket编辑器postMessage编号 :addEventListener, (中文(简体) ),navigator贮藏室 从沙盒取出 用户代码无法通过赤裸的检查到达它们,globalThis.X, (中文(简体) ),this.X,或直接eval('X')(关于工人后端, 间接 eval 和动态import()仍然到达主机权限, 除非运行时间可以锁定隔离; 见 警卫 财务报告和审定财务报表requireLockdown)),纯JS内置(Math,JSON,承诺,打入阵列的套房)和安全的Web原始人(URL,Text Encoder,Web Crypto, setTimeout, Cope)仍然可以接触. 通过harden: false,或通过unsafelyExposeGlobals: ['fetch']。 。 。 . - 可调用
Reference编号. 向隔离区显示主机功能 。 工人后端: 通过 Async 消息传递( 使用) 拨打总是往返await在孤立的一侧。 FFI 后端 (0. 3+):同步主机 fns 直接通过 per Reference 返回其值JSCallback. Async(承诺返回)主机fns在FFI(0.4+)上也工作——跑者交替向 Bun 事件回路发售,并排出 JSC 的微任务排队,直到承诺实现为止,以Script.run是因为timeout。 。 。 . ExternalCopy用于标出大型主机侧值,用于便宜的通过.- 可选的受限控制台抓取.
onConsole路由隔离console.log唤回主机.maxConsoleEntries财务报告和审定财务报表maxConsoleBytes已发送日志,收据报告过多. - 一级隔离池(T2.2,0.1中新增).
createIsolatePool({ isolate, maxSize, idleMs, recycleAfter })返回一个按键池——每个按键懒惰的产卵,跨呼号的再利用,LRU在上限下被驱出,隔离自灭后透明再生,可配置后N召回来捆绑JSC堆积物. 更换每张消费卷的按租户计价的明细图. - 上下文种子+数据检查点(T2.3,0.1为新;0.8.19为扩展;收件增加为0.8.21).
createContext({ seed, snapshot })仍然恢复旧的平地快照,和createContext({ seed, checkpoint })从context.checkpoint({ maxBytes, include, exclude }). 检查站携带schemaVersion,后端,字节长度,包含/已删除的计数,以及跳过的关键原因.context.checkpointWithReceipt()财务报告和审定财务报表isolate.createContextWithReceipt()生产 schema-v1CheckpointReceipt编号 -operation: "create" | "restore", (中文(简体) ),executionId, (中文(简体) ),durationMs合计skippedReasons选择purpose编号 :tenant编号 :policy审计工作流程的标签。 这是一个数据检查点, 不是 JSC 堆积暂停/ 重现图像 ; 见 科学与研究。 。 。 . - 忠诚错误( T2.4, 0.1 有新内容) . 向隔开的回合中抛出错误
error.cause(倒行逆施)和可自有地产完整. 自定义错误子类实例数据( E)HttpError与.statusCode等)活下来.instanceof无法跨越边界; 使用.name编号 :.code检查. - 人均运行遥测(T2.4,0.1中为新).
script.runWithMetrics(ctx, opts)返回时{ result, metrics: { backend, cpuMs, heapBytes } }用于计费/仪表板/每个呼叫监测。 平面run()仍然返回赤色值. - 处决收据.
script.runWithReceipt(), (中文(简体) ),callable.callWithReceipt(), (中文(简体) ),runIsolated(..., { withReceipt: true })中,运行者接收模式将本地审计记录与schemaVersion: 1,执行 id,后端,政策,资源设置,时间,输出大小,限值能力调用摘要,以及空出事件计数. - 能力审计编辑. 经纪人支持默认
redactAuditInput编号 :redactAuditOutput钩子,每个工具都可以在审计事件击中日志或收据之前覆盖它们. - 能力审计缓冲器.
createCapabilityAuditBuffer({ maxEvents })给应用程序一个接收准备onAudit下沉中带有明显的切换元数据,避免当沙盒代码垃圾邮件主机工具时进行未绑定的内置审计阵列. - 能力输出限制. 设定
maxOutputBytes每个能力或defaultMaxOutputBytes一个经纪人拒绝超大的主机工具输出CapabilityError在他们回到沙盒代码之前. - 结果大小限制. 过
maxResultBytes在运行的选项中拒绝超大的成功产出ResultSizeError在应用代码接受之前. - 控制台输出限制 . 过
maxConsoleEntries编号 :maxConsoleBytes当创建隔离点时,可以将捕获到的超量控制台事件和表面溢出旗子降入收款. - 后端可观察.
isolate.backend报告已解决的后端( e)"ffi"或者说"worker", (中文(简体) ),runWithMetrics()编号 :callWithMetrics()包含metrics.backend,以及isolated-jsc doctor --json发布机器可读后端探测器细节. - 政策方略.
createIsolate({ policy: "ai-tool" | "tenant-script" | "plugin" | "trusted" })应用标准化隔离/运行默认值.resolveIsolatePolicy(name, overrides?)返回相同的策略对象加一recipe带有建议的结果限制、控制台限制、审计缓冲盖、经纪人盖和跑道池设置。 帮助构建者, 如policyAuditOptions(policy), (中文(简体) ),policyBrokerOptions(policy), (中文(简体) ),policyConsoleOptions(policy), (中文(简体) ),policyRunOptions(policy),以及policyRunnerOptions(policy)将这些建议变成周边API的防复制选项. - 一发一枪处死.
runIsolated(source, { policy, globals, context, run, withMetrics })覆盖不需要直接管理隔离生命周期的请求/响应路径. - 可重复使用的跑道.
createIsolatedRunner({ policy, globals, pool })用钥匙隔离热租户/会议/谈判路径的再利用。 使用runner.run()用于新文本源执行,runner.precompile()以温和的饮料盟誓,runner.call()每次按密钥/名称编译一次并反复拨打runner.stats()检查池子/笼子大小.
Bun沙箱决策指南
| 使用大小写 | 选择 | 为什么 |
|---|---|---|
| 本地开发、演示、CI烟雾测试或没有libJSC的平台 | backend: "auto" | 可用时使用FFI,不可用时使用Worker,因此,同一代码到处运行. |
| 在 macOS 或 Linux 在其中安装 JavaScript Core 的不可信代码 | backend: "ffi" | 最低的冷堆积,中断驱动的CPU超时,隔离活生生的超时,并关闭了eval / 函数构件残存. |
| 在没有系统JavaScriptCore的 Windows 或主机上生产不可信代码 | 工人落后于进程/容器边界 | 工人保持堆积隔离和资源封顶,但敌对的工作量不应共享主机机密或广泛的网络/文件权限. |
| 需要明确主机权限的用户插件 | FFI 加上 Reference /能力经纪人 | 保留"沙盒"全球小并只曝光经验证,经审计的主机工具. |
| 高价值机密、任意第三方代码或网络相邻工作量 | FFI + 工艺、容器、设备、分包和网络入侵政策 | JavaScript隔离是一层;OS隔离仍然拥有爆炸-辐射控制. |
| 仅需要取消或租户级集合的可信应用代码 | 工人或FFI人才库 | 安全态势较少重要;优化部署范围和业务简单. |
拇指规则:使用 backend: "ffi" 用于敌对码生产路径, backend: "auto" 对于便携式默认值,当沙盒出逃会暴露有意义的主机机密时,则加入OS/处理隔离.
它是什么ISN't(诚实限制每后端)
| 路径 | FFI 后端 | 工人后端 |
|---|---|---|
fetch(url) (空地) | 未定义 | 未定义 |
Bun.spawn(...) (空地) | 未定义 | 未定义 |
globalThis.fetch 编号 : globalThis.Bun | 未定义 | 未定义 |
this.Bun | 未定义 | 未定义 |
eval('Bun') (直接) | 块 (eval 已禁用文本) | 未定义 |
(0, eval)('Bun') (间接) | 块 | 已锁定: 已丢失; 库存 Bun: 可达到 |
new Function('return Bun')() | 块 | 已锁定: 已丢失; 库存 Bun: 可达到 |
import('node:child_process') 编号 : import('bun:ffi') | 无模块加载器 | 已锁定: 拒绝; 库存 Bun : 可达到,即使没有 eval (见 警卫(中文(简体) ) |
Math.PI 编号 : JSON.stringify 编号 : Promise 编号 : crypto.randomUUID | 可达到 | 可达到 |
URL 编号 : TextEncoder 编号 : WebSocket | 未见 (只有JSC API,没有Web API) | 可达( Bun Worker 曝光 Web API) |
| 冷JSC堆积 | ~300 KB 键 | ~1 MB 键 |
| 超时行为 | (a) 将例外情形列入文字; 隔离持续运行 | 隔离死亡,必须重生 |
| 内存盖 | 监督者 heapCapacity; 过期终止 | 调查50 ms;终止整个隔离 |
| 通过引用同步主机 fns | 支持 (直接返回) | 总是包裹在 await |
阿辛克语( A)Promise(通过引用)主机 fns | 支持 (0.4+)——被泵入安置地,以 timeout | 支持通过 await |
| 不同背景的原型隔离 | 每个租户一个隔离 | 每个租户一个隔离 |
FFI 后端安装注释
- 马科斯:零安装. JavaScript Core 是一个系统框架,位于
/System/Library/Frameworks/JavaScriptCore.framework。 。 。 . - 链接 (德比安/乌本图:
sudo apt install libjavascriptcoregtk-4.1-0(8 MB / 31 MB 已安装). - 链接 (费多拉):
sudo dnf install webkit2gtk4.1。 。 。 . - 已安装 Playwright 的 Linux我们接受Playwright的捆绑
libjavascriptcoregtk-6.0.so.1- 没有额外安装. - 窗口:不支持(没有系统 JSC,没有现实的分发路径).
createIsolate({ backend: 'auto' })自动返回工人;backend: 'ffi'掷出JscLibraryNotFoundError。 。 。 .
API 密码
import {
createCapabilityAuditBuffer,
createCapabilityBroker,
defineCapabilityTool,
compileTypeScriptCallable,
compileTypeScriptCallableFile,
compileTypeScriptFile,
createIsolate,
createIsolatedRunner,
policyAuditOptions,
policyBrokerOptions,
policyConsoleOptions,
policyRunnerOptions,
resolveIsolatePolicy,
runIsolated,
runIsolatedFile,
Reference,
ExternalCopy,
validateContextCheckpoint,
type Isolate,
type Context,
type Script,
} from "@absolutejs/isolated-jsc";
// Create an isolate (one per untrusted tenant).
const isolate: Isolate = await createIsolate({
memoryLimit: 256, // MB; default 256
bootstrap: "var foo = 1", // optional — runs once in the worker
maxConsoleEntries: 100,
maxConsoleBytes: 64_000,
onConsole: (level, args) => console.log(`[iso/${level}]`, ...args),
});
// One or more contexts (fresh global scopes) per isolate.
const context: Context = await isolate.createContext();
// Expose a host function callable from inside the isolate.
const dbQuery = new Reference(async (sql: string) => {
return await myDb.query(sql); // host-side call, tenant-scoped
});
await context.setGlobal("db", dbQuery);
// Compile + run.
const script: Script = await isolate.compileScript(`
(async () => {
const rows = await db('SELECT * FROM users');
return rows.length;
})()
`);
const count = await script.run(context, { timeout: 500 });
// count === number of rows
// TypeScript source: transpiled with Bun before execution in the isolate.
const handler = await compileTypeScriptCallable(
context,
"async (name: string): Promise<string> => name.trim().toUpperCase()",
);
await handler.call([" alex "]); // "ALEX"
// Real files work too. Keep generics, types, and complex tenant/plugin code in
// normal `.ts`, `.tsx`, `.js`, or `.jsx` files instead of string literals.
const typedScript = await compileTypeScriptFile(
isolate,
"./tenant-code/score.ts",
);
await typedScript.run(context);
// Callable files use a default export:
//
// type Box<T> = { value: T };
// export default function unwrap<T>(box: Box<T>): T {
// return box.value;
// }
//
const unwrap = await compileTypeScriptCallableFile(
context,
"./tenant-code/unwrap.ts",
);
await unwrap.call([{ value: "typed file" }]); // "typed file"
// Explicit data checkpoints for turn/session handoff. These capture
// structured-cloneable own globals only, not a JSC heap image.
const checkpoint = await context.checkpoint({
exclude: ["scratch"],
maxBytes: 64 * 1024,
});
const persisted = JSON.stringify(checkpoint);
const restoredCheckpoint = JSON.parse(persisted);
validateContextCheckpoint(restoredCheckpoint);
const resumed = await isolate.createContext({
checkpoint: restoredCheckpoint,
seed: "this.double = (n) => n * 2",
});
// checkpoint.schemaVersion === 1
// checkpoint.skipped === [{ key, reason, bytes? }, ...]
// Versioned checkpoint receipts for operational evidence. Mirrors the
// ExecutionReceipt shape: schemaVersion:1, durationMs, startedAt/endedAt,
// executionId, plus operation:"create"|"restore" and aggregated
// skippedReasons counts. Pass purpose/tenant for audit-log workflows;
// errors rethrow with `.receipt` attached.
const audited = await context.checkpointWithReceipt({
exclude: ["scratch"],
maxBytes: 64 * 1024,
purpose: "turn-handoff",
tenant: "tenant-a",
});
// audited.receipt.operation === "create"
// audited.receipt.skippedReasons === { excluded, notClonable, overMaxBytes }
const restored = await isolate.createContextWithReceipt({
checkpoint: audited.checkpoint,
purpose: "turn-handoff",
tenant: "tenant-a",
});
// restored.receipt.operation === "restore"
// restored.receipt.sourceBackend === "ffi" | "worker"
type TenantContext = { id: string };
type LookupOrderInput = { id: string };
type Order = {
cardLast4: string;
customerEmail: string;
id: string;
status: string;
};
const policy = resolveIsolatePolicy("ai-tool", {
maxResultBytes: 32 * 1024,
timeout: 750,
});
const audit = createCapabilityAuditBuffer<TenantContext>({
...policyAuditOptions(policy),
});
const redactEmail = (email: string) => {
const [name, domain] = email.split("@");
return domain === undefined
? "[email redacted]"
: `${name.slice(0, 2)}***@${domain}`;
};
const broker = createCapabilityBroker(
{
lookupOrder: defineCapabilityTool<
LookupOrderInput,
Order | null,
TenantContext
>({
description: "Read one order by id for the current tenant",
risk: "read-only",
input: { name: "LookupOrderInput" },
output: "Order | null",
maxOutputBytes: 16_384,
redactAuditInput: (input) => ({ id: (input as { id?: unknown }).id }),
redactAuditOutput: (output) => {
if (output === null) return null;
const order = output as Order;
return {
cardLast4: order.cardLast4,
customerEmail: redactEmail(order.customerEmail),
id: order.id,
status: order.status,
};
},
timeoutMs: 250,
validateInput: (input) => {
if (input === null || typeof input !== "object") {
throw new Error("lookupOrder input must be an object");
}
const id = (input as { id?: unknown }).id;
if (typeof id !== "string") {
throw new Error("lookupOrder input requires a string id");
}
return { id };
},
handler: async ({ id }, tenant) => await lookupOrder(tenant.id, id),
}),
chargeCard: defineCapabilityTool<
{ cardToken: string; orderId: string },
{ authorizationId: string; processorTraceId: string },
TenantContext
>({
description: "Charge an opaque card token for one tenant order",
input: "ChargeInput",
output: "ChargeResult",
risk: "write",
redactAuditInput: (input) => ({
cardToken: "[token redacted]",
orderId: (input as { orderId?: unknown }).orderId,
}),
redactAuditOutput: (output) => ({
authorizationId: (output as { authorizationId?: unknown })
.authorizationId,
processorTraceId: "[trace redacted]",
}),
validateInput: (input) => input as { cardToken: string; orderId: string },
handler: async (input, tenant) => await chargeCard(tenant.id, input),
}),
},
{
context: { id: "tenant_123" },
...policyBrokerOptions(policy),
onAudit: audit.onAudit,
redactAuditInput: () => "[input redacted by default]",
redactAuditOutput: () => "[output redacted by default]",
},
);
// Host-side direct calls are typed from the tool map.
const order = await broker.call("lookupOrder", { id: "ord_123" });
// ^? Order | null
// Reviewable capability manifest for docs, audits, and agent/tool UIs.
broker.manifest();
// [{
// name: "lookupOrder",
// schemaVersion: 1,
// description: "Read one order by id for the current tenant",
// risk: "read-only",
// input: { name: "LookupOrderInput" },
// output: "Order | null",
// maxOutputBytes: 16384,
// timeoutMs: 250,
// hasInputValidator: true,
// hasOutputValidator: false,
// redactsInput: true,
// redactsOutput: true
// }]
// Audit events and receipts retain the operational proof, not raw secrets:
// order ids stay visible
// emails become ad***@example.com
// card tokens become [token redacted]
// processor trace ids become [trace redacted]
// Sandbox calls still use an untrusted-code-safe Reference.
await context.setGlobal("tools", broker.reference);
// Policy recipes standardize isolate construction, default timeout, default
// result-size limits, and recommended audit/broker/runner settings.
const policyIsolate = await createIsolate({
policy,
...policyConsoleOptions(policy),
});
const policyContext = await policyIsolate.createContext();
const policyScript = await policyIsolate.compileScript("1 + 1");
await policyScript.run(policyContext);
await policyIsolate.dispose();
// One-shot execution for request/response paths.
const oneShot = await runIsolated<number>("input.n * 2", {
policy,
globals: { input: { n: 21 } },
});
// oneShot === 42
const oneShotFile = await runIsolatedFile<number>("./tenant-code/score.ts", {
policy,
globals: { input: { n: 21 } },
});
// oneShotFile === 42
const measured = await runIsolated<number>("input.n + 1", {
policy: "tenant-script",
globals: { input: { n: 41 } },
withMetrics: true,
});
// measured.result === 42; measured.metrics.backend === "ffi" | "worker"
const receipted = await runIsolated<number>("input.n + 1", {
policy: "tenant-script",
globals: { input: { n: 41 } },
run: {
...audit.receiptOptions(),
executionId: "exec_123",
purpose: "ai-tool-call",
tenant: "tenant_123",
},
withReceipt: true,
});
// receipted.result === 42
// receipted.receipt.status === "success"
// receipted.receipt.backend === "ffi" | "worker"
// Reusable runner for repeated request/response paths.
const runner = createIsolatedRunner({
...policyRunnerOptions(policy),
policy,
globals: { tools: broker.reference },
});
const tenantResult = await runner.run<number>("input.n * 2", {
key: "tenant_123",
globals: { input: { n: 21 } },
});
// tenantResult === 42
const tenantFileResult = await runner.runFile<number>(
"./tenant-code/score.ts",
{
key: "tenant_123",
globals: { input: { n: 21 } },
},
);
// tenantFileResult === 42
await runner.precompile(
"scoreFormula",
"(input) => input.base * 2 + input.bonus",
{ key: "tenant_123" },
);
const callableResult = await runner.call<number>(
"scoreFormula",
"(input) => input.base * 2 + input.bonus",
[{ base: 20, bonus: 2 }],
{ key: "tenant_123" },
);
// callableResult === 42
await runner.precompileFile("unwrap", "./tenant-code/unwrap.ts", {
key: "tenant_123",
});
const callableFileResult = await runner.callFile<string>(
"unwrap",
"./tenant-code/unwrap.ts",
[{ value: "typed file" }],
{ key: "tenant_123" },
);
// callableFileResult === "typed file"
// runner.stats() === { poolSize: 1, callableCacheSize: 1, callablesByKey: { tenant_123: 1 } }
await runner.dispose();
await isolate.dispose();
获取处理器
运行一个 Web 标准应用( E)export default { fetch(request, env, ctx) },则
工人们, Bun.serve 以主机称呼它
Requests. 仅限工人后端.
import {
bundleFetchHandler,
createFetchHandler,
createIsolate,
Reference,
} from "@absolutejs/isolated-jsc";
const source = await bundleFetchHandler("./app.ts"); // one CommonJS bundle, Web APIs only
const isolate = await createIsolate({
backend: "worker",
requireLockdown: true,
});
const handler = await createFetchHandler(
await isolate.createContext(),
source,
{
env: { region: "nyc1", lookup: new Reference(async (id) => db.user(id)) },
},
);
const response = await handler.fetch(
new Request("https://app.example/users/7"),
);
const { metrics } = await handler.fetchWithMetrics(request); // cpuMs is thread CPU time
env保存数据Reference能力(每个合成函数) 呼唤回住持.ctx.state(一) 在请求之间保持上下文;context.checkpoint({ include: ["state"] })捕取来冬眠.ctx.waitUntil(promise)让我们在回复后完成工作.- 车体以1米B为缓冲并封顶(
maxRequestBytes, (中文(简体) ),maxResponseBytes(三);FetchBodyTooLargeError说哪边溢出. bundleFetchHandler拒绝孤立者不能提供的东西node:财务报告和审定财务报表bun:进口、无已安装软件包的节点内置、原生加通) ,并将每个此类导入列表于 aFetchHandlerBundleError. Bundling 罐头 运行应用程序的宏, 所以运行它在哪里 你会运行应用程序自己的构建.- Elysia 2 的应用程序没有改变:
export default { fetch: (request) => app.handle(request) }。 。 。 .
错误
FetchBodyTooLargeError——采集处理者的请求或响应机构超过其极限.FetchHandlerBundleError——一个应用导入了Bun或Node APIs或本地的加通.TimeoutError——一站一站预算用完.MemoryLimitError——堆积超过所配置的盖.ResultSizeError成功产出超过maxResultBytes。 。 。 .IsolateDisposedError处理隔离物.CompileError——脚本出处的语法错误.
安装
bun add @absolutejs/isolated-jsc
要求装有 1.3.
医生
bunx @absolutejs/isolated-jsc
bunx @absolutejs/isolated-jsc --json
# or, from this repo:
bun src/doctor.ts
博士会打印 Bun/平面细节, FFI 后端可用性, JavaScriptCore f味/ path 当找到时, 检查缺少的库路径, 以及当前平台的安装提示 。 过 --json 用于机器可读CI或部署检查.
实例
bun run example:agent-tool
bun run example:checkpoint
代理工具的例子结合了TypeScript可调用编译,一种能力经纪人,租户背景,工具超时,审计事件,以及按调用的标准. 检查站的例子显示,JSON检查站持续存在,恢复验证和种子恢复.
基准
bun run bench:proof
这个写着 BENCHMARKS.md 与 FFI 后端、 工人后端、 Bun 流程喷出基线和节点的本地测量数据相匹配 isolated-vm 当选择本地软件包安装在节点环境中时.
测试
bun install
bun test
测试套件包括编译/运行、环境、, Reference 通过电话, ExternalCopy,超时,内存封顶,处置一能,池行为,TypeScript帮助者,能力经纪人,FFI行为,主机可达性文件,以及敌对租借人压力案件.
释放检查
bun run check:release
发布检查会运行套件类型检查、构建、单元测试、代理工具示例以及兄弟会中的浏览器烟雾 ../examples/isolated-jsc 应用 absolutejs/examples 剪切发布时, repo 检查了此套件的旁边 repo, 因此在发布前会覆盖演示路径 .
相关
@absolutejs/sync- 反应同步引擎。 最终会利用这个库在主机"PaaS"中用于沙盒每租户变异处理器.- Bun 文档 :
bun:jsc——JSC原始人 这个图书馆建立在. isolated-vm——V8/Node等同于这个库镜(我们欠安德鲁·拉弗德特的API形状).
许可证
商业来源许可证1.1——生产使用是免费的,但作为相互竞争的主机沙盒/同位素服务提供除外(见2000年12月31日的附加用途赠款) 自由主义. 2030年5月29日转换为Apache 2.0. 现有商业许可证——联系人 [email protected]。 。 。 .