豫言 / 豫言操作系统编译运行适配 @ 0.1.0

经云工句柄桥调用宿主提供的编译运行器(内存文件系统里运行豫言编译器 Wasm 与 Binaryen 组装),拉取式取回编译事件与产物。

源码浏览已生成;不能解析的文件以纯文本展示,不表示通过类型检查。

说明.汉语.md

# 编译运行云工适配

把公共[编译运行接口](../../../豫言操作系统接口/编译运行/规范.汉语.md)映射到 Cloudflare Worker:用豫言写在云工宿主的句柄桥之上(`编译。豫`),**不增加任何宿主原语,也不改 `宿主.mjs`**;真正运行豫言编译器的是一个新的宿主 JavaScript 模块 [`宿主/云工/编译运行.mjs`](../../宿主/云工/编译运行.mjs)(“在操作系统里的 JS”),由平台外壳放进 Worker 的 `env`。

## 结构

- **运行器(宿主 JS)**:`宿主/云工/编译运行.mjs` 导出 `创建编译运行器工厂({binaryen, 编译模块, 桥模块, 取标准库资料?})`,返回函数 `(资产绑定) → 运行器`。运行器复用浏览器编译器宿主(`宿主/浏览器/编译器/宿主.mjs` 的 `内存文件系统`、`执行模块` 与 `组装.mjs` 的 `创建组装器`,与本模块同处操作系统目录,相对位置不变)。它不解析 HTTP、不决定响应形状,只做:校验请求(与规范同一套规则,防应用出错)→ 排队 → 每次运行新建内存文件系统(预置 `标准库.json.gz` 的资料,进程内缓存“加载承诺”)→ 写 `/包上下文` 与 `/用户程序/*` → 用 `执行模块` 运行编译器 Wasm(Binaryen 组装回调)→ 把阶段与输出排成事件队列 → 成功时读 `/程序.wasm`、算 SHA-256。方法:`启动`、`读事件`、`取产物`、`取产物Base64`、`结束`(另有诊断用的 `运行数`)。
- **适配(豫言)**:`编译。豫` 经 `云工绑定句柄 COMPILE <绑定名>` 取得运行器对象句柄(**许可 `COMPILE` 列表授权,绑定名由应用传入**,与 D1、R2 等绑定同一套机制),再用 `云工调用方法安全` 调它的方法:宿主方法的失败(含 Promise 拒绝)转成可捕获的豫言异常,消息前缀“编译运行:”;产物字节以 `Uint8Array` 句柄返回,经 `云工句柄取字节` 读出后立即释放;每次调用后释放运行器句柄。适配自己校验编译器名(1 至 128 字节、无控制字符)、运行号、请求大小(≤ 2097152 字节)与等待毫秒(1 至 60000)。
- **运行号只在启动它的事件内有效**:适配返回的运行号是“事件标记:宿主运行号”,事件标记是每个 Wasm 实例(每个事件)生成一次的随机前缀(同 网页事件流 的流柄规则);别的事件里用它抛出“运行号不属于当前事件”。这也是宿主平台的硬约束:Worker 不允许一个请求启动的异步工作在别的请求里继续(本适配的一致性验证最初把接口五个函数各做成一个 HTTP 端点,编译因此永不启动、`读取编译运行事件` 一直返回状态 1——这就是该规则的来历)。
- **外壳接入**:应用许可 `{"COMPILE":["COMPILER_RUNTIME"]}`;外壳在调用应用之前把运行器放进 `env`:

```js
import 应用 from './<应用产物>/入口.mjs';
import binaryen from './组装器.mjs';                 // Binaryen 第三方胶水(它自己静态导入组装器.wasm)
import 编译模块 from './资源/编译器.wasm';
import 桥模块 from './资源/值桥接.wasm';
import {创建编译运行器工厂} from '<操作系统目录>/宿主/云工/编译运行.mjs';
const 造运行器 = 创建编译运行器工厂({binaryen, 编译模块, 桥模块});
export default {fetch: (请求, 环境, 上下文) => 应用.fetch(请求, {...环境, COMPILER_RUNTIME: 造运行器(环境.ASSETS)}, 上下文)};
```

  编译器 Wasm 与 Binaryen 的 Wasm 必须由外壳静态导入(Workers 不允许运行时从字节编译 Wasm),所以它们留在平台外壳一侧;`ASSETS` 绑定提供 `标准库.json.gz`(约 2.6 MiB,解压 JSON 约 57 MiB,不在豫言里解析)。云仓的用法见 `应用/云端编译服务/编译外壳.mjs`。

## 限额(运行器强制,规范一致)

