@dp-bohrium/widget-sdk 0.0.1 → 0.0.3

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.
Files changed (2) hide show
  1. package/README.md +87 -97
  2. package/package.json +17 -3
package/README.md CHANGED
@@ -1,36 +1,34 @@
1
1
  # @dp-bohrium/widget-sdk
2
2
 
3
- Widget developer SDK. Use `createWidgetClient` inside a production Widget
4
- Bundle. It announces the bundle to the Host, accepts the transferred
5
- `MessagePort`, and exposes the shared lifecycle and capability protocol
6
- without requiring Widget code to handle `window.postMessage` directly.
3
+ Widget 开发者 SDK。在生产 Widget Bundle 内使用 `createWidgetClient`:向 Host
4
+ 宣告 Bundle、接收转移过来的 `MessagePort`,并暴露共享的生命周期与能力协议,
5
+ 无需直接处理 `window.postMessage`。
7
6
 
8
- Install the exact prerelease from the internal registry:
7
+ npmjs 安装(默认最新版):
9
8
 
10
9
  ```bash
11
- pnpm add @dp-bohrium/widget-sdk@0.0.1 \
12
- --registry=https://registry.npmjs.org
10
+ pnpm add @dp-bohrium/widget-sdk
13
11
  ```
14
12
 
15
- Host Runtime and Shrimp should keep consuming `@dp-bohrium/widget-contracts`.
16
- They must not install this package.
13
+ Host 与控制面应继续只消费 `@dp-bohrium/widget-contracts`,不要安装本包。
17
14
 
18
15
  ```ts
19
16
  import { createWidgetClient } from "@dp-bohrium/widget-sdk";
20
17
 
21
18
  const widget = createWidgetClient({
22
- widgetSdkVersion: "0.0.1",
19
+ // 填入已安装的 @dp-bohrium/widget-sdk 精确版本(npm view / package.json)
20
+ widgetSdkVersion: "REPLACE_WITH_INSTALLED_SDK_VERSION",
23
21
  async onInit(payload) {
24
- // Initialize using the Host-provided locale, theme and capabilities.
22
+ // 使用 Host 下发的 localetheme capabilities 初始化。
25
23
  console.log(payload.locale);
26
- await Promise.resolve(); // Load application state here.
24
+ await Promise.resolve(); // 在此加载应用状态。
27
25
  },
28
26
  onRender(request) {
29
- // Render the complete snapshot for the selected slot.
27
+ // 按所选 Slot 渲染完整快照。
30
28
  console.log(request.slot);
31
29
  },
32
30
  onDispose({ reason, deadlineMs }) {
33
- // Release local timers, subscriptions and workers.
31
+ // 释放本地定时器、订阅与 worker。
34
32
  console.log(reason, deadlineMs);
35
33
  },
36
34
  });
@@ -39,10 +37,11 @@ await widget.ready();
39
37
  widget.resize({ width: 600, height: 400 });
40
38
  ```
41
39
 
42
- ## Host-managed network access
40
+ ## Host 托管的网络访问
43
41
 
44
- Declare `requestedCapabilities.network.fetch` in the Widget Manifest, then use the typed facade after
45
- `ready()` resolves. The Widget never receives Host credentials and does not call browser `fetch` directly:
42
+ Widget Manifest 中声明 `requestedCapabilities.network.fetch`,在 `ready()`
43
+ 完成后再调用类型化 facade。Widget 不会收到 Host 凭据,也不应直接调用浏览器
44
+ `fetch`:
46
45
 
47
46
  ```ts
48
47
  const controller = new AbortController();
@@ -63,17 +62,16 @@ if (result.ok) {
63
62
  }
64
63
  ```
65
64
 
66
- The Host decides whether to prompt, remember an exact Origin grant, select an opaque credential binding,
67
- follow a redirect, or deny the request. Calls before readiness, after disposal, or without a current
68
- `network.fetch` grant reject locally. Abort and timeout reuse the existing MessageChannel capability lifecycle.
69
- `requestCapability` remains available for protocol-level integrations, but `widget.network.fetch` is the
70
- supported network API for Widget application code.
65
+ 是否弹窗、记住精确 Origin 授权、选择不透明凭据绑定、跟随重定向或拒绝,均由
66
+ Host 决定。在未就绪、已 dispose,或当前没有 `network.fetch` grant 时,调用会在
67
+ 本地拒绝。中止与超时复用既有 MessageChannel 能力生命周期。
68
+ `requestCapability` 仍可用于协议级集成,但 Widget 应用代码应优先使用
69
+ `widget.network.fetch`。
71
70
 
72
- ## Host-governed panel presentation
71
+ ## Host 治理的面板呈现
73
72
 
