@dp-bohrium/widget-sdk 0.0.6 → 0.0.7

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 CHANGED
@@ -4,32 +4,48 @@ Widget 开发者 SDK。在生产 Widget Bundle 内使用 `createWidgetClient`:
4
4
  宣告 Bundle、接收转移过来的 `MessagePort`,并暴露共享的生命周期与能力协议,
5
5
  无需直接处理 `window.postMessage`。
6
6
 
7
- 从 npmjs 安装(默认最新版):
7
+ ## 环境要求
8
+
9
+ | 项 | 要求 |
10
+ | --- | --- |
11
+ | Node.js | ≥ 20(仅构建期;产物运行在浏览器 iframe 内) |
12
+ | 源码格式 | 纯 ESM,必须经打包器处理后交付 |
13
+ | 运行环境 | 必须由 Bohrium Host 加载,脱离 Host 无法完成握手 |
14
+ | 产物格式 | Host iframe 为 `sandbox="allow-scripts"` 且无 `allow-same-origin` 时,打成 classic script / IIFE(隔离源下 `type="module"` 需要 CORS) |
15
+
16
+ ## 安装
17
+
18
+ 写 Widget 装本包。Host 与控制面只消费协议类型,装
19
+ [`@dp-bohrium/widget-contracts`](https://www.npmjs.com/package/@dp-bohrium/widget-contracts)
20
+ 即可。
8
21
 
9
22
  ```bash
23
+ npm install @dp-bohrium/widget-sdk
10
24
  pnpm add @dp-bohrium/widget-sdk
25
+ yarn add @dp-bohrium/widget-sdk
11
26
  ```
12
27
 
13
- Host 与控制面应继续只消费 `@dp-bohrium/widget-contracts`,不要安装本包。
28
+ 在自己的 `package.json` 里钉死精确 SemVer,不要用 `^` 或裸 `latest`。
29
+
30
+ ## 快速开始
14
31
 
15
32
  ```ts
16
33
  import { createWidgetClient } from "@dp-bohrium/widget-sdk";
17
34
 
18
35
  const widget = createWidgetClient({
19
- // 填入已安装的 @dp-bohrium/widget-sdk 精确版本(npm view / package.json)
36
+ // 填已安装的精确版本,并与 manifest.json 的 widgetSdkVersion 写成同一个值。
20
37
  widgetSdkVersion: "REPLACE_WITH_INSTALLED_SDK_VERSION",
21
38
  async onInit(payload) {
22
- // 使用 Host 下发的 locale、theme 与 capabilities 初始化。
23
- console.log(payload.locale);
24
- await Promise.resolve(); // 在此加载应用状态。
39
+ // Host 下发 locale、theme 与已授予的 capabilities。
40
+ await applyHostContext(payload.locale, payload.theme, payload.capabilities);
25
41
  },
26
42
  onRender(request) {
27
- // 按所选 Slot 渲染完整快照。
28
- console.log(request.slot);
43
+ // 按 Slot 渲染完整快照。
44
+ renderSlot(request.slot, request.content);
29
45
  },
30
46
  onDispose({ reason, deadlineMs }) {
31
- // 释放本地定时器、订阅与 worker。
32
- console.log(reason, deadlineMs);
47
+ // 释放定时器、订阅与 worker。
48
+ releaseLocalResources(reason, deadlineMs);
33
49
  },
34
50
  });
35
51
 
@@ -37,155 +53,100 @@ await widget.ready();
37
53
  widget.resize({ width: 600, height: 400 });
38
54
  ```
39
55
 
40
- ## Host 托管的网络访问
56
+ 三条时序约定:
57
+
58
+ - `ready()` 只在 `onInit` 返回(含其 Promise settle)之后才发给 Host,
59
+ `handshakeTimeoutMs` 同时约束这一步;
60
+ - 初始化失败时,SDK 先报结构化 `onError`,再调 `onDispose`;
61
+ - 若只提供 `onUpdate`,首帧完整 `render` 快照也会投递给 `onUpdate`。
62
+
63
+ ## 包入口
64
+
65
+ | 入口 | 内容 | 用途 |
66
+ | --- | --- | --- |
67
+ | `.` | `createWidgetClient`、`PRESENTATION_CONFIRMATION_TIMEOUT_MS`,以及全部公开类型 | 生产 Widget |
68
+ | `./testing` | `MemoryTransport`、`MockWidgetHost` | 单元测试 |
69
+ | `./runtime` | 低层 `WidgetClient`、transport 与 bootstrap 常量 | 协议级集成 |
70
+ | `./package.json` | 已安装包的元数据 | 工具读取版本。源码与 Manifest 的 `widgetSdkVersion` 写成同一个精确版本字符串 |
71
+
72
+ 根入口只导出两个运行时值,其余均为类型。`MessagePortTransport` 与 bootstrap 消息
73
+ 不属于普通 Widget API。
74
+
75
+ ## 能力
41
76
 
42
- 在 Widget Manifest 中声明 `requestedCapabilities.network.fetch`,在 `ready()`
43
- 完成后再调用类型化 facade。Widget 不会收到 Host 凭据,也不应直接调用浏览器
44
- `fetch`:
77
+ 每项能力都要在 Manifest 的 `requestedCapabilities` 里声明,并由 Host 实际 grant;
78
+ 缺任一侧,调用在 Widget 本地即被拒绝。所有能力调用都必须在 `ready()` 之后。
79
+
80
+ 下面五项是当前的全部能力。grant 名与 Manifest 申请键不一定同名 —— `ui.presentation`
81
+ 对应的申请键是 `requestedCapabilities.presentation`。
82
+
83
+ | grant 名 | Manifest 申请键 | SDK 调用 |
84
+ | --- | --- | --- |
85
+ | `files.list` / `files.metadata` / `files.read` | `files` | `widget.requestCapability({ operation, input })` |
86
+ | `events.read` | `events`(需列出 `topics`) | 拉取 `widget.subscribeEvents(…)` / `widget.onTool(…)` |
87
+ | `actions.invoke` | `actions` | `widget.invokeAction(…)` |
88
+ | `network.fetch` | `network` | `widget.network.fetch(…)` |
89
+ | `ui.presentation` | `presentation` | `widget.present(…)` / `changePresentationSurface` / `focusPresentationBoundary` / `closePresentation` |
90
+
91
+ 五项共用同一套调用范式,掌握下面这一个就会调其余四个:
45
92
 
46
93
  ```ts
47
94
  const controller = new AbortController();
48
95
  const result = await widget.network.fetch(
49
- {
50
- url: "https://api.example.org/papers",
51
- auth: "optional",
52
- method: "GET",
53
- headers: { accept: "application/json" },
54
- },
96
+ { url: "https://api.example.org/papers", method: "GET", auth: "optional" },
55
97
  { signal: controller.signal, timeoutMs: 15_000 },
56
98
  );
57
99
 
58
100
  if (result.ok) {
59
101
  consume(result.data.status, result.data.headers, result.data.body);
60
102
  } else {
103
+ // 策略拒绝、用户拒绝、未授权都走这里,不是 throw。
61
104
  showNetworkFailure(result.reason, result.retryable);
62
105
  }
63
106
  ```
64
107
 
65
- 是否弹窗、记住精确 Origin 授权、选择不透明凭据绑定、跟随重定向或拒绝,均由
66
- Host 决定。在未就绪、已 dispose,或当前没有 `network.fetch` grant 时,调用会在
67
- 本地拒绝。中止与超时复用既有 MessageChannel 能力生命周期。
68
- `requestCapability` 仍可用于协议级集成,但 Widget 应用代码应优先使用
69
- `widget.network.fetch`。
70
-
71
- ## Host 治理的面板呈现
72
-
73
- Panel Widget 可以请求 Host 以 workspace、floating 或 overlay 表面呈现当前面板。
74
- 普通 `createWidgetClient()` 结果与低层 `WidgetClient` 上均可使用相同方法:
108
+ 跨能力的六条约定:
109
+
110
+ - 失败以 `{ ok: false, reason, message, retryable }` 正常兑现;只有客户端超时、中止、
111
+ dispose 和畸形响应才 reject。
112
+ - 中止与超时统一用 `{ signal, timeoutMs }`,复用既有 MessageChannel 能力生命周期。
113
+ - Widget 永远拿不到 Host 凭据,也不应直接调用浏览器 `fetch`:是否弹窗、记住 Origin
114
+ 授权、跟随重定向还是拒绝,全部由 Host 决定。
115
+ - 呈现只是**请求**。Host 可能降级到别的表面,成功结果里的 `surface` 才是真实表面;
116
+ Widget 不能指定目标 Panel、身份、运行时 generation、坐标或层级。
117
+ - 事件有两条路径,按需要选一条:`onEvent(handler)` 接收 Host 从当前 Runtime **主动
118
+ 推送**的聚合事件,只按 `type` 分发,不依赖 Manifest Topic 或 `events.read` grant;
119
+ `subscribeEvents` / `onTool` 走兼容的**有界分页拉取**,带游标、可续读。
120
+ - `subscribeEvents` / `onTool` 的所有订阅共享同一实例的 events 读预算,并各自遵守
121
+ topic 最小轮询间隔 —— 订阅越多,单个 topic 刷新越慢。游标只在 `onBatch` 成功后
122
+ 提交,重新订阅需显式传回 `events.cursor`。工具 Hook 观察的是**已经发生的**服务端
123
+ 事实,不是执行前拦截器。
124
+
125
+ ## 测试
75
126
 
76
127
  ```ts
77
- import { PRESENTATION_CONFIRMATION_TIMEOUT_MS } from "@dp-bohrium/widget-sdk";
78
-
79
- const presentationAbort = new AbortController();
80
- const result = await widget.present("floating", {
81
- timeoutMs: PRESENTATION_CONFIRMATION_TIMEOUT_MS,
82
- signal: presentationAbort.signal,
83
- });
84
-
85
- if (!result.ok) {
86
- showPresentationDenial(result.reason, result.message);
87
- } else if ("surface" in result.data) {
88
- // Host 可能回报不同的实际表面,例如紧凑模式下从 floating 降级到 overlay
89
- // 或 workspace。
90
- showCurrentSurface(result.data.surface);
91
- }
92
-
93
- await widget.changePresentationSurface("overlay");
94
- await widget.focusPresentationBoundary("forward");
95
- await widget.closePresentation();
128
+ import { MockWidgetHost } from "@dp-bohrium/widget-sdk/testing";
96
129
  ```
97
130
 
98
- 当 Host 授予带 `overlay` 表面的 `ui.presentation` 时,普通 client 还会安装跨源
99
- Panel overlay 的键盘协作:未处理、受信、非 composing 的 Escape 会请求
100
- `closePresentation()`;Tab 之后焦点离开 iframe 会请求
101
- `focusPresentationBoundary("forward" | "backward")`;iframe 内焦点移动不会发消息。
102
- 有自定义焦点管理器的框架可直接调用类型化 helper。
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` 为准。
131
+ `MockWidgetHost` 负责 init/ready 时序、首帧 render 与 update 选择、resize 事件、
132
+ 能力 adapter 响应与终态 dispose;`capabilityResult` 给出确定性的默认允许/拒绝,
133
+ 同时提供 `handleCapability` 时后者优先。`host.capabilityRequests` 返回有序的防御性
134
+ 拷贝,断言不会改动 Mock 状态。
134
135
 
135
- 可用 `capabilityResult` 给出确定性的默认允许或拒绝;若同时提供
136
- `handleCapability`,后者仍是权威的高级处理器。`host.capabilityRequests` 返回有序的
137
- 防御性拷贝快照,测试可检查请求而不改动 Mock Host 状态。
136
+ 它使用与生产 Host 相同的公开 contracts,但**不等同于**生产 iframe、CSP、授权或资源
137
+ 隔离保证。
138
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 仍视为活跃的连接。
145
-
146
- ## 受授权的事件订阅与工具 Hook(本地候选)
147
-
148
- 新增 `subscribeEvents`、`onTool` 和 `invokeAction`。Manifest 声明与 Host 实际
149
- grant 必须同时包含 topic/action;旧 Host 不会自动获得这些能力,发布时需一起升级
150
- contracts 与消费者。订阅类型从包根与 `/runtime` 导出。
151
-
152
- ```ts
153
- const events = client.subscribeEvents({
154
- topic: "jobs.progress",
155
- onBatch(batch, { signal }) {
156
- if (signal.aborted) return;
157
- // 只应用本批真实事件;batch.reset 时替换旧状态。
158
- renderProgress(batch.events);
159
- },
160
- onError: showSubscriptionError,
161
- });
162
- const hooks = client.onTool({
163
- onToolCall: showStarted,
164
- onToolResult: showCompleted,
165
- onToolError: showFailed,
166
- onToolCancelled: showCancelled,
167
- }, { onError: showSubscriptionError });
168
- const result = await client.invokeAction({
169
- action: "tools.inspect",
170
- idempotencyKey: crypto.randomUUID(),
171
- arguments: { toolCallId },
172
- });
173
- const resumeCursor = events.cursor;
174
- events.unsubscribe();
175
- hooks.unsubscribe();
176
- ```
139
+ ## 限制
177
140
 
178
- Hook 观察已经发生的服务端工具事实,不是执行前拦截器;不允许通过 iframe 回调改写
179
- 参数、审批或控制 durable 执行。`tools.inspect` 是常见的只读动作
180
- provider 示例,返回工具身份和最新可读取状态;其他 action 由 Host/provider 显式实现并
181
- 授权。SDK 不自动重试动作,也不把回调完成解释为工具执行完成。
141
+ - SDK 不做授权决策,能力是否可用最终由 Host 判定。
142
+ - `invokeAction` 不自动重试,回调完成也不代表工具执行完成。
143
+ - `subscribeEvents` 的 `events.read` 是有界分页读取,不是 websocket;实时推送走
144
+ `onEvent`。当前版本没有单请求取消的 wire 消息:`unsubscribe` 会停止后续轮询并取消
145
+ 本地等待,已发出的服务端读取可能完成,但结果被忽略。
146
+ - Host 发来畸形 Bridge 信封或载荷时,transport 报结构化 `MESSAGE_INVALID` 并关闭
147
+ 连接,不会让 Widget 悬等。
148
+ - Schema 与类型校验以 `@dp-bohrium/widget-contracts` 为准。
182
149
 
183
- 所有订阅共享实例的 events 请求预算,并各自遵守 topic 最小间隔。游标仅在
184
- `onBatch` 成功后提交;消费者异常、权限撤销和不可恢复的历史错误会关闭订阅并调用
185
- `onError`。`unsubscribe` 和 Host dispose 释放订阅、排队请求和本地在途等待,忽略
186
- 迟到结果;异步回调需检查传入 signal 后再更新自己的状态。`closed` 表示订阅已关闭,
187
- 并不等待用户未完成的回调结束。重新订阅时显式传入已保存 cursor。
150
+ ## 许可证
188
151
 
189
- 每次 events.read 是有界、非阻塞读取;当前 V1 没有单请求取消 wire 消息,
190
- unsubscribe 会停止后续轮询并取消本地等待,已经发出的服务端读取可能完成但其结果被
191
- 忽略。Host 实例卸载另通过既有 lease/AbortSignal 释放在途宿主请求。
152
+ MIT。
@@ -1,4 +1,4 @@
1
- import { n as MemoryTransport, t as ProtocolEndpoint } from "../protocol-endpoint-ZmZWaN92.js";
1
+ import { n as MemoryTransport, t as ProtocolEndpoint } from "../protocol-endpoint-I78q3jVT.js";
2
2
  //#region src/runtime/mock-host.ts
3
3
  const widgetMessageTypes = /* @__PURE__ */ new Set([
4
4
  "ready",
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { i as createWidgetClient, o as PRESENTATION_CONFIRMATION_TIMEOUT_MS } from "./runtime-Bva0ricl.js";
1
+ import { i as createWidgetClient, o as PRESENTATION_CONFIRMATION_TIMEOUT_MS } from "./runtime-h-oTCwcs.js";
2
2
  export { PRESENTATION_CONFIRMATION_TIMEOUT_MS, createWidgetClient };
@@ -39,7 +39,7 @@ function isProtocolPayload(type, payload) {
39
39
  const content = property(payload, "content");
40
40
  return property(payload, "schemaVersion") === 1 && typeof property(payload, "requestId") === "string" && typeof property(payload, "instanceId") === "string" && typeof revision === "number" && Number.isSafeInteger(revision) && revision >= 1 && typeof property(payload, "slot") === "string" && typeof property(payload, "state") === "string" && isRecord(context) && isRecord(content);
41
41
  }
42
- case "event": return property(payload, "schemaVersion") === 1 && typeof property(payload, "id") === "string" && typeof property(payload, "occurredAt") === "string" && typeof property(payload, "sessionId") === "string" && typeof property(payload, "workflowId") === "string" && typeof property(payload, "topic") === "string" && typeof property(payload, "type") === "string" && isRecord(property(payload, "payload"));
42
+ case "event": return typeof property(payload, "type") === "string" && isRecord(property(payload, "payload"));
43
43
  case "capability-result": return typeof property(payload, "requestId") === "string" && isRecord(property(payload, "result"));
44
44
  case "error": return typeof property(payload, "code") === "string" && typeof property(payload, "phase") === "string" && typeof property(payload, "message") === "string" && typeof property(payload, "retryable") === "boolean" && typeof property(payload, "correlationId") === "string";
45
45
  case "dispose": return typeof property(payload, "reason") === "string" && isFiniteNonNegative(property(payload, "deadlineMs"));
@@ -1,4 +1,4 @@
1
- import type { CapabilityRequest, CapabilityResult, InitPayload, PresentationCapabilityResult, PublicWidgetEvent, RenderRequest, WidgetError } from "@dp-bohrium/widget-contracts";
1
+ import type { CapabilityRequest, CapabilityResult, InitPayload, PresentationCapabilityResult, RenderRequest, WidgetError, WidgetLiveEvent } from "@dp-bohrium/widget-contracts";
2
2
  import { type PresentationFocusDirection, type PresentationSurface, type WidgetCapabilityRequestOptions, type WidgetClientEvents, type WidgetClientState } from "./client.js";
3
3
  import { type SubscribeWidgetEventsOptions, type WidgetEventSubscription, type WidgetToolHooks } from "./events.js";
4
4
  import type { WidgetNetworkClient } from "./network.js";
@@ -26,7 +26,7 @@ export interface WidgetLiveEventContext {
26
26
  readonly signal: AbortSignal;
27
27
  }
28
28
  /** 由 Host 通过当前 MessageChannel 推送的实时 Workflow 事件处理器。 */
29
- export type WidgetLiveEventHandler = (event: PublicWidgetEvent, context: WidgetLiveEventContext) => void | Promise<void>;
29
+ export type WidgetLiveEventHandler = (event: WidgetLiveEvent, context: WidgetLiveEventContext) => void | Promise<void>;
30
30
  export interface CreateWidgetClientOptions {
31
31
  widgetSdkVersion: string;
32
32
  hostApiVersion?: 1;
@@ -87,12 +87,10 @@ export declare class WidgetRuntimeClient {
87
87
  changePresentationSurface(surface: PresentationSurface, options?: WidgetCapabilityRequestOptions): Promise<PresentationCapabilityResult>;
88
88
  focusPresentationBoundary(direction: PresentationFocusDirection, options?: WidgetCapabilityRequestOptions): Promise<PresentationCapabilityResult>;
89
89
  subscribeEvents(options: SubscribeWidgetEventsOptions): WidgetEventSubscription;
90
- /**
91
- * 订阅 Host 从当前 Workflow 流实时推送的事件。
92
- *
93
- * Topic 授权由 Host 在发送前按 Manifest 与 Grant 过滤;这里不发起 HTTP 轮询。
94
- */
90
+ /** 订阅 Host 从当前 Workflow 流实时推送的全部聚合事件。 */
95
91
  onEvent(handler: WidgetLiveEventHandler): () => void;
92
+ /** 订阅 Host 从当前 Workflow 流实时推送的指定聚合事件。 */
93
+ onEvent(eventName: string, handler: WidgetLiveEventHandler): () => void;
96
94
  onTool(hooks: WidgetToolHooks, options: Pick<SubscribeWidgetEventsOptions, "cursor" | "onError">): WidgetEventSubscription;
97
95
  invokeAction(input: Extract<CapabilityRequest, {
98
96
  operation: "actions.invoke";
@@ -1,4 +1,4 @@
1
- import type { CapabilityRequest, CapabilityResult, GrantedCapability, InitPayload, PresentationCapabilityRequest, PresentationCapabilityResult, PublicWidgetEvent, RenderRequest, WidgetError } from "@dp-bohrium/widget-contracts";
1
+ import type { CapabilityRequest, CapabilityResult, GrantedCapability, InitPayload, PresentationCapabilityRequest, PresentationCapabilityResult, RenderRequest, WidgetError, WidgetLiveEvent } from "@dp-bohrium/widget-contracts";
2
2
  import { type WidgetNetworkClient } from "./network.js";
3
3
  import type { WidgetTransport } from "./transport.js";
4
4
  export type WidgetClientState = "created" | "waiting-ready" | "ready" | "disposed";
@@ -16,8 +16,8 @@ export interface WidgetClientEvents {
16
16
  onInit?: (payload: InitPayload) => void | PromiseLike<void>;
17
17
  onRender?: (request: RenderRequest, update: boolean) => void;
18
18
  onUpdate?: (request: RenderRequest) => void;
19
- /** 接收 Host 从当前 Workflow 流主动推送的公开事件。 */
20
- onEvent?: (event: PublicWidgetEvent) => void;
19
+ /** 接收 Host 从当前 Runtime 主动推送的聚合事件。 */
20
+ onEvent?: (event: WidgetLiveEvent) => void;
21
21
  onError?: (error: WidgetError) => void;
22
22
  onDispose?: (reason: string, deadlineMs?: number) => void;
23
23
  }
@@ -1,3 +1,3 @@
1
- import { a as isWidgetHostConnectMessage, i as createWidgetClient, n as WIDGET_HOST_CONNECT, o as PRESENTATION_CONFIRMATION_TIMEOUT_MS, r as WidgetRuntimeClient, s as WidgetClient, t as WIDGET_BOOTSTRAP_READY } from "../runtime-Bva0ricl.js";
2
- import { i as isWidgetProtocolMessage, r as MessagePortTransport } from "../protocol-endpoint-ZmZWaN92.js";
1
+ import { a as isWidgetHostConnectMessage, i as createWidgetClient, n as WIDGET_HOST_CONNECT, o as PRESENTATION_CONFIRMATION_TIMEOUT_MS, r as WidgetRuntimeClient, s as WidgetClient, t as WIDGET_BOOTSTRAP_READY } from "../runtime-h-oTCwcs.js";
2
+ import { i as isWidgetProtocolMessage, r as MessagePortTransport } from "../protocol-endpoint-I78q3jVT.js";
3
3
  export { MessagePortTransport, PRESENTATION_CONFIRMATION_TIMEOUT_MS, WIDGET_BOOTSTRAP_READY, WIDGET_HOST_CONNECT, WidgetClient, WidgetRuntimeClient, createWidgetClient, isWidgetHostConnectMessage, isWidgetProtocolMessage };
@@ -1,4 +1,4 @@
1
- import { r as MessagePortTransport, t as ProtocolEndpoint } from "./protocol-endpoint-ZmZWaN92.js";
1
+ import { r as MessagePortTransport, t as ProtocolEndpoint } from "./protocol-endpoint-I78q3jVT.js";
2
2
  //#region src/runtime/network.ts
3
3
  const failureReasons = /* @__PURE__ */ new Set([
4
4
  "unsupported",
@@ -1023,16 +1023,18 @@ var WidgetRuntimeClient = class {
1023
1023
  if (this.disposed || this.currentState === "disposed") subscription.unsubscribe();
1024
1024
  return subscription;
1025
1025
  }
1026
- /**
1027
- * 订阅 Host 从当前 Workflow 流实时推送的事件。
1028
- *
1029
- * Topic 授权由 Host 在发送前按 Manifest 与 Grant 过滤;这里不发起 HTTP 轮询。
1030
- */
1031
- onEvent(handler) {
1026
+ onEvent(eventNameOrHandler, maybeHandler) {
1032
1027
  if (this.disposed) throw new Error("client is disposed");
1033
- this.liveEventHandlers.add(handler);
1028
+ const handler = typeof eventNameOrHandler === "string" ? maybeHandler : eventNameOrHandler;
1029
+ if (!handler) throw new TypeError("event handler is required");
1030
+ const eventName = typeof eventNameOrHandler === "string" ? eventNameOrHandler : void 0;
1031
+ const subscribedHandler = eventName === void 0 ? handler : (event, context) => {
1032
+ if (event.type !== eventName) return;
1033
+ return handler(event, context);
1034
+ };
1035
+ this.liveEventHandlers.add(subscribedHandler);
1034
1036
  return () => {
1035
- this.liveEventHandlers.delete(handler);
1037
+ this.liveEventHandlers.delete(subscribedHandler);
1036
1038
  };
1037
1039
  }
1038
1040
  onTool(hooks, options) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dp-bohrium/widget-sdk",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "description": "Bohrium Widget 开发者 SDK:在 Widget Bundle 内与 Host 建立 Bridge,并暴露生命周期与能力协议。",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -45,7 +45,7 @@
45
45
  "access": "public"
46
46
  },
47
47
  "dependencies": {
48
- "@dp-bohrium/widget-contracts": "0.0.6"
48
+ "@dp-bohrium/widget-contracts": "0.0.7"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@biomejs/biome": "^2.2.0",