webloom-framework 0.3.0 → 0.4.1
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/README.md +70 -42
- package/dist/advanced.d.ts +168 -0
- package/dist/advanced.js +441 -0
- package/dist/advanced.js.map +1 -0
- package/dist/chunk-4DSINPZD.js +158 -0
- package/dist/chunk-4DSINPZD.js.map +1 -0
- package/dist/chunk-ANA6GBEI.js +1737 -0
- package/dist/chunk-ANA6GBEI.js.map +1 -0
- package/dist/chunk-HJKPKWI7.js +4024 -0
- package/dist/chunk-HJKPKWI7.js.map +1 -0
- package/dist/chunk-SX46RHDI.js +433 -0
- package/dist/chunk-SX46RHDI.js.map +1 -0
- package/dist/index.d.ts +39 -259
- package/dist/index.js +38 -1359
- package/dist/index.js.map +1 -1
- package/dist/messageBus-CtrwkjrO.d.ts +5 -0
- package/dist/messagePortServiceTransport-BYprNvQY.d.ts +264 -0
- package/dist/react.d.ts +41 -28
- package/dist/react.js +79 -88
- package/dist/react.js.map +1 -1
- package/dist/runtimeTypes-DquUCHz-.d.ts +1640 -0
- package/dist/sharedWorkerHost-KI7TIGdX.d.ts +192 -0
- package/dist/testing.d.ts +18 -17
- package/dist/testing.js +23 -15
- package/dist/testing.js.map +1 -1
- package/dist/windowRuntime-BKkLPsAS.d.ts +23 -0
- package/docs/api.md +148 -111
- package/docs/proposals/webloom-v4/implementation-plan.md +443 -0
- package/docs/proposals/webloom-v4/requirements.md +555 -0
- package/docs/proposals/webloom-v4/verification.md +115 -0
- package/package.json +11 -2
- package/dist/chunk-76BGPI6M.js +0 -4261
- package/dist/chunk-76BGPI6M.js.map +0 -1
- package/dist/createPluginHost-BVsUCDKN.d.ts +0 -1318
- package/dist/resourceRegistry-BFnjmeGE.d.ts +0 -267
package/docs/api.md
CHANGED
|
@@ -1,27 +1,31 @@
|
|
|
1
|
-
# WebLoom API 说明
|
|
1
|
+
# WebLoom v4 API 说明
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
WebLoom 0.4.1 只支持两个真实 JavaScript realm:`window-main` 和
|
|
4
|
+
`shared-worker`。`runtime` 是受限的 `RuntimeKind`,不是可自由填写的环境标签;不支持
|
|
5
|
+
的 Runtime 在装配边界 fail closed。
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
`
|
|
7
|
-
|
|
8
|
-
其它服务端 PluginHost。
|
|
7
|
+
一次 Runtime 启动生成不可复用的 `runtimeInstanceId`。每个插件运行单元启动生成不可
|
|
8
|
+
复用的 `instanceId`。同一个 SharedWorker 接收多个 Window 连接时,Worker 单元仍只有
|
|
9
|
+
一个实例;每条物理端口拥有独立的 peer、调用、订阅和 exposure。
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
会生成不可复用的运行单元 `instanceId`。同一 SharedWorker 接收多个 Window 连接
|
|
12
|
-
时,Worker 单元仍只有一个实例;端口本身隔离请求和取消空间,物理端口身份不进入
|
|
13
|
-
公共 Runtime 或 RemoteService wire。
|
|
11
|
+
## capability 与普通插件
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
Capability 对象是契约、类型和运行时校验的唯一入口。跨 realm 只发送不含函数的
|
|
14
|
+
`{ kind, id, version }` descriptor;parser、transfer extractor 和 handler 留在各自
|
|
15
|
+
realm。
|
|
16
16
|
|
|
17
17
|
```ts
|
|
18
|
-
import { createWindowApp, definePlugin } from "webloom-framework";
|
|
18
|
+
import { createWindowApp, defineCapability, definePlugin } from "webloom-framework";
|
|
19
|
+
|
|
20
|
+
const Hello = defineCapability<{ value: string }>({
|
|
21
|
+
kind: "local", id: "hello.service", version: "1",
|
|
22
|
+
});
|
|
19
23
|
|
|
20
24
|
const hello = definePlugin({
|
|
21
25
|
id: "hello",
|
|
22
|
-
provides: [
|
|
26
|
+
provides: [Hello] as const,
|
|
23
27
|
setup(ctx) {
|
|
24
|
-
ctx.provide(
|
|
28
|
+
ctx.provide(Hello, { value: "world" });
|
|
25
29
|
ctx.onDispose(() => {
|
|
26
30
|
// 释放本插件登记的资源。
|
|
27
31
|
});
|
|
@@ -29,144 +33,177 @@ const hello = definePlugin({
|
|
|
29
33
|
});
|
|
30
34
|
|
|
31
35
|
const app = await createWindowApp({ plugins: [hello] });
|
|
32
|
-
const service = app.capability
|
|
36
|
+
const service = app.capability(Hello);
|
|
33
37
|
```
|
|
34
38
|
|
|
35
|
-
|
|
36
|
-
静态 descriptor 可用于验证和快照,不携带函数。`createWindowApp()` 自动固定
|
|
37
|
-
`window-main`、生成实例身份、创建内部 Implementation Registry、批量注册并
|
|
38
|
-
等待初始启动;使用者不需要手工 `register()`。
|
|
39
|
+
local capability 不能跨 Runtime;RPC/stream capability 必须提供生产 `ValueParser`:
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
```ts
|
|
42
|
+
const ReadProfile = defineCapability({
|
|
43
|
+
kind: "rpc",
|
|
44
|
+
id: "profile.read",
|
|
45
|
+
version: "1",
|
|
46
|
+
request: profileRequestParser,
|
|
47
|
+
response: profileResponseParser,
|
|
48
|
+
});
|
|
43
49
|
|
|
44
|
-
|
|
50
|
+
const Changes = defineCapability({
|
|
51
|
+
kind: "stream",
|
|
52
|
+
id: "profile.changes",
|
|
53
|
+
version: "1",
|
|
54
|
+
request: profileWatchParser,
|
|
55
|
+
item: profileChangeParser,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const profile = definePlugin({
|
|
59
|
+
id: "profile",
|
|
60
|
+
provides: [ReadProfile, Changes] as const,
|
|
61
|
+
setup(ctx) {
|
|
62
|
+
ctx.handle(ReadProfile, (request, call) => loadProfile(request.userId, call.signal));
|
|
63
|
+
ctx.handle(Changes, (request, call) => observeProfiles(request, call.signal));
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`ctx.provide(C, value)` 只注册声明的 local;`ctx.handle(C, handler)` 只注册声明的
|
|
69
|
+
RPC/stream。`ctx.capability(C)` 和 `ctx.optionalCapability(C)` 的参数、返回值由 C
|
|
70
|
+
推导,调用者不再手写请求/结果泛型,也不能临时传入 transfer 数组。
|
|
71
|
+
|
|
72
|
+
## SharedWorker 与双向 peer
|
|
45
73
|
|
|
46
74
|
Worker 入口:
|
|
47
75
|
|
|
48
76
|
```ts
|
|
49
77
|
import { definePlugin, startSharedWorkerApp } from "webloom-framework";
|
|
78
|
+
import { Health } from "./contracts";
|
|
50
79
|
|
|
51
|
-
const
|
|
52
|
-
id: "
|
|
53
|
-
provides: [
|
|
80
|
+
const coordinator = definePlugin({
|
|
81
|
+
id: "coordinator",
|
|
82
|
+
provides: [Health] as const,
|
|
54
83
|
setup(ctx) {
|
|
55
|
-
ctx.
|
|
56
|
-
handle(request: { key: string }) {
|
|
57
|
-
return { key: request.key };
|
|
58
|
-
},
|
|
59
|
-
});
|
|
84
|
+
ctx.handle(Health, (request) => ({ type: request.type, instanceId: ctx.instanceId }));
|
|
60
85
|
},
|
|
61
86
|
});
|
|
62
87
|
|
|
63
|
-
startSharedWorkerApp({ id: "coordinator", plugins: [
|
|
88
|
+
startSharedWorkerApp({ id: "coordinator", plugins: [coordinator], expose: [Health] });
|
|
64
89
|
```
|
|
65
90
|
|
|
66
|
-
Window
|
|
91
|
+
Window 侧把 Bundler 生成的 JavaScript Worker URL 传给连接器:
|
|
67
92
|
|
|
68
93
|
```ts
|
|
69
|
-
|
|
70
|
-
import coordinatorWorkerUrl from "./coordinator.worker.ts?sharedworker&url";
|
|
94
|
+
import workerUrl from "./coordinator.worker.ts?sharedworker&url";
|
|
71
95
|
import { connectSharedWorker } from "webloom-framework";
|
|
96
|
+
import { Health } from "./contracts";
|
|
72
97
|
|
|
98
|
+
const runtime = connectSharedWorker({ id: "coordinator", url: workerUrl });
|
|
99
|
+
const result = await runtime.capability(Health).call({ type: "health" });
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`connectSharedWorker()` 同步返回 `RuntimeHandle`。远程 capability 的 proxy 构造不等待
|
|
103
|
+
Worker;第一次 call/subscribe 在一个有限 deadline 内等待精确的 Runtime、contract 和
|
|
104
|
+
service exposure。断线、协议不兼容、超时和撤销都返回结构化错误;框架不自动重连或重放。
|
|
105
|
+
|
|
106
|
+
页面反向能力必须先存在于 WindowApp:
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
const page = await createWindowApp({ plugins: [pageIoPlugin] });
|
|
73
110
|
const runtime = connectSharedWorker({
|
|
74
111
|
id: "coordinator",
|
|
75
|
-
url:
|
|
112
|
+
url: workerUrl,
|
|
113
|
+
client: { app: page, expose: [LocalStorageIo] },
|
|
76
114
|
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Worker 的 handler 通过 `call.peer.capability(LocalStorageIo)` 得到当前端口对应页面的
|
|
118
|
+
typed client。`PeerController` 只在可信 `configurePeer` 回调中出现,不暴露原始 port、Worker 或发送函数;`peer.expose(C, options)`
|
|
119
|
+
只允许暴露本 Host 已注册的 RPC/stream,并在 provider scope、peer scope 和领域 scope
|
|
120
|
+
任一撤销时同步移除。授权更新必须 revoke 旧 exposure 后新建,旧 proxy 永不换绑。
|
|
121
|
+
|
|
122
|
+
如果页面需要在已有 Host 上分阶段增加远程依赖,从 `/advanced` 使用:
|
|
77
123
|
|
|
78
|
-
|
|
79
|
-
|
|
124
|
+
```ts
|
|
125
|
+
import { attachRemote, registerPlugins } from "webloom-framework/advanced";
|
|
126
|
+
|
|
127
|
+
const detach = await attachRemote(page, runtime);
|
|
128
|
+
await registerPlugins(page, [remoteConsumerPlugin]);
|
|
129
|
+
// 结束页面生命周期时:detach(); await page.dispose();
|
|
80
130
|
```
|
|
81
131
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
返回惰性代理,第一次 `call()` 在同一个有限 deadline 内等待目录和远程执行。断线、
|
|
85
|
-
协议不兼容、Worker 重启或 Provider 实例变化都会同步撤销旧代理。显式重建只建立
|
|
86
|
-
新句柄和新代理,不会重放可能产生外部副作用的调用,也不会静默替换旧代理的绑定。
|
|
132
|
+
普通 `createWindowApp()` 不接受 Host 或测试 scope 注入,也不会根据 Worker manifest 创建
|
|
133
|
+
第二套 Window 单元。
|
|
87
134
|
|
|
88
|
-
|
|
89
|
-
`?sharedworker&url` 或等价的独立 Rollup entry;不要把
|
|
90
|
-
`new URL("./coordinator.worker.ts", import.meta.url)` 作为普通参数传入框架,
|
|
91
|
-
因为框架内部的 `new SharedWorker()` 不会让 Vite 重新发现调用方源码入口。
|
|
135
|
+
## wire、快照与错误
|
|
92
136
|
|
|
93
|
-
`
|
|
137
|
+
唯一 Runtime wire 是 `webloom.runtime.v1`,消息为 snapshot、runtime-error、call、result、
|
|
138
|
+
error、cancel、next、credit。快照只有 ready 状态发布当前可调用 services;每条 peer 有
|
|
139
|
+
独立严格递增 revision。旧协议被明确拒绝,不尝试降级解析。
|
|
94
140
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
141
|
+
框架错误通过 `WebLoomError` 暴露,至少覆盖 `protocol_mismatch`、`invalid_snapshot`、
|
|
142
|
+
`capability_unavailable`、`contract_mismatch`、`request_validation_failed`、
|
|
143
|
+
`response_validation_failed`、`request_clone_failed`、`response_clone_failed`、
|
|
144
|
+
`transfer_invalid`、`handler_failed`、`call_timeout`、`request_cancelled`、
|
|
145
|
+
`service_revoked`、`service_stale`、`transport_unavailable`、
|
|
146
|
+
`runtime_initialization_failed` 和 `stream_overflow`。错误只带脱敏 message/details,
|
|
147
|
+
不回显 request、密钥、口令、凭据或授权 headers;发送请求后的超时不推断远端副作用一定
|
|
148
|
+
未发生。
|
|
103
149
|
|
|
104
|
-
|
|
150
|
+
## transfer 与 stream
|
|
105
151
|
|
|
106
|
-
|
|
107
|
-
|
|
152
|
+
RPC 契约可声明 `transfer.request(value)`、`transfer.response(value)`,stream 契约可声明
|
|
153
|
+
`transfer.item(value)`。顺序固定为 parser → extractor/去重/可达性校验 → `postMessage`;
|
|
154
|
+
接收端再次 parser。多个 TypedArray 视图共享同一个 backing buffer 时,转移其中一个会
|
|
155
|
+
转移整个 buffer 的所有权。发送后取消不恢复所有权,也不会自动重传;迟到结果不交付给
|
|
156
|
+
旧 proxy。
|
|
157
|
+
|
|
158
|
+
Stream handler 返回 `AsyncIterable`,订阅返回 `ready`、`closed` 和幂等 `cancel()`:
|
|
108
159
|
|
|
109
160
|
```ts
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
contractVersion: "coordinator.service.v1",
|
|
117
|
-
sourceRuntime: "shared-worker",
|
|
118
|
-
}],
|
|
119
|
-
setup(ctx) {
|
|
120
|
-
const coordinator = ctx.serviceBridge?.requireProxy({
|
|
121
|
-
capabilityId: "coordinator.service",
|
|
122
|
-
contractVersion: "coordinator.service.v1",
|
|
123
|
-
runtime: "shared-worker",
|
|
124
|
-
}, ctx.scope);
|
|
125
|
-
if (!coordinator) throw new Error("Remote service bridge is unavailable");
|
|
126
|
-
ctx.provide("window.coordinator", coordinator);
|
|
127
|
-
},
|
|
128
|
-
})],
|
|
129
|
-
});
|
|
161
|
+
const sub = runtime.capability(Changes).subscribe(
|
|
162
|
+
{ userId: "123" },
|
|
163
|
+
{ onNext: renderChange, timeoutMs: 5_000 },
|
|
164
|
+
);
|
|
165
|
+
await sub.ready;
|
|
166
|
+
await sub.closed;
|
|
130
167
|
```
|
|
131
168
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
和远程代理,显式重建后的新代理必须重新取得,不会静默重绑旧引用。
|
|
169
|
+
默认 credit 为 16,窗口范围为 1–256;没有 credit 时 producer 不拉取 iterator,item
|
|
170
|
+
交付完成后才补回 credit。sequence 从 1 连续递增;错序、重复、非法 credit、消费者
|
|
171
|
+
回调失败和撤销都会终止当前订阅,不影响其它 peer。长流没有自动心跳或持久重放保证。
|
|
136
172
|
|
|
137
|
-
##
|
|
173
|
+
## Scope、诊断与 React
|
|
138
174
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
ownership 和 cleanup callbacks;这个 Scope 不再从用户声明的生命周期分类推导。
|
|
175
|
+
`scope.listen()`、`scope.interval()`、`scope.subscribe()` 都返回幂等 release,并在同步
|
|
176
|
+
revoke 时解除资源;它们复用同一个 Scope resource ledger。异步创建使用 `scope.acquire()`,
|
|
177
|
+
晚到资源仍会在 Scope 已撤销后尽力释放。
|
|
143
178
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
`LifecycleDisposeResult` 暴露。
|
|
179
|
+
App/Handle 提供不可变 `state()`、`inspect()`、`subscribe()`。inspect 只报告 Runtime、
|
|
180
|
+
插件/单元、scope、peer 和 framework-owned pending/stream 计数;`explain()` 返回稳定的
|
|
181
|
+
缺 provider、契约不匹配、依赖阻塞、scope 撤销和初始化失败原因,不包含业务载荷。
|
|
148
182
|
|
|
149
|
-
|
|
150
|
-
fence)不属于 WebLoom Runtime 生命周期。应用自己的 Coordinator/服务控制器
|
|
151
|
-
负责推进领域状态,再通过新的服务快照让旧代理失效。
|
|
183
|
+
React 在 `/react`:
|
|
152
184
|
|
|
153
|
-
|
|
185
|
+
```tsx
|
|
186
|
+
import { WebLoomProvider, useCapability, usePluginState } from "webloom-framework/react";
|
|
187
|
+
|
|
188
|
+
function Panel() {
|
|
189
|
+
const health = useCapability(Health);
|
|
190
|
+
const plugin = usePluginState("coordinator");
|
|
191
|
+
return <output>{plugin?.lifecycleState ?? health ? "ready" : "waiting"}</output>;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
<WebLoomProvider app={runtime}><Panel /></WebLoomProvider>;
|
|
195
|
+
```
|
|
154
196
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
`defineRuntimeUnitProvidedContracts()` 生成默认 v1 版本;框架不会根据 capability
|
|
158
|
-
名称猜测远端服务。`providedContracts`、Provider 实例身份、Runtime 启动身份和
|
|
159
|
-
快照 revision 都参与代理绑定。
|
|
197
|
+
Provider 保存稳定 App 引用,hooks 使用外部 store 一致性机制;capability、plugin 和
|
|
198
|
+
selector 按相关状态订阅,不把每次全局版本变化广播给所有消费者。
|
|
160
199
|
|
|
161
|
-
##
|
|
200
|
+
## 入口边界
|
|
162
201
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
202
|
+
- 主入口:capability、插件、三个 Runtime 构造函数、App/Handle、契约/错误/Scope;不加载 React 或底层 transport。
|
|
203
|
+
- `/advanced`:Host/graph/registry、peer exposure、strict v4 bridge/provider 和分阶段装配。
|
|
204
|
+
- `/react`:WebLoomProvider、typed capability/plugin/resource hooks。
|
|
205
|
+
- `/testing`:生产 parser 驱动的 fake transport、可控 Worker/Scope harness。
|
|
167
206
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
仓库提供 `scripts/browser-runtime-fixture/` 与 `pnpm run test:browser`;缺少
|
|
172
|
-
Playwright/Chromium 时脚本明确报告 unsupported,不回退为 Node 或同页面模拟。
|
|
207
|
+
真实浏览器验收必须使用 Bundler 产出的 SharedWorker chunk 和 Chromium;Node
|
|
208
|
+
MessageChannel 单测只证明 transport simulation,不替代 Window/SharedWorker realm、多个
|
|
209
|
+
页面、transfer ownership 或 Worker 退出验收。
|