74
- Panel Widgets can ask the Host to present their current panel in a workspace,
75
- floating, or overlay surface. The same methods are available on the ordinary
76
- `createWidgetClient()` result and the low-level `WidgetClient`:
73
+ Panel Widget 可以请求 Host workspace、floating overlay 表面呈现当前面板。
74
+ 普通 `createWidgetClient()` 结果与低层 `WidgetClient` 上均可使用相同方法:
77
75
 
78
76
  ```ts
79
77
  import { PRESENTATION_CONFIRMATION_TIMEOUT_MS } from "@dp-bohrium/widget-sdk";
@@ -87,8 +85,8 @@ const result = await widget.present("floating", {
87
85
  if (!result.ok) {
88
86
  showPresentationDenial(result.reason, result.message);
89
87
  } else if ("surface" in result.data) {
90
- // The Host can report a different actual surface, such as a compact-mode
91
- // downgrade from floating to overlay or workspace.
88
+ // Host 可能回报不同的实际表面,例如紧凑模式下从 floating 降级到 overlay
89
+ // workspace
92
90
  showCurrentSurface(result.data.surface);
93
91
  }
94
92
 
@@ -97,74 +95,59 @@ await widget.focusPresentationBoundary("forward");
97
95
  await widget.closePresentation();
98
96
  ```
99
97
 
100
- When the Host grants `ui.presentation` with the `overlay` surface, the ordinary
101
- client also installs keyboard cooperation for cross-origin Panel overlays. An
102
- unhandled, trusted, non-composing Escape requests `closePresentation()`. A Tab
103
- that is followed by focus leaving the iframe requests
104
- `focusPresentationBoundary("forward" | "backward")`; internal focus movement
105
- does not send anything. Frameworks with a custom focus manager can call the
106
- typed helper directly.
107
-
108
- The default confirmation timeout is 60 seconds. `timeoutMs` overrides it and
109
- `signal` cancels local waiting. A Host policy or user denial resolves normally
110
- as `{ ok: false, reason, message, retryable }`; client timeout, abort, dispose,
111
- or a malformed successful response rejects the Promise. Browser resize,
112
- visibility, focus, and pointer events are never treated as confirmation.
113
-
114
- These methods only request a presentation. The Host remains the final authority
115
- for grants, supported surfaces, confirmation, compact-mode downgrade, and the
116
- actual panel state. `isTrusted` and `defaultPrevented` are Widget-realm noise
117
- filters, not authorization: the MessageChannel identifies the current iframe
118
- instance but cannot prove a physical key or human activation. The Widget cannot
119
- name a target Panel, Host selector, identity, runtime generation, coordinate, or
120
- layer. The Host must recheck the current instance, top Overlay, focus epoch, and
121
- higher security layers before accepting either request.
122
-
123
- `ready()` is not sent to the Host until `onInit` returns or its Promise
124
- settles. If initialization fails, the SDK reports a structured `onError`
125
- event and then invokes `onDispose` so local resources can be released.
126
- `handshakeTimeoutMs` also bounds this initialization step after the Host
127
- connection has been established.
128
-
129
- When only `onUpdate` is supplied, the first complete `render` snapshot is also
130
- delivered to `onUpdate`.
131
-
132
- `WidgetClient` provides the framework-neutral, low-level runtime interface.
133
- Capability requests accept `{ timeoutMs, signal }`, so application lifecycle
134
- hooks can cancel pending reads without receiving late results. It is available
135
- from `@dp-bohrium/widget-sdk/runtime` for advanced integrations and protocol-level
136
- tests.
137
-
138
- The main entry exposes the production `createWidgetClient` factory. Low-level
139
- protocol classes and bootstrap constants are available from
140
- `@dp-bohrium/widget-sdk/runtime`; `MessagePortTransport` and the bootstrap
141
- messages are not part of the ordinary Widget API.
142
-
143
- `@dp-bohrium/widget-sdk/testing` provides `MemoryTransport` and
144
- `MockWidgetHost`. The Mock Host owns init/ready sequencing, first-render versus
145
- update selection, resize events, capability adapter responses, and terminal
146
- dispose behavior. It uses the same public contracts as production Hosts but
147
- does not claim production iframe, CSP, authorization, or resource-isolation
148
- guarantees. Contract validators stay in the unpublished
149
- `@dp-bohrium/widget-contract-testing` workspace package.
150
-
151
- Set `capabilityResult` for one deterministic default allow or denial. A supplied
152
- `handleCapability` remains the authoritative advanced handler when both are
153
- present. `host.capabilityRequests` returns an ordered defensive-copy snapshot,
154
- so tests can inspect requests without mutating Mock Host state.
155
-
156
- or fallback UI. If the Host iframe uses `sandbox="allow-scripts"` without
157
- `allow-same-origin`, load the bundled Widget as a classic script or IIFE
158
- unless the isolated origin serves CORS headers for `type="module"`.
159
-
160
- If the Host sends a malformed Bridge envelope or payload, the transport reports
161
- a structured `MESSAGE_INVALID` error and closes the connection. The Widget is
162
- not left waiting on a connection that the Host still considers active.
98
+ Host 授予带 `overlay` 表面的 `ui.presentation` 时,普通 client 还会安装跨源
99
+ Panel overlay 的键盘协作:未处理、受信、非 composing Escape 会请求
100
+ `closePresentation()`;Tab 之后焦点离开 iframe 会请求
101
+ `focusPresentationBoundary("forward" | "backward")`;iframe 内焦点移动不会发消息。
102
+ 有自定义焦点管理器的框架可直接调用类型化 helper。
163
103
 