请求 ≤ 2 MiB、文件 1 至 256 个、路径规则、内容合计 ≤ 262144 字节、产物 ≤ 8 MiB、事件文字合计 ≤ 16 MiB(超出的过程事件被丢弃,终止事件不丢)、编译器输出 ≤ 2 MiB 与编译期限 90 秒(由 `执行模块` 强制)、未终止的运行 ≤ 8 个、已终止而等待读取的运行 ≤ 32 个(丢弃最旧的)、运行存活 ≤ 5 分钟、等待毫秒 1 至 60000。编译阶段串行(同一时刻只有一份 57 MiB 的编译文件系统副本),FS 在编译结束后立即释放,只留产物字节。

## 已验证

一致性验证在 [`一致性验证/`](一致性验证/说明.汉语.md):真实豫言 Wasm(试验应用)+ 真实运行器 + 真实编译器与标准库,在 Node 进程内与本地 workerd(Miniflare)各跑同一组 12 个场景,另有 2 项 Node 进程内专属测试(未授权绑定、无残留运行)与 6 项只能在 Node 内做的运行器级测试,共 32 项通过。另在云仓 `应用/云端编译服务/` 的黑盒测试 `测试/编译.test.mjs`(7 项)对整个服务全部通过,并与旧 JS 实现做过逐请求差分。

## 与旧行为的差异

- 请求体不是有效 JSON、为空或超过 2 MiB 时,400 的 `error` 文字是宿主适配的中文消息(“入站 JSON 正文无效:…”“入站 JSON 正文超过 2 MiB”),不再是 JS 引擎的原消息;超过 2 MiB 的请求旧实现会掐断连接,现在返回干净的 400。
- 单个 Worker 进程里同时排队或编译的运行超过 8 个时,第 9 个请求得到 503(消息“编译运行过多”);旧实现无此限额,全部排队。
- 诊断事件里的错误栈含宿主模块路径,两版不同。
- 输入宽容度(应用层,由豫言 JSON 解析与宿主结果桥的限制而来):请求体的多余字段含指数记法的数字(如 `1e29`)或嵌套超过 32 层时返回 400(旧实现接受);以 UTF-8 BOM 开头的请求体改为接受(旧实现 400)。真实调用方(云端项目 DO)只发 `files`、`entry`、`includeArtifact`,不受影响。

## 未验证与待办

- Cloudflare 边缘的真实内存(128 MiB 限额)与 CPU 表现:本地 workerd 不强制;本机 RSS 对比未见泄漏,峰值与旧实现同量级。
- 真流式:编译器 Wasm 同步运行,会独占 isolate,事件其实要等编译结束才能送出(旧实现同样:响应头与所有行同时到达);接口已是拉取式,宿主日后让出事件循环即可实时;届时应用改用可选内容类型的流式回应(`网页事件流` 目前固定 `text/event-stream`,可增 0.2.0 函数 `开始入站文字流回应`)。
- 本地 `wrangler dev` 在 8 路并发压测重复数次后会崩溃退出(旧实现同样),不影响单请求正确性;生产未见此类。

说明.文言.md

# 编译运行云工适配

映公共[编译运行公约](../../../豫言操作系统接口/编译运行/规范.文言.md)于 Cloudflare Worker:以豫言书于云工宿主句柄桥之上(`编译。豫`),**不增宿主原语,亦不改 `宿主.mjs`**;真行豫言编器者,乃新增之宿主 JavaScript 模块[`宿主/云工/编译运行.mjs`](../../宿主/云工/编译运行.mjs)(“居于操作系统之 JS”),由平台外壳置于 Worker 之 `env`。

## 构

