@jhh96/light-app-bridge 1.2.0 → 1.3.0

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/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export { default } from './lightAppBridge';
2
2
  export { createBridge } from './lightAppBridge';
3
- export type { BridgeRole, BindMode, EnvelopeType, Envelope, BridgeOptions, SendOptions, MessageHandler } from './lightAppBridge';
3
+ export type { BridgeRole, BindMode, ReportMode, EnvelopeType, Envelope, BridgeOptions, SendOptions, MessageHandler } from './lightAppBridge';
@@ -30,6 +30,17 @@ export type BridgeRole = 'plugin' | 'lightapp';
30
30
  * 向新窗口探测握手(成功即切换绑定;失败——如未集成 SDK——保持旧绑定)。
31
31
  */
32
32
  export type BindMode = 'fixed' | 'dynamic';
33
+ /**
34
+ * 指令执行结果的上报模式(轻应用角色语义声明,默认 'plugin'):
35
+ * - plugin 默认。轻应用不在本窗口回传 ai-controller,执行结果随 reply 返回
36
+ * 插件窗口,由插件统一上报。reply 无需额外字段。
37
+ * - self 轻应用业务自行 POST ai-controller/callback(如需 AI 闭环),
38
+ * 并在 onMessage 的 reply 上带 result_reported: true,
39
+ * 插件据此跳过补报,避免双重上报。
40
+ * 纯语义声明:SDK 不执行上报,读取方是插件侧业务代码(经 reply 字段判定),
41
+ * 两 SDK 间零依赖。
42
+ */
43
+ export type ReportMode = 'plugin' | 'self';
33
44
  /** 信封类型 */
34
45
  export type EnvelopeType = 'hello' | 'ack' | 'req' | 'res' | 'ping' | 'pong';
35
46
  /** 消息信封:所有跨窗口通信的统一包装 */