104
+ 默认确认超时为 60 秒。可用 `timeoutMs` 覆盖,用 `signal` 取消本地等待。Host
105
+ 策略拒绝或用户拒绝会以 `{ ok: false, reason, message, retryable }` 正常兑现;
106
+ 客户端超时、中止、dispose 或畸形成功响应会 reject Promise。浏览器 resize、
107
+ 可见性、焦点与指针事件都不会被当成确认。
108
+
109
+ 这些方法只是提出呈现请求。grant、支持的表面、确认、紧凑模式降级与真实面板状态
110
+ 仍由 Host 最终裁决。`isTrusted` 与 `defaultPrevented` 只是 Widget 域内噪声过滤,
111
+ 不是授权:MessageChannel 能识别当前 iframe 实例,但不能证明物理按键或人类激活。
112
+ Widget 不能指定目标 Panel、Host 选择器、身份、运行时 generation、坐标或层级。
113
+ Host 在接受请求前必须复核当前实例、顶层 Overlay、焦点 epoch 与更高安全层。
114
+
115
+ `ready()` 不会在 `onInit` 返回(或其 Promise settle)之前发给 Host。初始化失败时,
116
+ SDK 会报告结构化 `onError`,再调用 `onDispose` 以便释放本地资源。
117
+ `handshakeTimeoutMs` 也会在 Host 连接建立后约束该初始化步骤。
118
+
119
+ 若只提供了 `onUpdate`,首次完整 `render` 快照也会投递给 `onUpdate`。
120
+
121
+ `WidgetClient` 提供框架无关的低层运行时接口。能力请求接受
122
+ `{ timeoutMs, signal }`,应用生命周期钩子可取消在途读取、避免迟到结果。高级集成与
123
+ 协议级测试可从 `@dp-bohrium/widget-sdk/runtime` 使用。
124
+
125
+ 主入口暴露生产用 `createWidgetClient`。低层协议类与 bootstrap 常量见
126
+ `@dp-bohrium/widget-sdk/runtime`;`MessagePortTransport` 与 bootstrap 消息不属于
127
+ 普通 Widget API。
128
+
129
+ `@dp-bohrium/widget-sdk/testing` 提供 `MemoryTransport` 与 `MockWidgetHost`。
130
+ Mock Host 负责 init/ready 时序、首帧 render 与 update 选择、resize 事件、能力
131
+ adapter 响应与终态 dispose。它使用与生产 Host 相同的公开 contracts,但不等同于
132
+ 生产 iframe、CSP、授权或资源隔离保证。Schema 与类型校验以
133
+ `@dp-bohrium/widget-contracts` 为准。
134
+
135
+ 可用 `capabilityResult` 给出确定性的默认允许或拒绝;若同时提供
136
+ `handleCapability`,后者仍是权威的高级处理器。`host.capabilityRequests` 返回有序的
137
+ 防御性拷贝快照,测试可检查请求而不改动 Mock Host 状态。
138
+
139
+ 若 Host iframe 使用 `sandbox="allow-scripts"` 且没有 `allow-same-origin`,除非隔离
140
+ 源为 `type="module"` 提供 CORS,否则请将打包后的 Widget 以 classic script / IIFE
141
+ 加载。
142
+
143
+ 若 Host 发送畸形 Bridge 信封或载荷,transport 会报告结构化 `MESSAGE_INVALID`
144
+ 并关闭连接,不会让 Widget 继续等待一个 Host 仍视为活跃的连接。
164
145
 
165
146
  ## 受授权的事件订阅与工具 Hook(本地候选)
166
147
 
167
- 新增 `subscribeEvents`、`onTool` 和 `invokeAction`。Manifest 声明与 Host 实际 grant 必须同时包含 topic/action,旧 Host 不会自动获得这些能力;发布时需一起升级 contracts 和消费者。订阅类型从包根与 `/runtime` 导出。
148
+ 新增 `subscribeEvents`、`onTool` 和 `invokeAction`。Manifest 声明与 Host 实际
149
+ grant 必须同时包含 topic/action;旧 Host 不会自动获得这些能力,发布时需一起升级
150
+ contracts 与消费者。订阅类型从包根与 `/runtime` 导出。
168
151
 
