@ arrow-js/ sandbox (英语)

ArrowJS sandbox执行用户授权的Arrow JavaScript或TypeScript在一个Aync快JS/WASM VM内部执行,同时通过可信赖的主机DOM代码渲染.
这个软件包做什么
@arrow-js/sandbox 允许您运行未信任的箭头代码而不执行页面中的代码 window 领域.
它规定:
- 用户授权模块的ASync QuickJS/WASM运行时间
- 基于默认箭头导入和模板提取的 AST 预处理
- 特定沙盒
@arrow-js/core嘘 - 一个主机 DOM 渲染器和授权的事件桥
安装
pnpm add @arrow-js/sandbox
基本用途
import { sandbox } from '@arrow-js/sandbox'
const view = sandbox({
source: {
'main.ts': `
const state = reactive({ count: 0 })
export default html\`<button @click="\${() => state.count++}">
Clicked \${() => state.count}
</button>\`
`,
},
})
view(document.getElementById('app')!)
箭头标识符,例如 html, (中文(简体) ), reactive, (中文(简体) ), component, (中文(简体) ), pick, (中文(简体) ), props, (中文(简体) ), nextTick,以及 onCleanup 当它们被用作免费识别符时,可以自动注入. 明确用户进口得到保存,包括从 @arrow-js/core。 。 。 .
多文件模块
const view = sandbox({
source: {
'main.ts': `
import App from './App.ts'
export default App
`,
'state.ts': `
import { reactive } from '@arrow-js/core'
export const state = reactive({ count: 0 })
`,
'App.ts': `
import { html } from '@arrow-js/core'
import { state } from './state.ts'
export default html\`
<button @click="\${() => state.count++}">
Clicked \${() => state.count}
</button>
\`
`,
},
})
view(mountPoint)
支持的虚拟导入 :
- 提供的虚拟文件之间的相对导入
.ts, (中文(简体) ),.js, (中文(简体) ),.mjs,以及index.*后退分辨率@arrow-js/core{\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}我对沙盒心存决心
不支持的导入失败快 。 没有网络获取回落.
API 密码
export interface SandboxProps {
source: Record<string, string>
shadowDOM?: boolean
onError?: (error: Error | string) => void
debug?: boolean
}
export interface SandboxEvents {
output?: (payload: unknown) => void
}
export type HostBridgeFn = (...args: unknown[]) => unknown | Promise<unknown>
export type HostBridgeModule = Record<string, HostBridgeFn>
export type HostBridge = Record<string, HostBridgeModule>
export function sandbox<T extends {
source: object
shadowDOM?: boolean
onError?: (error: Error | string) => void
debug?: boolean
}>(
props: T,
events?: SandboxEvents,
hostBridge?: HostBridge
): ArrowTemplate
sandbox() 返回箭头模板。 您可以直接挂载, 或在更大的箭头模板内作曲 :
html`<section>${sandbox({ source })}</section>`
给定的主机元素总是 <arrow-sandbox>。 。 。 .
来源要求:
- 完全一个条目文件 :
main.ts或者说main.js - 选项
main.css,注入沙盒主机根 - 所有其他条目均为JS/TS/MJS虚拟模块
shadowDOM 默认为 true。启用时,沙盒会挂入打开的阴影根 <arrow-sandbox>。在禁用时,它会挂入元件的光DOM.
主机桥模块
任选第三项 hostBridge 参数显示主机拥有的功能为可导入的沙盒模块 :
const view = sandbox(
{
source: {
'main.ts': `
import { getGreeting } from 'host-bridge:greetings'
const payload = await getGreeting('Arrow')
export default html\`<div>\${payload.message}</div>\`
`,
},
},
undefined,
{
'host-bridge:greetings': {
getGreeting(name) {
return { message: \`Hello \${String(name)}\` }
},
},
}
)
每个顶级 hostBridge 键作为模块指定符直接导入。 Bridge导出仅被命名为函数,而沙盒代码总是得到"承诺回放"的函数. 桥站参数和返回值必须是简单的序列数据.
沙盒输出桥
可选 events.output 回调通过全局接收从QuickJS内部发出的值 output(payload) 函数 :
const view = sandbox(
{
source: {
'main.ts': `
output({ status: 'ready' })
export default html\`<div>Sandbox Ready</div>\`
`,
},
},
{
output(payload) {
console.log(payload)
},
}
)
output(payload) 接受一个有效载荷值。 有效载荷在从VM进入主机前被序列化为纯数据.
安保模式
- 由用户授权的逻辑运行在QuickJS/WASM内部.
- 主机页面仅通过可信任的渲染器代码来变换出真实的 DOM.
- 关于真正的DOM前置消毒有效载荷的活动听众返回VM.
- 沙盒不能直接进入
window, (中文(简体) ),document,DOM节点,存储,或任意浏览器API. html模板被预处理成描述符. 主机从不评价用户表达式.- DOM主机中的收听器从不附加来自沙盒代码的原始用户回调.
- 合成沙盒事件保持了共同的进入模式,如
event.target.value财务报告和审定财务报表event.currentTarget.checked不暴露现场 主机DOM节点.
目前明确覆盖的全球包括: setTimeout, (中文(简体) ), clearTimeout, (中文(简体) ), setInterval, (中文(简体) ), clearInterval和限制 fetch() 代理服务器。 主机拥有实时计时器和网络,但已注册的回调和响应处理仍然在QuickJS内部执行.
事件有效载荷作为简单数据传送。 VM收到一个狭小的快照, 不是活的 DOM 事件对象 .
沙盒会暴露 event.target, (中文(简体) ), event.currentTarget,以及
event.srcElement 作为带有故意小表面的简单数据快照:
value, (中文(简体) ), checked, (中文(简体) ), id,以及 tagName。兼容性快捷键,例如
event.value 财务报告和审定财务报表 event.checked 仍然在场,但 event.target.value
是首选形状.
沙盒获取
那个沙盒 fetch() 桥面有意比浏览器窄 window.fetch数字 :
- 仅绝对
https:允许使用 URL,加http:本地主机地址 - 没有
Request对象, 没有相对的 URL, 没有继承的浏览器请求上下文 - 证书总是被迫
omit referrerPolicy总是被迫no-referrermode总是被迫cors- 请求头仅是用户提供的和敏感的环境头,例如
authorization, (中文(简体) ),cookie, (中文(简体) ),origin, (中文(简体) ),referer,以及user-agent被封锁 - 反应作为小型反应类物体与
ok, (中文(简体) ),status, (中文(简体) ),statusText, (中文(简体) ),url, (中文(简体) ),redirected, (中文(简体) ),headers, (中文(简体) ),text(), (中文(简体) ),json(),以及arrayBuffer() - 15秒后请求暂停,答复上限为 1 MB
这个桥的设计是为了避免环境页面证书和主机DOM访问. 它仍然通过浏览器网络堆栈进行路由,所以浏览器控制的元数据如 Origin 或者说 User-Agent hTTP 层可能仍然存在.
支持的子集
- 文本插值
- 属性插值
- 约束事件,例如
@click - 嵌入元素
- 同步
component()组成 - 组件通过
component((props, emit) => ...)和家长听众通过Child(props, { eventName }) - 自动同步
component()与VM所属倒置/投降/反应处理的构成 pick()编号 :props()缩小组件道具- 全球
output(payload)主机桥 - 直接主机桥模块通过第三个
sandbox()参数 - vM 内部的反应性更新
- 限制桥接
fetch()请求和JSON/文本回复处理 - 桥接计时器调用
setTimeout财务报告和审定财务报表setInterval - 阵列和有条件的儿童区域
- 没有包装元素的多根模板
不支持或部分支持
- 按键列表 diffing
- 直接 DOM 校对或真实 DOM 节点访问
- 任意的外部进口
- 浏览器 API 访问没有明确桥段
- 硬 CPU 和内存隔离
目前的限制
- 这还不是对抗CPU或内存耗尽的硬边界.
- 内存限制适用于快取JS运行时间,但拒绝服务硬化仍需做更多的工作.
- 类型脚本支持用途
typescript.transpileModule,不完全的语义类型检查. - 模板支持有意比标准箭头主机运行时间更窄.
发展
pnpm --filter @arrow-js/sandbox sync:vm
pnpm --filter @arrow-js/sandbox demo
pnpm exec vitest run packages/sandbox/src/index.spec.ts
pnpm exec playwright test -c playwright.sandbox.config.ts
演示内容包括从公共Open-Meteo预测API获取当前条件的气象小应用.