@@ -51,6 +62,13 @@ export interface BridgeOptions {
51
62
  * dynamic:轮询 getContentContext 跟随当前激活的轻应用窗口切换绑定。
52
63
  */
53
64
  bindMode?: BindMode;
65
+ /**
66
+ * 结果上报模式(轻应用角色语义声明),默认 'plugin':
67
+ * 'plugin'=结果交插件统一上报(reply 无需额外字段);
68
+ * 'self'=业务自行上报并在 reply 带 result_reported: true。
69
+ * SDK 不执行上报,仅存为实例属性 reportMode 供业务读取。
70
+ */
71
+ reportMode?: ReportMode;
54
72
  /** dynamic 模式轮询 getContentContext 的间隔(ms),默认 2000 */
55
73
  dynamicPollInterval?: number;
56
74
  /** dynamic 模式迁移探测窗口:向新窗口发 hello 等 ack 的时长(ms),默认 3000 */
@@ -94,6 +112,7 @@ export default class LightAppBridge {
94
112
  timeout: number;
95
113
  handshakeTimeout: number;
96
114
  bindMode: BindMode;
115
+ reportMode: ReportMode;
97
116
  dynamicPollInterval: number;
98
117
  migrateProbeTimeout: number;
99
118
  pingInterval: number;
@@ -139,6 +158,28 @@ export default class LightAppBridge {
139
158
  constructor(role?: BridgeRole, options?: BridgeOptions);
140
159
  /** debug 日志(options.debug 开启时打印,前缀带角色便于双端对照) */
141
160
  private _log;
161
+ /**
162
+ * debug 模式下在 window 挂载控制台测试方法(挂在单一入口 __lightAppBridge 下,
163
+ * destroy 时注销):
164
+ *
165
+ * __lightAppBridge.send(data, timeout?) —— 以本实例身份向对端发一条请求,返回 Promise。
166
+ * 等价于业务代码里的 bridge.send(...)。
167
+ * await __lightAppBridge.send({ action: 'ping' })
168
+ * await __lightAppBridge.send({ action: 'scroll.to', payload: {...} }, 5000)
169
+ *
170
+ * __lightAppBridge.inject(type, data?, fromId?, id?) —— 模拟对端来一条消息,直接喂给
171
+ * 本实例的消息分发入口(绕过原生投递层),无需真实对端窗口即可测试收发逻辑。
172
+ * type 取信封类型:'hello' | 'ack' | 'req' | 'res' | 'ping'
173
+ * __lightAppBridge.inject('ping') // 看本端自动回 pong
174
+ * __lightAppBridge.inject('req', { action: 'test' }) // 触发本端 onMessage handler
175
+ * __lightAppBridge.inject('hello', null, 42) // 模拟 webContentsId=42 的对端握手
176
+ * __lightAppBridge.inject('res', {ok:1}, 77, reqId) // 回 res:第 4 参传原请求 id 配对唤醒
177
+ *
178
+ * 多实例同时开启 debug 时后注册者覆盖前者(控制台操作的是最后创建的实例)。
179
+ * 不挂实例本身(避免控制台误触内部状态)。
180
+ */
181
+ private _registerDebugHelpers;
182
+ private _debugCleanup;
142
183
  /** 校验依赖是否就绪,缺失抛出明确异常 */
143
184
  private _checkDeps;
144
185
  /** 绑定消息监听:优先 waltz;无 waltz 时定义/包装 window.handleMessageFromNative */
@@ -202,6 +202,7 @@ export default class LightAppBridge {
202
202
  this._probeOk = false; // 兜底探测是否收到 ack
203
203
  this._probeTimers = []; // 防 destroy 后悬挂
204
204
  this._disconnectCbs = [];
205
+ this._debugCleanup = null;
205
206
  let r = role === 'plugin' || role === 'lightapp' ? role : 'lightapp';
206
207
  if (role !== 'plugin' && role !== 'lightapp') {
207
208
  const wl = window.worklink;
@@ -211,6 +212,7 @@ export default class LightAppBridge {
211
212
  this.timeout = options.timeout != null ? options.timeout : DEFAULT_TIMEOUT;
212
213
  this.handshakeTimeout = options.handshakeTimeout != null ? options.handshakeTimeout : DEFAULT_HANDSHAKE_TIMEOUT;
213
214
  this.bindMode = options.bindMode === 'dynamic' ? 'dynamic' : DEFAULT_BIND_MODE;
215
+ this.reportMode = options.reportMode === 'self' ? 'self' : 'plugin';
214
216
  this.dynamicPollInterval = options.dynamicPollInterval != null ? options.dynamicPollInterval : DEFAULT_DYNAMIC_POLL_INTERVAL;
215
217
  this.migrateProbeTimeout = options.migrateProbeTimeout != null ? options.migrateProbeTimeout : DEFAULT_MIGRATE_PROBE_TIMEOUT;
216
218
  this.pingInterval = options.pingInterval != null ? options.pingInterval : DEFAULT_PING_INTERVAL;
@@ -232,6 +234,7 @@ export default class LightAppBridge {
232
234
  });
233
235
  this._checkDeps(); // 依赖校验,缺失直接抛异常
234
236
  this._startListener(); // 绑定消息监听(waltz 或定义 handleMessageFromNative)
237
+ this._registerDebugHelpers(); // debug 模式:注册控制台测试方法
235
238
  this.connect(); // 构造即自动发起握手(内部会等监听就绪)
236
239
  }
237
240
  /** debug 日志(options.debug 开启时打印,前缀带角色便于双端对照) */
@@ -240,6 +243,58 @@ export default class LightAppBridge {
240
243
  return;
241
244
  console.log(`[LightAppBridge:${this.role}]`, ...args);
242
245
  }
246
+ // —— debug 控制台测试方法(options.debug 开启时挂 window)—— //
247
+ /**
248
+ * debug 模式下在 window 挂载控制台测试方法(挂在单一入口 __lightAppBridge 下,
249
+ * destroy 时注销):
250
+ *
251
+ * __lightAppBridge.send(data, timeout?) —— 以本实例身份向对端发一条请求,返回 Promise。
252
+ * 等价于业务代码里的 bridge.send(...)。
253
+ * await __lightAppBridge.send({ action: 'ping' })
254
+ * await __lightAppBridge.send({ action: 'scroll.to', payload: {...} }, 5000)
255
+ *
256
+ * __lightAppBridge.inject(type, data?, fromId?, id?) —— 模拟对端来一条消息,直接喂给
257
+ * 本实例的消息分发入口(绕过原生投递层),无需真实对端窗口即可测试收发逻辑。
258
+ * type 取信封类型:'hello' | 'ack' | 'req' | 'res' | 'ping'
259
+ * __lightAppBridge.inject('ping') // 看本端自动回 pong
260
+ * __lightAppBridge.inject('req', { action: 'test' }) // 触发本端 onMessage handler
261
+ * __lightAppBridge.inject('hello', null, 42) // 模拟 webContentsId=42 的对端握手
262
+ * __lightAppBridge.inject('res', {ok:1}, 77, reqId) // 回 res:第 4 参传原请求 id 配对唤醒
263
+ *
264
+ * 多实例同时开启 debug 时后注册者覆盖前者(控制台操作的是最后创建的实例)。
265
+ * 不挂实例本身(避免控制台误触内部状态)。
266
+ */
267
+ _registerDebugHelpers() {
268
+ if (!this._debug)
269
+ return;
270
+ const w = window;
271
+ const sendFn = (data, timeout) => {
272
+ // eslint-disable-next-line no-console
273
+ console.log(`[LightAppBridge:${this.role}] send→`, data);
274
+ return this.send(data, timeout != null ? { timeout } : undefined);
275
+ };
276
+ const injectFn = (type, data, fromId, id) => {
277
+ const envelope = this._envelope(type, data != null ? data : {}, id || genId() // res 场景必须传原请求 id 才能配对唤醒(未传则生成新 id,作为陌生 res 被忽略)
278
+ );
279
+ // eslint-disable-next-line no-console
280
+ console.log(`[LightAppBridge:${this.role}] inject←`, envelope);
281
+ this._onMessage({ envelope, fromWebContentsId: fromId != null ? fromId : 0 });
282
+ };
283
+ const facade = { send: sendFn, inject: injectFn };
284
+ const prev = w.__lightAppBridge; // 多实例 debug:保留被覆盖者的清理引用链
285
+ w.__lightAppBridge = facade;
286
+ // eslint-disable-next-line no-console
287
+ console.info(`[LightAppBridge:${this.role}] debug 方法已挂载: ` +
288
+ 'await __lightAppBridge.send(data, timeout?) 发请求 / ' +
289
+ '__lightAppBridge.inject(type, data?, fromId?, id?) 模拟来消息');
290
+ this._debugCleanup = () => {
291
+ // 仅当仍是自己挂的 facade 才清理,避免误删后建实例的挂载
292
+ if (w.__lightAppBridge === facade)
293
+ delete w.__lightAppBridge;
294
+ else
295
+ w.__lightAppBridge = prev;
296
+ };
297
+ }
243
298
  /** 校验依赖是否就绪,缺失抛出明确异常 */
244
299
  _checkDeps() {
245
300
  const w = window;
@@ -821,6 +876,14 @@ export default class LightAppBridge {
821
876
  catch { /* ignore */ }
822
877
  this._unlisten = null;
823
878
  }
879
+ // 注销 debug 控制台测试方法
880
+ if (this._debugCleanup) {
881
+ try {
882
+ this._debugCleanup();
883
+ }
884
+ catch { /* ignore */ }
885
+ this._debugCleanup = null;
886
+ }
824
887
  this._clearHelloTimer();
825
888
  this._stopDynamicPoll();
826
889
  this._stopPing();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jhh96/light-app-bridge",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "type": "module",
5
5
  "description": "招商随行(WorkLink)插件窗口(plugin)与轻应用窗口(lightapp)之间的双向通信 SDK",
6
6
  "main": "./dist/index.js",