169
152
  ```ts
170
153
  const events = client.subscribeEvents({
@@ -192,10 +175,17 @@ events.unsubscribe();
192
175
  hooks.unsubscribe();
193
176
  ```
194
177
 
195
- Hook 观察已经发生的服务端工具事实,不是执行前拦截器;不允许通过 iframe 回调改写参数、审批或控制 durable 执行。`tools.inspect` 是当前 Shrimp 的只读动作 provider,返回工具身份和最新可读取状态;其他 action 由 Host/provider 显式实现并授权。SDK 不自动重试动作,也不把回调完成解释为工具执行完成。
196
-
197
- 所有订阅共享实例的 events 请求预算,并各自遵守 topic 最小间隔。游标仅在 `onBatch` 成功后提交;消费者异常、权限撤销和不可恢复的历史错误会关闭订阅并调用 `onError`。`unsubscribe` 和 Host dispose 释放订阅、排队请求和本地在途等待,忽略迟到结果;异步回调需检查传入 signal 后再更新自己的状态。`closed` 表示订阅已关闭,并不等待用户未完成的回调结束。重新订阅时显式传入已保存 cursor。
178
+ Hook 观察已经发生的服务端工具事实,不是执行前拦截器;不允许通过 iframe 回调改写
179
+ 参数、审批或控制 durable 执行。`tools.inspect` 是常见的只读动作
180
+ provider 示例,返回工具身份和最新可读取状态;其他 action Host/provider 显式实现并
181
+ 授权。SDK 不自动重试动作,也不把回调完成解释为工具执行完成。
198
182
 
199
- 维护者可复验包在仓库 `examples/forge/tool-observer`,不包含在开发者 npm 包中。
183
+ 所有订阅共享实例的 events 请求预算,并各自遵守 topic 最小间隔。游标仅在
184
+ `onBatch` 成功后提交;消费者异常、权限撤销和不可恢复的历史错误会关闭订阅并调用
185
+ `onError`。`unsubscribe` 和 Host dispose 释放订阅、排队请求和本地在途等待,忽略
186
+ 迟到结果;异步回调需检查传入 signal 后再更新自己的状态。`closed` 表示订阅已关闭,
187
+ 并不等待用户未完成的回调结束。重新订阅时显式传入已保存 cursor。
200
188
 
201
- 每次 events.read 是有界、非阻塞读取;当前 V1 没有单请求取消 wire 消息,unsubscribe 会停止后续轮询并取消本地等待,已经发出的服务端读取可能完成但其结果被忽略。Host 实例卸载另通过既有 lease/AbortSignal 释放在途宿主请求。
189
+ 每次 events.read 是有界、非阻塞读取;当前 V1 没有单请求取消 wire 消息,
190
+ unsubscribe 会停止后续轮询并取消本地等待,已经发出的服务端读取可能完成但其结果被
191
+ 忽略。Host 实例卸载另通过既有 lease/AbortSignal 释放在途宿主请求。
package/package.json CHANGED
@@ -1,12 +1,25 @@
1
1
  {
2
2
  "name": "@dp-bohrium/widget-sdk",
3
- "version": "0.0.1",
4
- "description": "Widget developer SDK runtime client for Bohrium Widget Platform.",
3
+ "version": "0.0.3",
4
+ "description": "Bohrium Widget 开发者 SDK:在 Widget Bundle 内与 Host 建立 Bridge,并暴露生命周期与能力协议。",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "engines": {
8
8
  "node": ">=20"
9
9
  },
10
+ "keywords": [
11
+ "bohrium",
12
+ "dp-bohrium",
13
+ "widget",
14
+ "sdk",
15
+ "iframe",
16
+ "messagechannel",
17
+ "host-bridge",
18
+ "runtime"
19
+ ],
20
+ "author": "Bohrium",
21
+ "homepage": "https://www.npmjs.com/package/@dp-bohrium/widget-sdk",
22
+ "types": "./dist/index.d.ts",
10
23
  "exports": {
11
24
  ".": {
12
25
  "types": "./dist/index.d.ts",
@@ -27,11 +40,12 @@
27
40
  "README.md",
28
41
  "LICENSE"
29
42
  ],
43
+ "sideEffects": false,
30
44
  "publishConfig": {
31
45
  "access": "public"
32
46
  },
33
47
  "dependencies": {
34
- "@dp-bohrium/widget-contracts": "0.0.1"
48
+ "@dp-bohrium/widget-contracts": "0.0.3"
35
49
  },
36
50
  "devDependencies": {
37
51
  "@biomejs/biome": "^2.2.0",