@heybox/hb-sdk 0.7.4-alpha.1 → 0.7.4-alpha.4

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/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.7.4-alpha.4
4
+
5
+ ### SDK
6
+
7
+ - 同步 `auth.login()` 授权弹窗展示说明与 Agent Skill 引用。
8
+
9
+ ### Runtime
10
+
11
+ - 修复首次授权弹窗仅显示占位信息的问题;展示小程序名称和图标,并在申请 `profile` 时预览当前账号昵称和头像,资料读取失败继续使用中性占位。
12
+ - 展示资料读取增加独立超时与取消边界,避免可选请求阻塞授权队列;账号切换、撤销或 Runtime 终止会立即取消当前确认界面。
13
+ - Mobile/PC Host 启动配置复用已可信解析的小程序资料,回退请求携带 canonical version,避免预览或开发实例展示线上版本资料。
14
+ - 将 hb-sdk release family 单测接入 `build_changed_packages` MR 门禁。
15
+
16
+ ## 0.7.4-alpha.3
17
+
18
+ ### Runtime
19
+
20
+ - 兼容缺少 User Activation API 的旧版 iOS WKWebView;支持环境继续使用标准用户激活状态,旧版环境回退到父文档捕获的近期 iframe 输入与焦点组合判定。旧环境的手势门禁强度低于标准环境,环境读取失败一律拒绝。
21
+
3
22
  ## 0.7.4-alpha.1
4
23
 
5
24
  ### Breaking / Host Runtime
@@ -5,8 +5,8 @@ var fs = require('node:fs/promises');
5
5
  var path = require('node:path');
6
6
  var runtimePermissionEnv = require('./runtime-permission-env-D-8_jPG3.cjs');
7
7
  var runtimeGate = require('./runtime-gate-CtV7rWyX.cjs');
8
- var index = require('./index-BCd2vU5D.cjs');
9
- var projectVite = require('./project-vite-BtIYxLkt.cjs');
8
+ var index = require('./index-CyEqCbeu.cjs');
9
+ var projectVite = require('./project-vite-BUY9DgYo.cjs');
10
10
  require('node:async_hooks');
11
11
  require('node:module');
12
12
  require('path');
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var session = require('./session-9ZWPGpqB.cjs');
3
+ var session = require('./session-BUjFX2U2.cjs');
4
4
  var runtimePermissionEnv = require('./runtime-permission-env-D-8_jPG3.cjs');
5
5
  var fs$1 = require('node:fs');
6
6
  var fs = require('node:fs/promises');
@@ -5,7 +5,7 @@ var fs = require('node:fs/promises');
5
5
  var path = require('node:path');
6
6
  var require$$0 = require('fs');
7
7
  var require$$1 = require('path');
8
- var index = require('./index-BCd2vU5D.cjs');
8
+ var index = require('./index-CyEqCbeu.cjs');
9
9
  require('node:module');
10
10
  require('os');
11
11
  require('readline');
@@ -6,15 +6,15 @@ var path = require('node:path');
6
6
  var net = require('node:net');
7
7
  var promises = require('node:dns/promises');
8
8
  var node_http = require('node:http');
9
- var context = require('./context-DATgeHkI.cjs');
9
+ var context = require('./context-DTr3hRTv.cjs');
10
10
  var node_crypto = require('node:crypto');
11
11
  var undici = require('undici');
12
12
  var browser = require('./browser-RAy8e8cV.cjs');
13
- var index = require('./index-BCd2vU5D.cjs');
14
- var projectVite = require('./project-vite-BtIYxLkt.cjs');
13
+ var index = require('./index-CyEqCbeu.cjs');
14
+ var projectVite = require('./project-vite-BUY9DgYo.cjs');
15
15
  var fs$1 = require('node:fs/promises');
16
16
  var runtimePermissionEnv = require('./runtime-permission-env-D-8_jPG3.cjs');
17
- require('./session-9ZWPGpqB.cjs');
17
+ require('./session-BUjFX2U2.cjs');
18
18
  require('fs');
19
19
  require('constants');
20
20
  require('stream');