- **运行器(宿主 JS)**:`宿主/云工/编译运行.mjs` 出 `创建编译运行器工厂({binaryen, 编译模块, 桥模块, 取标准库资料?})`,返一函数 `(资产绑定) → 运行器`。运行器借浏览器编器宿主(`宿主/浏览器/编译器/宿主.mjs` 之 `内存文件系统`、`执行模块` 与 `组装.mjs` 之 `创建组装器`,与本模块同处操作系统目录,相对之位不易)。不解 HTTP,不定应答之形,惟司:验请求(与公约同则,防客之误)→ 排队 → 每运新造内存文件系,预置 `标准库.json.gz` 之资(进程内缓存“加载之诺”)→ 写 `/包上下文` 与 `/用户程序/*` → 以 `执行模块` 行编器 Wasm(Binaryen 组装之回调)→ 排阶段与出为事之队 → 成则读 `/程序.wasm`、算 SHA-256。术:`启动`、`读事件`、`取产物`、`取产物Base64`、`结束`(另有诊断之 `运行数`)。
- **适配(豫言)**:`编译。豫` 由 `云工绑定句柄 COMPILE <绑定名>` 得运行器之对象柄(**许可 `COMPILE` 列授之,绑定名由客传入**,与 D1、R2 等绑定同制),复以 `云工调用方法安全` 调其术:宿主之败(含 Promise 之拒)转为可捕之豫言异,辞冠“编译运行:”;产物字节以 `Uint8Array` 柄返,经 `云工句柄取字节` 读出即释;每调之后释运行器之柄。适配自验编译器名(一至一百二十八字节、无控制字)、运行号、请求之大(不逾二百零九万七千一百五十二字节)与等待毫秒(一至六万)。
- **运行号惟启之之事有效**:适配所返之运行号乃“事标:宿主运行号”,事标者,每 Wasm 实例(每事)一生之随机前缀(同网页事件流之流柄则);他事用之,抛“运行号不属于当前事件”。此亦宿主平台之硬约:Worker 不许一请求所启之异步工作续于他请求(本适配一致性验证初以公约五术各为一 HTTP 端点,编译因而永不启,`读取编译运行事件` 恒返状态一——此则之所由来也)。
- **外壳之接**:应用之许 `{"COMPILE":["COMPILER_RUNTIME"]}`;外壳于调应用之前置运行器于 `env`(代码见汉语版)。编器 Wasm 与 Binaryen 之 Wasm 须由外壳静态导入(Workers 不许运行时自字节编 Wasm),故留于平台外壳之侧;`ASSETS` 绑定供 `标准库.json.gz`(约二点六 MiB,解压 JSON 约五十七 MiB,不于豫言中解析)。云仓之用法见 `应用/云端编译服务/编译外壳.mjs`。

## 限(运行器强制,与公约同)

请求不逾二 MiB、文件一至二百五十六、路径之则、内容合不逾二十六万二千一百四十四字节、产物不逾八 MiB、事文合不逾十六 MiB(逾者过程之事弃,终止之事不弃)、编器之出不逾二 MiB 与编期九十秒(由 `执行模块` 强制)、未终之运不逾八、既终待读之运不逾三十二(弃最旧)、运存活不逾五分钟、等待毫秒一至六万。编阶段串行(同一时唯一份五十七 MiB 之编文件系副本),编毕即释文件系,惟留产物字节。

## 已验

一致性验证在[`一致性验证/`](一致性验证/说明.文言.md):真豫言 Wasm(试验应用)+ 真运行器 + 真编器与标准库,于 Node 进程内与本地 workerd(Miniflare)各行同一组十二景,另有二项惟 Node 进程内之测试(未授权之绑定、无残留之运)与六项惟 Node 内可行之运行器级测试,凡三十二项皆过。又于云仓 `应用/云端编译服务/` 之黑盒测试 `测试/编译.test.mjs`(七项)对整个服务皆过,并与旧 JS 之实现作逐请求之差分。

## 异于旧者

- 请求体非有效 JSON、为空或逾二 MiB 时,四百之 `error` 文乃宿主适配之中文辞(“入站 JSON 正文无效:…”“入站 JSON 正文超过 2 MiB”),不复为 JS 引擎之原辞;逾二 MiB 之请求,旧实现掐断其连接,今回洁净之四百。
- 单一 Worker 进程中同时候或编之运逾八,则第九请求得五百零三(辞“编译运行过多”);旧实现无此限,尽排队。
- 诊断事中之错误栈含宿主模块之径,两版有异。
- 输入宽容之度(应用层,缘豫言 JSON 解析与宿主结果桥之限):请求体之余字段含指数记数(如 `1e29`)或嵌套逾三十二层者答四百(旧受之);以 UTF-8 BOM 起首之请求体改受之(旧答四百)。真调用方(云端项目 DO)惟发 `files`、`entry`、`includeArtifact`,不受其扰。

## 未验与待办

- Cloudflare 边缘之真内存(一百二十八 MiB 之限)与 CPU 之表现:本地 workerd 不强制;本机 RSS 之较,未见泄漏,峰值与旧实现同量级。
- 真流式:编器 Wasm 同步而行,独占 isolate,事实待编毕方能送出(旧实现亦然:应答头与诸行同时至);公约已为拉取式,宿主日后让出事件循环即可实时;届时应用改用可选内容种类之流式应答(`网页事件流` 今固定为 `text/event-stream`,可增 0.2.0 之术 `开始入站文字流回应`)。
- 本地 `wrangler dev` 于八路并发压测重复数次后崩溃而退(旧实现同然),不碍单请求之正确;生产未见。