@@ -2005,7 +2005,7 @@ function createHeyboxProtocol(payload) {
2005
2005
  /** 构建时替换为当前发布包的实际版本。 */
2006
2006
  const HB_SDK_VERSION = typeof undefined === 'string'
2007
2007
  ? undefined
2008
- : '0.7.4-alpha.1';
2008
+ : '0.7.4-alpha.4';
2009
2009
 
2010
2010
  class DevPermissionOverrideStoreError extends Error {
2011
2011
  code;
@@ -4,7 +4,7 @@ var fs$1 = require('node:fs');
4
4
  var fs = require('node:fs/promises');
5
5
  var os = require('node:os');
6
6
  var path = require('node:path');
7
- var index = require('./index-BCd2vU5D.cjs');
7
+ var index = require('./index-CyEqCbeu.cjs');
8
8
  require('node:module');
9
9
  require('path');
10
10
  require('os');
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index$2 = require('./index-BCd2vU5D.cjs');
3
+ var index$2 = require('./index-CyEqCbeu.cjs');
4
4
  var require$$0$2 = require('fs');
5
5
  var require$$2$1 = require('crypto');
6
6
  var require$$1$2 = require('path');
@@ -234,19 +234,19 @@ function requireArgument () {
234
234
 
235
235
  var command = {};
236
236
 
237
- const require$5 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-BCd2vU5D.cjs', document.baseURI).href)));
237
+ const require$5 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-CyEqCbeu.cjs', document.baseURI).href)));
238
238
  function __require$4() { return require$5("node:events"); }
239
239
 
240
- const require$4 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-BCd2vU5D.cjs', document.baseURI).href)));
240
+ const require$4 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-CyEqCbeu.cjs', document.baseURI).href)));
241
241
  function __require$3() { return require$4("node:child_process"); }
242
242
 
243
- const require$3 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-BCd2vU5D.cjs', document.baseURI).href)));
243
+ const require$3 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-CyEqCbeu.cjs', document.baseURI).href)));
244
244
  function __require$2() { return require$3("node:path"); }
245
245
 
246
- const require$2 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-BCd2vU5D.cjs', document.baseURI).href)));
246
+ const require$2 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-CyEqCbeu.cjs', document.baseURI).href)));
247
247
  function __require$1() { return require$2("node:fs"); }
248
248
 
249
- const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-BCd2vU5D.cjs', document.baseURI).href)));
249
+ const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-CyEqCbeu.cjs', document.baseURI).href)));
250
250
  function __require() { return require$1("node:process"); }
251
251
 
252
252
  var help = {};
@@ -13347,7 +13347,7 @@ function getPathname(pathWithQuery) {
13347
13347
  }
13348
13348
 
13349
13349
  const CLI_VERSION_PLACEHOLDER = ['__HB', 'SDK', 'CLI', 'VERSION__'].join('_');
13350
- const BUILT_CLI_VERSION = '0.7.4-alpha.1';
13350
+ const BUILT_CLI_VERSION = '0.7.4-alpha.4';
13351
13351
  const PACKAGE_JSON_CANDIDATES = [
13352
13352
  path.resolve(__dirname, '..', '..', 'package.json'),
13353
13353
  path.resolve(__dirname, '..', 'package.json'),
@@ -13684,35 +13684,35 @@ function createCommandLoggerResolver(options) {
13684
13684
  };
13685
13685
  }
13686
13686
  const defaultClearLoginStatus = async (...args) => {
13687
- const { clearLoginStatus } = await Promise.resolve().then(function () { return require('./login-BLTILOf-.cjs'); });
13687
+ const { clearLoginStatus } = await Promise.resolve().then(function () { return require('./login-CuAGltGs.cjs'); });
13688
13688
  return clearLoginStatus(...args);
13689
13689
  };
13690
13690
  const defaultLoginToHeybox = async (...args) => {
13691
- const { loginToHeybox } = await Promise.resolve().then(function () { return require('./login-BLTILOf-.cjs'); });
13691
+ const { loginToHeybox } = await Promise.resolve().then(function () { return require('./login-CuAGltGs.cjs'); });
13692
13692
  return loginToHeybox(...args);
13693
13693
  };
13694
13694
  const defaultPrintLoginStatus = async (...args) => {
13695
- const { printLoginStatus } = await Promise.resolve().then(function () { return require('./login-BLTILOf-.cjs'); });
13695
+ const { printLoginStatus } = await Promise.resolve().then(function () { return require('./login-CuAGltGs.cjs'); });
13696
13696
  return printLoginStatus(...args);
13697
13697
  };
13698
13698
  const defaultRunBuildCommand = async (...args) => {
13699
- const { runBuildCommand } = await Promise.resolve().then(function () { return require('./build-Cej8ObyY.cjs'); });
13699
+ const { runBuildCommand } = await Promise.resolve().then(function () { return require('./build-BqGFRLe-.cjs'); });
13700
13700
  return runBuildCommand(...args);
13701
13701
  };
13702
13702
  const defaultRunCreateCommand = async (...args) => {
13703
- const { runCreateCommand } = await Promise.resolve().then(function () { return require('./create-LXHV_lW5.cjs'); });
13703
+ const { runCreateCommand } = await Promise.resolve().then(function () { return require('./create-OkiiiH4I.cjs'); });
13704
13704
  return runCreateCommand(...args);
13705
13705
  };
13706
13706
  const defaultRunDevCommand = async (...args) => {
13707
- const { runDevCommand } = await Promise.resolve().then(function () { return require('./dev-CDuVyGm9.cjs'); });
13707
+ const { runDevCommand } = await Promise.resolve().then(function () { return require('./dev-j7W9R7ew.cjs'); });
13708
13708
  return runDevCommand(...args);
13709
13709
  };
13710
13710
  const defaultRunDoctorCommand = async (...args) => {
13711
- const { runDoctorCommand } = await Promise.resolve().then(function () { return require('./doctor-BqmQrPaV.cjs'); });
13711
+ const { runDoctorCommand } = await Promise.resolve().then(function () { return require('./doctor-BO0vkDny.cjs'); });
13712
13712
  return runDoctorCommand(...args);
13713
13713
  };
13714
13714
  const defaultRunRemoteCommand = async (...args) => {
13715
- const { runRemoteCommand } = await Promise.resolve().then(function () { return require('./remote-Bp9SK8C3.cjs'); });
13715
+ const { runRemoteCommand } = await Promise.resolve().then(function () { return require('./remote-tPMcxgpi.cjs'); });
13716
13716
  return runRemoteCommand(...args);
13717
13717
  };
13718
13718
  function resolveStandaloneLogger(options, verbose) {
@@ -3,9 +3,9 @@
3
3
  var promises = require('node:readline/promises');
4
4
  var node_crypto = require('node:crypto');
5
5
  var node_http = require('node:http');
6
- var session = require('./session-9ZWPGpqB.cjs');
6
+ var session = require('./session-BUjFX2U2.cjs');
7
7
  var browser = require('./browser-RAy8e8cV.cjs');
8
- var index = require('./index-BCd2vU5D.cjs');
8
+ var index = require('./index-CyEqCbeu.cjs');
9
9
  require('node:path');
10
10
  require('fs');
11
11
  require('constants');
@@ -5,7 +5,7 @@ var fs$1 = require('node:fs/promises');
5
5
  var node_module = require('node:module');
6
6
  var path = require('node:path');
7
7
  var node_url = require('node:url');
8
- var index = require('./index-BCd2vU5D.cjs');
8
+ var index = require('./index-CyEqCbeu.cjs');
9
9
 
10
10
  function findProjectRoot(startDir) {
11
11
  let current = path.resolve(startDir);
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  var promises = require('node:readline/promises');
4
- var index = require('./index-BCd2vU5D.cjs');
5
- var session = require('./session-9ZWPGpqB.cjs');
4
+ var index = require('./index-CyEqCbeu.cjs');
5
+ var session = require('./session-BUjFX2U2.cjs');
6
6
  var childProcess = require('node:child_process');
7
7
  var fs = require('node:fs');
8
8
  var fs$1 = require('node:fs/promises');
@@ -10,7 +10,7 @@ var path = require('node:path');
10
10
  var runtimePermissionEnv = require('./runtime-permission-env-D-8_jPG3.cjs');
11
11
  var runtimeGate = require('./runtime-gate-CtV7rWyX.cjs');
12
12
  var node_crypto = require('node:crypto');
13
- var context = require('./context-DATgeHkI.cjs');
13
+ var context = require('./context-DTr3hRTv.cjs');
14
14
  require('node:module');
15
15
  require('path');
16
16
  require('os');
@@ -271,7 +271,7 @@ function createDefaultCosClient(uploadToken, COS) {
271
271
  };
272
272
  }
273
273
  async function loadCosConstructor() {
274
- const cosModule = await Promise.resolve().then(function () { return require('./index-Ck7X1LRP.cjs'); }).then(function (n) { return n.index; });
274
+ const cosModule = await Promise.resolve().then(function () { return require('./index-CZuvk1Rg.cjs'); }).then(function (n) { return n.index; });
275
275
  return cosModule.default;
276
276
  }
277
277
  function formatSize(bytes) {
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-BCd2vU5D.cjs');
3
+ var index = require('./index-CyEqCbeu.cjs');
4
4
  var node_crypto = require('node:crypto');
5
5
  var path = require('node:path');
6
6
  var require$$0$2 = require('fs');
package/dist/cli.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./cli-chunks/index-BCd2vU5D.cjs');
3
+ var index = require('./cli-chunks/index-CyEqCbeu.cjs');
4
4
  require('node:module');
5
5
  require('node:fs');
6
6
  require('node:fs/promises');
@@ -216,11 +216,18 @@ function readBrowserEnvironment() {
216
216
  return { activeElement: null };
217
217
  }
218
218
  }
219
- /** 按浏览器消息、用户激活和目标 iframe 焦点生成请求级可信手势快照。 */
220
- function computeTrustedIframeUserGesture(event, iframe, environment = readBrowserEnvironment()) {
221
- return (event.isTrusted === true
222
- && environment.userActivation?.isActive === true
223
- && environment.activeElement === iframe);
219
+ const USER_GESTURE_TTL_MS = 1000;
220
+ /** 优先使用 User Activation;旧版 WebView 使用带时效的 iframe 焦点回退。 */
221
+ function computeTrustedIframeUserGesture(iframe, environment = readBrowserEnvironment()) {
222
+ if (environment.userActivation) {
223
+ return environment.userActivation.isActive === true;
224
+ }
225
+ const lastUserInteractionAt = environment.lastUserInteractionAt;
226
+ const now = environment.now ?? Date.now();
227
+ return (environment.activeElement === iframe
228
+ && lastUserInteractionAt !== undefined
229
+ && now >= lastUserInteractionAt
230
+ && now - lastUserInteractionAt <= USER_GESTURE_TTL_MS);
224
231
  }
225
232
 
226
233
  const RUNTIME_GATE_PROBE_METHOD = 'runtime.gate.probe';
@@ -238,6 +245,7 @@ class MiniProgramBridgeServer {
238
245
  this.onDuplicateHandshake = options.onDuplicateHandshake;
239
246
  this.onInternalEvent = options.onInternalEvent;
240
247
  this.handleMessage = this.onMessage.bind(this);
248
+ this.handleUserInteraction = this.onUserInteraction.bind(this);
241
249
  this.dispatcher = options.dispatcher;
242
250
  this.targetOrigin = options.targetOrigin || '*';
243
251
  }
@@ -248,6 +256,9 @@ class MiniProgramBridgeServer {
248
256
  }
249
257
  this.started = true;
250
258
  window.addEventListener('message', this.handleMessage);
259
+ for (const eventName of ['pointerdown', 'touchend', 'mousedown', 'keydown']) {
260
+ window.addEventListener(eventName, this.handleUserInteraction, true);
261
+ }
251
262
  }
252
263
  /** 设置发送给 iframe 的 targetOrigin。 */
253
264
  setTargetOrigin(targetOrigin) {
@@ -263,6 +274,10 @@ class MiniProgramBridgeServer {
263
274
  timestamp: Date.now(),
264
275
  });
265
276
  window.removeEventListener('message', this.handleMessage);
277
+ for (const eventName of ['pointerdown', 'touchend', 'mousedown', 'keydown']) {
278
+ window.removeEventListener(eventName, this.handleUserInteraction, true);
279
+ }
280
+ this.lastUserInteractionAt = undefined;
266
281
  }
267
282
  /** 向 iframe 内小程序派发生命周期或业务事件。 */
268
283
  postEvent(eventName, payload) {
@@ -297,13 +312,31 @@ class MiniProgramBridgeServer {
297
312
  return;
298
313
  }
299
314
  if (message.type === 'request') {
300
- this.handleRequest(message, computeTrustedIframeUserGesture(event, this.iframe));
315
+ let trustedUserGesture = false;
316
+ try {
317
+ trustedUserGesture = computeTrustedIframeUserGesture(this.iframe, {
318
+ activeElement: document.activeElement,
319
+ userActivation: navigator.userActivation,
320
+ lastUserInteractionAt: this.lastUserInteractionAt,
321
+ now: Date.now(),
322
+ });
323
+ }
324
+ catch {
325
+ trustedUserGesture = false;
326
+ }
327
+ this.handleRequest(message, trustedUserGesture);
301
328
  return;
302
329
  }
303
330
  if (message.type === 'event' && this.handshaken) {
304
331
  this.onInternalEvent?.(message);
305
332
  }
306
333
  }
334
+ onUserInteraction(event) {
335
+ const path = typeof event.composedPath === 'function' ? event.composedPath() : [];
336
+ if (event.target === this.iframe || path.includes(this.iframe)) {
337
+ this.lastUserInteractionAt = Date.now();
338
+ }
339
+ }
307
340
  isTrustedMiniProgramMessage(event) {
308
341
  return (event.source === this.iframe.contentWindow &&
309
342
  isMiniProgramBridgeMessage(event.data) &&
@@ -624,6 +657,63 @@ function parseAPIResponse(response, fallbackMessage) {
624
657
  return data;
625
658
  }
626
659
 
660
+ /**
661
+ * @packageDocumentation
662
+ * 定义 AccountUserBaseInfo 接口的 Runtime endpoint 契约。
663
+ */
664
+ /**
665
+ * AccountUserBaseInfo 原始信封 endpoint。
666
+ *
667
+ * @remarks
668
+ * 供需要区分 `login`、`relogin` 等认证状态的领域服务使用;调用输入仍为 `void`,
669
+ * wire path 只由本 API contract owner 维护。
670
+ */
671
+ const accountUserBaseInfoEnvelopeEndpoint = {
672
+ auth: 'optional',
673
+ channel: 'api',
674
+ id: 'heybox.account.user_base_info.envelope.get',
675
+ method: 'GET',
676
+ path: '/account/get_user_base_info',
677
+ };
678
+
679
+ /**
680
+ * @packageDocumentation
681
+ * 定义 UserMiniprogramPublicDetail 接口的 Runtime endpoint 契约。
682
+ */
683
+ /** 用户侧工坊小程序详情 endpoint。 */
684
+ const userMiniprogramPublicDetailEndpoint = {
685
+ auth: 'optional',
686
+ channel: 'api',
687
+ failurePresentation: 'none',
688
+ id: 'heybox.user_miniprogram.public.detail.get',
689
+ method: 'GET',
690
+ path: '/user_miniprogram/public/detail',
691
+ /**
692
+ * 把业务输入映射为接口 query。
693
+ *
694
+ * @param input - 已由调用方提供的接口输入。
695
+ */
696
+ query(input) {
697
+ return {
698
+ mini_program_id: input.mini_program_id,
699
+ ...(input.miniprogram_version ? { miniprogram_version: input.miniprogram_version } : {}),
700
+ ...(input.preview_token ? { preview_token: input.preview_token } : {}),
701
+ ...(input.local_dev_launch_token ? { local_dev_launch_token: input.local_dev_launch_token } : {}),
702
+ ...(input.entry ? { entry: input.entry } : {}),
703
+ ...(input.h_src_parent ? { h_src_parent: input.h_src_parent } : {}),
704
+ };
705
+ },
706
+ /**
707
+ * 保留标准响应信封,由迁移页维持旧 `status` 分支语义。
708
+ *
709
+ * @param response - Runtime request pipeline 返回的 transport 响应。
710
+ * @param _input - 当前 endpoint 输入;解析响应时无需读取。
711
+ */
712
+ parse(response, _input) {
713
+ return parseAPIResponse(response, '工坊小程序详情加载失败');
714
+ },
715
+ };
716
+
627
717
  function runtimeContextBody(runtimeContext) {
628
718
  return { mini_program_id: runtimeContext.miniProgramId };
629
719
  }
@@ -964,6 +1054,7 @@ async function requestEndpoint(network, endpoint, input, context) {
964
1054
  }
965
1055
 
966
1056
  const USER_INFO_AUTHORIZATION_SCOPE_SET = new Set(USER_INFO_AUTHORIZATION_SCOPES);
1057
+ const AUTHORIZATION_PRESENTATION_DETAILS_TIMEOUT_MS = 1000;
967
1058
  function createAuthorizationCoordinator(options) {
968
1059
  const listeners = new Set();
969
1060
  const localIdentityCache = new Map();
@@ -972,13 +1063,18 @@ function createAuthorizationCoordinator(options) {
972
1063
  let generation = 0;
973
1064
  let disposed = false;
974
1065
  let presentationQueue = Promise.resolve();
1066
+ let activePresentationController;
975
1067
  const unsubscribeAccount = options.account.onChange((userId) => {
1068
+ invalidateAuthorizationContext();
1069
+ emit('heybox_app_login_change', { isHeyboxAppLoggedIn: Boolean(userId) });
1070
+ });
1071
+ function invalidateAuthorizationContext() {
976
1072
  generation += 1;
1073
+ activePresentationController?.abort();
977
1074
  localIdentityCache.clear();
978
1075
  localIdentityInflight.clear();
979
1076
  grantedScopes.clear();
980
- emit('heybox_app_login_change', { isHeyboxAppLoggedIn: Boolean(userId) });
981
- });
1077
+ }
982
1078
  function emit(name, payload) {
983
1079
  for (const listener of listeners) {
984
1080
  try {
@@ -1036,12 +1132,14 @@ function createAuthorizationCoordinator(options) {
1036
1132
  }
1037
1133
  return userId;
1038
1134
  }
1039
- async function request(endpoint, input) {
1135
+ async function request(endpoint, input, signal = options.operationContext.signal) {
1040
1136
  try {
1041
- return await requestEndpoint(options.network, endpoint, input, {
1137
+ if (signal.aborted)
1138
+ throw createAbortError$3();
1139
+ return await waitForAbortableOperation(requestEndpoint(options.network, endpoint, input, {
1042
1140
  credentials: 'heybox-session',
1043
- signal: options.operationContext.signal,
1044
- });
1141
+ signal,
1142
+ }), signal);
1045
1143
  }
1046
1144
  catch (error) {
1047
1145
  if (options.operationContext.signal.aborted) {
@@ -1071,7 +1169,19 @@ function createAuthorizationCoordinator(options) {
1071
1169
  }).catch(() => undefined);
1072
1170
  }
1073
1171
  function runPresentation(operation) {
1074
- const result = presentationQueue.then(operation, operation);
1172
+ const run = async () => {
1173
+ const controller = createLinkedAbortController(options.operationContext.signal);
1174
+ activePresentationController = controller;
1175
+ try {
1176
+ return await operation(controller.signal);
1177
+ }
1178
+ finally {
1179
+ if (activePresentationController === controller)
1180
+ activePresentationController = undefined;
1181
+ controller.abort();
1182
+ }
1183
+ };
1184
+ const result = presentationQueue.then(run, run);
1075
1185
  presentationQueue = result.then(() => undefined, () => undefined);
1076
1186
  return result;
1077
1187
  }
@@ -1084,14 +1194,17 @@ function createAuthorizationCoordinator(options) {
1084
1194
  await cancelAuthorization(miniProgramId, challengeValue.challenge);
1085
1195
  throw createCapabilityBridgeError('AUTHORIZATION_PRESENTATION_UNAVAILABLE', '授权确认界面不可用');
1086
1196
  }
1087
- return runPresentation(async () => {
1197
+ return runPresentation(async (presentationSignal) => {
1198
+ await assertAuthorizationContext(expectedUserId, expectedGeneration);
1199
+ const presentationDetails = await loadAuthorizationPresentationDetails(miniProgramId, challengeValue.displayedScopes, presentationSignal);
1088
1200
  await assertAuthorizationContext(expectedUserId, expectedGeneration);
1089
1201
  let decision;
1090
1202
  try {
1091
1203
  decision = await options.authPresentation.confirmAuthorization({
1092
1204
  miniProgramId,
1093
1205
  scopes: challengeValue.displayedScopes,
1094
- signal: options.operationContext.signal,
1206
+ ...presentationDetails,
1207
+ signal: presentationSignal,
1095
1208
  });
1096
1209
  }
1097
1210
  catch (error) {
@@ -1115,6 +1228,53 @@ function createAuthorizationCoordinator(options) {
1115
1228
  return selectedScopes;
1116
1229
  });
1117
1230
  }
1231
+ async function loadAuthorizationPresentationDetails(miniProgramId, displayedScopes, presentationSignal) {
1232
+ const detailController = createLinkedAbortController(presentationSignal);
1233
+ const timeout = setTimeout(() => detailController.abort(), AUTHORIZATION_PRESENTATION_DETAILS_TIMEOUT_MS);
1234
+ try {
1235
+ const trustedMiniProgram = normalizeMiniProgramPresentation(options.miniProgramPresentation);
1236
+ const [miniProgram, userProfile] = await Promise.all([
1237
+ trustedMiniProgram ? Promise.resolve(trustedMiniProgram) : loadMiniProgramPresentation(miniProgramId, detailController.signal),
1238
+ displayedScopes.includes('profile') ? loadUserProfilePresentation(detailController.signal) : Promise.resolve(undefined),
1239
+ ]);
1240
+ return {
1241
+ ...(miniProgram ? { miniProgram } : {}),
1242
+ ...(userProfile ? { userProfile } : {}),
1243
+ };
1244
+ }
1245
+ finally {
1246
+ clearTimeout(timeout);
1247
+ detailController.abort();
1248
+ }
1249
+ }
1250
+ async function loadMiniProgramPresentation(miniProgramId, signal) {
1251
+ try {
1252
+ const version = options.identity.get()?.version?.trim();
1253
+ const envelope = await request(userMiniprogramPublicDetailEndpoint, {
1254
+ mini_program_id: miniProgramId,
1255
+ ...(version ? { miniprogram_version: version } : {}),
1256
+ }, signal);
1257
+ const result = readSuccessfulResult$3(envelope, '小程序公开资料');
1258
+ const name = readOptionalPresentationText(result.name);
1259
+ const avatarUrl = readOptionalPresentationText(result.icon_url);
1260
+ return name || avatarUrl ? { ...(name ? { name } : {}), ...(avatarUrl ? { avatarUrl } : {}) } : undefined;
1261
+ }
1262
+ catch {
1263
+ return undefined;
1264
+ }
1265
+ }
1266
+ async function loadUserProfilePresentation(signal) {
1267
+ try {
1268
+ const envelope = await request(accountUserBaseInfoEnvelopeEndpoint, undefined, signal);
1269
+ const result = readSuccessfulResult$3(envelope, '账号基础信息');
1270
+ const nickname = readOptionalPresentationText(result.display_username);
1271
+ const avatar = readOptionalPresentationText(result.display_avatar);
1272
+ return nickname || avatar ? { ...(nickname ? { nickname } : {}), ...(avatar ? { avatar } : {}) } : undefined;
1273
+ }
1274
+ catch {
1275
+ return undefined;
1276
+ }
1277
+ }
1118
1278
  async function login(scopes, trustedUserGesture) {
1119
1279
  const miniProgramId = requireCanonicalMiniProgramId();
1120
1280
  const userId = await requireAuthenticatedUser(trustedUserGesture);
@@ -1231,10 +1391,7 @@ function createAuthorizationCoordinator(options) {
1231
1391
  });
1232
1392
  await assertAuthorizationContext(userId, expectedGeneration);
1233
1393
  readSuccessfulResult$3(envelope, '用户授权撤销');
1234
- generation += 1;
1235
- localIdentityCache.clear();
1236
- localIdentityInflight.clear();
1237
- grantedScopes.clear();
1394
+ invalidateAuthorizationContext();
1238
1395
  emit('user_info_authorization_change', { identity: 'denied', profile: 'denied' });
1239
1396
  return undefined;
1240
1397
  }
@@ -1251,11 +1408,8 @@ function createAuthorizationCoordinator(options) {
1251
1408
  if (disposed)
1252
1409
  return;
1253
1410
  disposed = true;
1254
- generation += 1;
1411
+ invalidateAuthorizationContext();
1255
1412
  unsubscribeAccount();
1256
- localIdentityCache.clear();
1257
- localIdentityInflight.clear();
1258
- grantedScopes.clear();
1259
1413
  listeners.clear();
1260
1414
  },
1261
1415
  };
@@ -1339,6 +1493,46 @@ function validateSelectedScopes(scopes, displayedScopes) {
1339
1493
  }
1340
1494
  return selected;
1341
1495
  }
1496
+ function readOptionalPresentationText(value) {
1497
+ return typeof value === 'string' && value.trim() ? value.trim() : undefined;
1498
+ }
1499
+ function normalizeMiniProgramPresentation(value) {
1500
+ const name = readOptionalPresentationText(value?.name);
1501
+ const avatarUrl = readOptionalPresentationText(value?.avatarUrl);
1502
+ return name || avatarUrl ? { ...(name ? { name } : {}), ...(avatarUrl ? { avatarUrl } : {}) } : undefined;
1503
+ }
1504
+ function createLinkedAbortController(parent) {
1505
+ const controller = new AbortController();
1506
+ if (parent.aborted) {
1507
+ controller.abort(parent.reason);
1508
+ }
1509
+ else {
1510
+ parent.addEventListener('abort', () => controller.abort(parent.reason), { once: true, signal: controller.signal });
1511
+ }
1512
+ return controller;
1513
+ }
1514
+ function waitForAbortableOperation(operation, signal) {
1515
+ if (signal.aborted)
1516
+ return Promise.reject(createAbortError$3());
1517
+ return new Promise((resolve, reject) => {
1518
+ let settled = false;
1519
+ const settle = (callback) => {
1520
+ if (settled)
1521
+ return;
1522
+ settled = true;
1523
+ signal.removeEventListener('abort', onAbort);
1524
+ callback();
1525
+ };
1526
+ const onAbort = () => settle(() => reject(createAbortError$3()));
1527
+ signal.addEventListener('abort', onAbort, { once: true });
1528
+ operation.then((value) => settle(() => resolve(value)), (error) => settle(() => reject(error)));
1529
+ });
1530
+ }
1531
+ function createAbortError$3() {
1532
+ const error = new Error('The operation was aborted');
1533
+ error.name = 'AbortError';
1534
+ return error;
1535
+ }
1342
1536
  function validateScopeArray(value, label) {
1343
1537
  if (!Array.isArray(value) ||
1344
1538
  value.some((scope) => typeof scope !== 'string' || !USER_INFO_AUTHORIZATION_SCOPE_SET.has(scope)) ||
@@ -3267,25 +3461,6 @@ function isBridgeError$1(error) {
3267
3461
  return isCapabilityRecord(error) && typeof error.code === 'string' && typeof error.message === 'string';
3268
3462
  }
3269
3463
 
3270
- /**
3271
- * @packageDocumentation
3272
- * 定义 AccountUserBaseInfo 接口的 Runtime endpoint 契约。
3273
- */
3274
- /**
3275
- * AccountUserBaseInfo 原始信封 endpoint。
3276
- *
3277
- * @remarks
3278
- * 供需要区分 `login`、`relogin` 等认证状态的领域服务使用;调用输入仍为 `void`,
3279
- * wire path 只由本 API contract owner 维护。
3280
- */
3281
- const accountUserBaseInfoEnvelopeEndpoint = {
3282
- auth: 'optional',
3283
- channel: 'api',
3284
- id: 'heybox.account.user_base_info.envelope.get',
3285
- method: 'GET',
3286
- path: '/account/get_user_base_info',
3287
- };
3288
-
3289
3464
  /**
3290
3465
  * @packageDocumentation
3291
3466
  * 定义 GameSteamGetGameList 接口的 Runtime endpoint 契约。
@@ -3878,6 +4053,7 @@ function createRuntimeCapabilityModules(options) {
3878
4053
  identity: options.identity,
3879
4054
  operationContext,
3880
4055
  authPresentation: options.authPresentation,
4056
+ miniProgramPresentation: options.miniProgramPresentation,
3881
4057
  });
3882
4058
  let user;
3883
4059
  let cloud;
@@ -4564,6 +4740,7 @@ class MiniProgramRuntimeImpl {
4564
4740
  if (this.isInactive())
4565
4741
  return;
4566
4742
  this.runtimePermissions = configuration.runtimePermissions;
4743
+ this.miniProgramPresentation = configuration.miniProgramPresentation;
4567
4744
  this.locationBasePath = configuration.locationBasePath;
4568
4745
  this.anonymousStorageScope = configuration.anonymousStorageScope ?? this.options.anonymousStorageScope;
4569
4746
  this.allowedHttpOrigins = configuration.allowedHttpOrigins ?? this.options.allowedHttpOrigins;
@@ -4625,6 +4802,7 @@ class MiniProgramRuntimeImpl {
4625
4802
  terminalSignal: this.terminalController.signal,
4626
4803
  eventSink,
4627
4804
  authPresentation: this.options.authPresentation,
4805
+ miniProgramPresentation: this.miniProgramPresentation,
4628
4806
  anonymousStorageScope: this.anonymousStorageScope,
4629
4807
  storageLimits: this.options.storageLimits,
4630
4808
  allowedHttpOrigins: this.allowedHttpOrigins,
package/dist/index.cjs.js CHANGED
@@ -671,7 +671,7 @@ function createMessageId() {
671
671
  /** 构建时替换为当前发布包的实际版本。 */
672
672
  const HB_SDK_VERSION = typeof undefined === 'string'
673
673
  ? undefined
674
- : '0.7.4-alpha.1';
674
+ : '0.7.4-alpha.4';
675
675
 
676
676
  const DEFAULT_TIMEOUT = 10000;
677
677
  const HANDSHAKE_RETRY_INTERVAL = 250;
package/dist/index.esm.js CHANGED
@@ -667,7 +667,7 @@ function createMessageId() {
667
667
  /** 构建时替换为当前发布包的实际版本。 */
668
668
  const HB_SDK_VERSION = typeof undefined === 'string'
669
669
  ? undefined
670
- : '0.7.4-alpha.1';
670
+ : '0.7.4-alpha.4';
671
671
 
672
672
  const DEFAULT_TIMEOUT = 10000;
673
673
  const HANDSHAKE_RETRY_INTERVAL = 250;
package/dist/vite.cjs.js CHANGED
@@ -8,7 +8,7 @@ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentS
8
8
  /** 构建时替换为当前发布包的实际版本。 */
9
9
  const HB_SDK_VERSION = typeof undefined === 'string'
10
10
  ? undefined
11
- : '0.7.4-alpha.1';
11
+ : '0.7.4-alpha.4';
12
12
 
13
13
  var re = {exports: {}};
14
14
 
package/dist/vite.esm.js CHANGED
@@ -5,7 +5,7 @@ import { AsyncLocalStorage } from 'node:async_hooks';
5
5
  /** 构建时替换为当前发布包的实际版本。 */
6
6
  const HB_SDK_VERSION = typeof undefined === 'string'
7
7
  ? undefined
8
- : '0.7.4-alpha.1';
8
+ : '0.7.4-alpha.4';
9
9
 
10
10
  var re = {exports: {}};
11
11
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heybox/hb-sdk",
3
- "version": "0.7.4-alpha.1",
3
+ "version": "0.7.4-alpha.4",
4
4
  "sideEffects": [
5
5
  "./src/index.ts",
6
6
  "./src/core/singleton.ts",
@@ -55,7 +55,7 @@
55
55
  "dependencies": {
56
56
  "parse5": "^7.3.0",
57
57
  "undici": "^7.28.0",
58
- "@heybox/hb-sdk-protocol": "0.7.4-alpha.1"
58
+ "@heybox/hb-sdk-protocol": "0.7.4-alpha.4"
59
59
  },
60
60
  "peerDependencies": {
61
61
  "vite": ">=5"
@@ -96,7 +96,7 @@
96
96
  "vue": "^2.7.16",
97
97
  "vite": "^8.0.12",
98
98
  "vitest": "^3.2.4",
99
- "@heybox/hb-sdk-runtime": "~0.7.4-alpha.1",
99
+ "@heybox/hb-sdk-runtime": "~0.7.4-alpha.4",
100
100
  "@heybox/hb-api": "~1.25.20"
101
101
  },
102
102
  "publishConfig": {
@@ -24,7 +24,7 @@
24
24
  ## Package metadata
25
25
 
26
26
  - Package: `@heybox/hb-sdk`
27
- - Version at generation time: `0.7.4-alpha.1`
27
+ - Version at generation time: `0.7.4-alpha.4`
28
28
  - Public root export: `@heybox/hb-sdk`
29
29
  - Protocol export: `@heybox/hb-sdk/protocol`
30
30
  - Vite plugin export: `@heybox/hb-sdk/vite`
@@ -163,6 +163,8 @@ async function loginFromUserAction() {
163
163
 
164
164
  需要展示登录或授权 UI 时,调用必须来自按钮点击等可信用户手势,否则返回 `USER_GESTURE_REQUIRED`。用户取消、拒绝或关闭授权页面时返回 `AUTHORIZATION_CANCELLED`,业务应停留在当前页面并允许稍后重试。
165
165
 
166
+ 首次授权时,Host 授权页会展示当前小程序的名称和图标;申请 `profile` scope 时,还会预览当前小黑盒账号的昵称和头像,帮助用户确认资料披露对象。Runtime 优先复用 Host 启动阶段已经解析的资料,读取补充资料失败或超时时使用中性占位,不影响用户继续授权。账号切换、授权撤销或 Runtime 终止会关闭当前确认界面;这些 Host 展示字段不会加入 `auth.login()` 返回值。
167
+
166
168
  用户已授权所需 scope 时,`auth.login()` 可以不展示 UI,静默返回新的短期授权码。业务仍应把可能出现的授权 UI 设计在明确的用户操作之后,不要在页面初始化阶段自动调用。
167
169
 
168
170
  ## 撤销当前小程序授权
package/skill/skill.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "hb-sdk",
3
- "skillVersion": "0.7.4-alpha.1+skill.012bc6457d0f",
3
+ "skillVersion": "0.7.4-alpha.4+skill.248b8d6d06cb",
4
4
  "sdk": {
5
5
  "package": "@heybox/hb-sdk",
6
- "version": "0.7.4-alpha.1",
7
- "compatibility": "0.7.4-alpha.1"
6
+ "version": "0.7.4-alpha.4",
7
+ "compatibility": "0.7.4-alpha.4"
8
8
  },
9
9
  "source": "https://open.xiaoheihe.cn/agent-skills/hb-sdk",
10
- "integrity": "sha256-012bc6457d0f8f3c30feb117ba0cbcde986dcbb4587587aade7a5a09b1bc3261"
10
+ "integrity": "sha256-248b8d6d06cb00817bfadca1bc5fd0d15112088f6548c11cb6d715453e2a6d4d"
11
11
  }