@heybox/hb-sdk 0.6.9 → 0.7.0-alpha.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.
Files changed (57) hide show
  1. package/CHANGELOG.md +41 -7
  2. package/README.md +83 -20
  3. package/dist/cli-chunks/{build-BtGxhrcV.cjs → build-CWBksuZX.cjs} +2 -2
  4. package/dist/cli-chunks/{context-DX1KG-8A.cjs → context-B3_TJIaj.cjs} +1 -1
  5. package/dist/cli-chunks/{create-DAD0OF1r.cjs → create-BdDwp1Qx.cjs} +1 -1
  6. package/dist/cli-chunks/{dev-Dh4HY0I8.cjs → dev-PCY_9q8y.cjs} +40 -8
  7. package/dist/cli-chunks/{doctor-BfKdiD3H.cjs → doctor-DzEMXA58.cjs} +1 -1
  8. package/dist/cli-chunks/{index-tCURDEx8.cjs → index-CjT2V5RD.cjs} +15 -14
  9. package/dist/cli-chunks/{index-DB6Q8HaC.cjs → index-DmgF1ROG.cjs} +1 -1
  10. package/dist/cli-chunks/{login-D60EJLgs.cjs → login-D775i7Ub.cjs} +2 -2
  11. package/dist/cli-chunks/{project-vite-DAUaP0_3.cjs → project-vite-ty-N0y8F.cjs} +1 -1
  12. package/dist/cli-chunks/{remote-nQDniAUY.cjs → remote-3Zmtshjq.cjs} +4 -4
  13. package/dist/cli-chunks/{session-D6jOKXeu.cjs → session-piLyMOuV.cjs} +1 -1
  14. package/dist/cli.cjs +1 -1
  15. package/dist/devtools/mock-host/index.html +9 -2
  16. package/dist/devtools/mock-host/main.js +390 -801
  17. package/dist/index.cjs.js +46 -90
  18. package/dist/index.esm.js +46 -90
  19. package/dist/protocol.cjs.js +98 -42
  20. package/dist/protocol.esm.js +93 -39
  21. package/dist/templates/vue3-vite-ts/README.md.ejs +1 -1
  22. package/dist/templates/vue3-vite-ts/src/App.vue +22 -17
  23. package/dist/templates/vue3-vite-ts/src/__tests__/App.spec.ts +37 -29
  24. package/dist/templates/vue3-vite-ts/src/auth-handoff.ts +46 -0
  25. package/dist/vite.cjs.js +2 -2
  26. package/dist/vite.esm.js +2 -2
  27. package/package.json +2 -2
  28. package/skill/SKILL.md +16 -12
  29. package/skill/references/api-protocol.md +22 -28
  30. package/skill/references/api-root.md +127 -112
  31. package/skill/references/cli.md +15 -20
  32. package/skill/references/examples.md +29 -17
  33. package/skill/references/recipes.md +180 -134
  34. package/skill/references/safety-boundaries.md +9 -3
  35. package/skill/scripts/sync-references.mjs +235 -139
  36. package/skill/scripts/validate-skill.mjs +18 -14
  37. package/skill/skill.json +4 -4
  38. package/types/index.d.ts +4 -4
  39. package/types/modules/auth/index.d.ts +16 -28
  40. package/types/modules/cloud/index.d.ts +2 -2
  41. package/types/modules/network/index.d.ts +1 -2
  42. package/types/modules/user/get-info.d.ts +4 -4
  43. package/types/modules/user/get-local-identity.d.ts +9 -0
  44. package/types/modules/user/index.d.ts +13 -41
  45. package/types/modules/user/revoke-authorization.d.ts +7 -0
  46. package/types/modules/user/steam-game-list.d.ts +72 -0
  47. package/types/modules/user/types.d.ts +37 -302
  48. package/types/protocol/capabilities.d.ts +24 -49
  49. package/types/protocol/constants.d.ts +1 -1
  50. package/types/protocol/network-policy.d.ts +10 -0
  51. package/types/protocol/types.d.ts +10 -6
  52. package/types/protocol.d.ts +4 -3
  53. package/types/modules/user/get-current-user-detail.d.ts +0 -9
  54. package/types/modules/user/get-current-user-profile.d.ts +0 -9
  55. package/types/modules/user/get-platform-account-info.d.ts +0 -12
  56. package/types/modules/user/get-platform-account-overview.d.ts +0 -9
  57. package/types/modules/user/get-steam-game-list.d.ts +0 -12
package/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.7.0-alpha.1
4
+
5
+ ### Docs / Agent Skill
6
+
7
+ - 开发者服务端改为调用 `GET /user_miniprogram/openapi/v1/user` 读取当前用户,不再使用已下线的 `/user/identity` 与 `/user/profile`。
8
+
9
+ ### Runtime
10
+
11
+ - 公开详情关网时的合法空权限快照视为未开通 `network.request`,允许本地身份读取与撤销授权。
12
+
13
+ ## 0.7.0-alpha.0
14
+
15
+ ### Release
16
+
17
+ - 硬切小程序隐私用户身份 v2 契约,并保留 v1 bridge 握手兼容。
18
+ - 排行榜记录的公开用户标识从 `userId` 硬切为按小程序隔离的 `appUserId`。
19
+
20
+ ### SDK
21
+
22
+ - 已开通网络权限的小程序统一通过 `auth.login({ scopes? })` 获取 5 分钟短期授权码;identity 隐式强制包含,返回值不再携带用户、资料或 `appUserId`。
23
+ - 未开通网络权限的小程序通过 `user.getLocalIdentity()` 读取当前小程序内隔离的 `appUserId`,不能获取授权码或调用 OpenAPI。
24
+ - 新增 `user.revokeAuthorization()`,在两种网络模式下由可信用户操作撤销当前账号对当前小程序的授权。
25
+ - 已开通网络权限时,Host current-user 资料与平台账号读取统一提示 `SERVER_API_REQUIRED`,由开发者服务端通过 OpenAPI 获取。
26
+
27
+ ### Security
28
+
29
+ - 授权码只能交给开发者服务端换取 token;小程序页面不得持有服务端应用凭据,`network.request` 也不能访问平台保留的 runtime auth 与 OpenAPI 内部路径。
30
+ - 需要授权 UI 且缺少可信用户手势时返回 `USER_GESTURE_REQUIRED`;用户取消或关闭时返回 `AUTHORIZATION_CANCELLED`,已授权场景可静默签发新 code。
31
+
32
+ ### Docs / Agent Skill
33
+
34
+ - README、用户身份 Guide、快速开始、登录门禁、错误处理、生命周期、CLI 与排行榜文档同步新身份边界,并移除旧用户授权 API 指引。
35
+
3
36
  ## 0.6.9
4
37
 
5
38
  ### SDK
@@ -45,16 +78,17 @@
45
78
 
46
79
  ### SDK
47
80
 
48
- - `network.request` 失败时输出脱敏诊断日志,覆盖 HTTP 非 2xx、无效响应与 bridge/runtime 错误;`HbMiniProgramNetworkError` 文案补充 statusText/method/url(message 为诊断字符串,业务请用 `instanceof` + `status`/`data` 等字段,勿精确匹配全文) (@heybox/hb-sdk).
49
- - 诊断日志与错误文案统一脱敏:敏感 header/query/body 字段、URL userinfo;Mock Host / mock network proxy 复用同一套脱敏原语 (@heybox/hb-sdk).
50
- - 日志前缀:`[hb-sdk][network.request]` / `[hb-sdk][mock-host][network.request]` / `[hb-sdk][mock-network]` (@heybox/hb-sdk).
51
- - `network.request` 提前拒绝 `multipart/form-data`(含手写 boundary body),以 `INVALID_PARAMS` 给出可操作中文说明;Mock 网络代理同步拒绝,避免本地 fetch 能通、App Host heybox 代发失败 (@heybox/hb-sdk).
52
- - `HbMiniProgramNetworkError` 识别宿主伪装的 `network_error` / `unsupported-request-shape` 失败,在 message 中标明“非目标站 HTTP 状态”并补充 form/json 用法提示 (@heybox/hb-sdk).
81
+ - 用户身份 API 收敛为 `auth.requireHeyboxAppLogin()`、`user.getInfo()` `user.authorize()`;登录不再返回资料,身份使用按小程序隔离的 `app_user_id`,资料按授权 scope 披露。
82
+ - Vue 3 模板、调试示例与公开文档同步使用 v2 登录和资料授权流程。
53
83
 
54
84
  ### Runtime
55
85
 
56
- - Runtime 侧记录 `network.request` 参数校验失败、adapter 失败与非 2xx 诊断日志(前缀 `[hb-sdk-runtime][network.request]`;非 2xx 仍保持 bridge success) (@heybox/hb-sdk-runtime).
57
- - Runtime 参数校验同步拒绝 multipart,避免落到 heybox transport 后变成含糊的 500 `network_error` (@heybox/hb-sdk-runtime).
86
+ - Host 集成改用稳定的用户身份隔离接口,并由 Runtime 构造授权结果,避免转发后端额外字段。
87
+ - `user.authorize` 对畸形 payload 稳定返回 `INVALID_PARAMS`;浏览器 Mock 使用 `heybox_app_login_change` 与 `user_info_authorization_change` 事件,并保持授权事件不携带身份资料。
88
+
89
+ ### Docs / Agent Skill
90
+
91
+ - 同步 README、Guide、Recipe、API Reference 与 Agent Skill,移除已删除的用户 API 指引。
58
92
 
59
93
  ## 0.6.8-alpha.2
60
94
 
package/README.md CHANGED
@@ -23,20 +23,49 @@ npm run dev
23
23
  npm install @heybox/hb-sdk
24
24
  ```
25
25
 
26
- 页面启动时等待 SDK 就绪,再读取当前用户状态:
26
+ 页面启动时先等待 SDK 就绪。未开通网络权限的小程序可以读取当前小程序内的隔离身份:
27
27
 
28
28
  ```ts
29
29
  import hbSDK from '@heybox/hb-sdk';
30
30
 
31
- await hbSDK.ready();
31
+ async function getLocalIdentityFromUserAction() {
32
+ await hbSDK.ready();
33
+ const { appUserId } = await hbSDK.user.getLocalIdentity();
34
+ return appUserId;
35
+ }
36
+ ```
37
+
38
+ 把 `getLocalIdentityFromUserAction` 绑定到按钮点击等可信用户操作。首次登录或 identity consent 需要 UI 而缺少可信手势时返回 `USER_GESTURE_REQUIRED`;用户取消或关闭时返回 `AUTHORIZATION_CANCELLED`,不会确认或改变授权状态。
39
+
40
+ 已开通网络权限的小程序在按钮点击等明确的用户操作中调用 `auth.login()`:
41
+
42
+ ```ts
43
+ async function loginFromUserAction() {
44
+ const { code, expiresIn, scopes } = await hbSDK.auth.login({ scopes: ['profile'] });
45
+ await hbSDK.network.request({
46
+ url: 'https://api.example.com/session/heybox',
47
+ method: 'POST',
48
+ data: { code },
49
+ });
50
+ console.log(expiresIn, scopes);
51
+ }
52
+ ```
53
+
54
+ `auth.login()` 返回 `{ code, expiresIn: 300, scopes }`,其中 `identity` 隐式强制包含;它不返回 user、profile、`appUserId` 或 token。页面只能把 code 交给开发者服务端,再由服务端按后端 OpenAPI 文档换取 token。未开通网络权限的小程序使用 `user.getLocalIdentity()`,无法获取 code 或调用 OpenAPI。完整边界见[用户身份与登录](https://docs.xiaoheihe.cn/hb_sdk/guide/auth)。
55
+
56
+ 用户可以在明确的按钮点击和二次确认后撤销当前小程序的授权:
57
+
58
+ ```ts
59
+ async function revokeAuthorizationFromUserAction() {
60
+ const confirmed = window.confirm('确定撤销当前小程序的用户授权吗?');
61
+ if (!confirmed) return;
32
62
 
33
- const result = await hbSDK.user.getInfo();
34
- if (result.isLogin && result.userInfo) {
35
- console.log(result.userInfo.nickname);
63
+ await hbSDK.user.revokeAuthorization();
64
+ // 同步清理业务保存的 appUserId、用户资料和服务端会话。
36
65
  }
37
66
  ```
38
67
 
39
- `ready()` 只表示 SDK 可以调用,不代表用户已经登录。需要登录时,请在按钮点击等明确的用户操作中调用 `hbSDK.auth.login()`。
68
+ `user.revokeAuthorization()` 在已开通和未开通网络权限的小程序中都可用,不接收小程序 ID、黑盒用户 ID 或手势参数。调用必须来自可信用户操作,否则返回 `USER_GESTURE_REQUIRED`。撤销成功后,后续身份或授权读取会重新进入授权流程;SDK 不会替业务清理已经持久化的数据。
40
69
 
41
70
  已有 Vite 项目还需要启用构建插件:
42
71
 
@@ -76,31 +105,65 @@ try {
76
105
 
77
106
  除 `ready()` 外,SDK 还提供 `on()` 和 `off()` 处理前后台、登录态等生命周期事件。
78
107
 
79
- | 模块 | 用途 |
80
- | ------------ | -------------------------------- |
81
- | `auth` | 由用户操作触发登录 |
82
- | `user` | 读取当前用户、账号资料和游戏数据 |
83
- | `share` | 打开分享或截图分享流程 |
84
- | `ui` | 展示 Toast 和 Loading |
85
- | `device` | 调用振动和剪贴板能力 |
86
- | `navigation` | 关闭、刷新页面或打开小黑盒页面 |
87
- | `viewport` | 读取窗口信息和设置导航栏样式 |
88
- | `storage` | 读写当前小程序的隔离存储 |
89
- | `cloud` | 使用小程序云端排行榜 |
90
- | `network` | 发起经过平台授权的网络请求 |
108
+ | 模块 | 用途 |
109
+ | ------------ | ------------------------------------------------------------ |
110
+ | `auth` | 获取交给开发者服务端交换的短期授权码 |
111
+ | `user` | 使用 Host current-user APIs 或读取无网络小程序的本地隔离身份 |
112
+ | `share` | 打开分享或截图分享流程 |
113
+ | `ui` | 展示 Toast 和 Loading |
114
+ | `device` | 调用振动和剪贴板能力 |
115
+ | `navigation` | 关闭、刷新页面或打开小黑盒页面 |
116
+ | `viewport` | 读取窗口信息和设置导航栏样式 |
117
+ | `storage` | 读写当前小程序的隔离存储 |
118
+ | `cloud` | 使用小程序云端排行榜 |
119
+ | `network` | 发起经过平台授权的网络请求 |
91
120
 
92
121
  具体方法、参数和返回值以 [API Reference](https://docs.xiaoheihe.cn/hb_sdk/reference/) 为准,常见组合写法见 [Recipes](https://docs.xiaoheihe.cn/hb_sdk/recipes/)。
93
122
 
94
123
  ## 关键约束
95
124
 
96
- - `ready()` 不代表用户已登录;使用 `user.getInfo()` 判断登录状态。
97
- - `auth.login()` 只能由明确的用户操作触发,不要在页面初始化时自动登录。
125
+ - `ready()` 只表示 SDK 可调用,不表示已取得用户授权。
126
+ - `auth.login({ scopes? })` 只返回 `{ code, expiresIn: 300, scopes }`;identity 隐式强制包含,code 只能提交给开发者服务端。
127
+ - 需要授权 UI 时,`auth.login()` 必须来自可信用户手势,否则返回 `USER_GESTURE_REQUIRED`;用户取消或关闭时返回 `AUTHORIZATION_CANCELLED`。已授权时可以静默返回新 code。
128
+ - `user.getSteamGameList()` 仅供未开通网络权限的小程序通过 Host 读取;已开通网络权限时返回 `SERVER_API_REQUIRED`,且授权码与 OpenAPI 不提供 Steam 游戏库 scope 或资源接口。
129
+ - 已开通网络权限时,公开的 `user.getInfo()` 和 `user.getLocalIdentity()` 返回 `SERVER_API_REQUIRED`;对应身份和资料数据应由开发者服务端通过 OpenAPI 获取。
130
+ - 未开通网络权限时,只用 `user.getLocalIdentity()` 获取 `{ appUserId }`,不能获取 code 或调用 OpenAPI。
131
+ - `user.revokeAuthorization()` 在两种网络模式下都要求可信用户手势;成功后必须停止使用并清理业务缓存的旧身份、资料和服务端会话。
98
132
  - `on()` 返回取消监听函数,组件卸载或页面销毁时需要调用。
99
133
  - 业务网络请求使用 `network.request()`,不要依赖浏览器原生网络出口。
134
+ - `network.request()` 不能访问平台保留的 runtime auth 与 OpenAPI 内部路径;页面不得持有或交换服务端应用凭据。
100
135
  - `network.request` 不支持 `multipart/form-data`;App Host 仅支持 form(`application/x-www-form-urlencoded`)与 JSON。表单请用 `URLSearchParams#toString()` 作为 `data`,文件上传请走专用上传能力。
101
136
  - 仅当远端已启用 `network.request` 且 `useOfficialDomain=true` 时,`hb-sdk dev` 与 `hb-sdk remote deploy` 构建才会跳过平台 CSP;其他构建继续注入平台 CSP。
102
137
  - 构建必须启用 `miniappManifest()`,推荐统一使用 `hb-sdk build`。
103
138
 
139
+ ## 云端排行榜
140
+
141
+ 删除当前用户的排行榜成绩属于破坏性操作,只能在明确的用户操作和二次确认后执行:
142
+
143
+ ```ts
144
+ async function deleteMyLeaderboardEntryFromUserAction() {
145
+ const confirmed = window.confirm('确定删除自己的榜单成绩吗?');
146
+ if (!confirmed) return;
147
+
148
+ try {
149
+ await hbSDK.cloud.leaderboard.deleteCurrentUserEntry({ key: 'cube_run_total' });
150
+ } catch (error) {
151
+ if (error instanceof HbMiniProgramSDKError) {
152
+ console.error(error.code, error.message);
153
+ }
154
+ throw error;
155
+ }
156
+ }
157
+ ```
158
+
159
+ 排行榜记录的 `extra` 会展示给榜单中的其他读取者,只能包含公开展示必需的数据;不得写入个人身份信息(PII)、token、设备标识或非必要行为数据。
160
+
161
+ 管理员删除完整榜单及其排名记录时,必须显式传入匹配的榜单 key 进行确认:
162
+
163
+ ```bash
164
+ hb-sdk remote cloud leaderboard delete <key> --confirm <key>
165
+ ```
166
+
104
167
  ## CLI 主流程
105
168
 
106
169
  ```bash
@@ -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-DKrhgVM3.cjs');
7
7
  var runtimeGate = require('./runtime-gate-BWlU-R4h.cjs');
8
- var index = require('./index-tCURDEx8.cjs');
9
- var projectVite = require('./project-vite-DAUaP0_3.cjs');
8
+ var index = require('./index-CjT2V5RD.cjs');
9
+ var projectVite = require('./project-vite-ty-N0y8F.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-D6jOKXeu.cjs');
3
+ var session = require('./session-piLyMOuV.cjs');
4
4
  var runtimePermissionEnv = require('./runtime-permission-env-DKrhgVM3.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-tCURDEx8.cjs');
8
+ var index = require('./index-CjT2V5RD.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-DX1KG-8A.cjs');
9
+ var context = require('./context-B3_TJIaj.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-tCURDEx8.cjs');
14
- var projectVite = require('./project-vite-DAUaP0_3.cjs');
13
+ var index = require('./index-CjT2V5RD.cjs');
14
+ var projectVite = require('./project-vite-ty-N0y8F.cjs');
15
15
  var fs$1 = require('node:fs/promises');
16
16
  var runtimePermissionEnv = require('./runtime-permission-env-DKrhgVM3.cjs');
17
- require('./session-D6jOKXeu.cjs');
17
+ require('./session-piLyMOuV.cjs');
18
18
  require('fs');
19
19
  require('constants');
20
20
  require('stream');
@@ -988,6 +988,7 @@ function createMiniProgramMockHostServer(root, runtime) {
988
988
  const pathname = decodeURIComponent(requestUrl.pathname);
989
989
  const devSessionRoute = devSessionRoutes.match(pathname);
990
990
  const loopbackPeer = runtime.isLoopbackPeer(request.socket.remoteAddress);
991
+ // Dev Session 需要允许手机局域网访问;其余 mock 页仍限制本机。
991
992
  if (!loopbackPeer && !devSessionRoute) {
992
993
  writeForbidden(response);
993
994
  return;
@@ -1230,7 +1231,8 @@ function createMacAppProtocol(appUrl, options = {}) {
1230
1231
  return createHeyboxProtocol(createMiniProgramDevShellOpenWindowPayload(appUrl, options));
1231
1232
  }
1232
1233
  function createMobileAppQrPayload(appUrl, options = {}) {
1233
- return `${OPEN_IN_APP_URL}#${createHeyboxProtocol(createMiniProgramDevShellOpenWindowPayload(appUrl, { ...options, encodeMiniUrl: false }))}`;
1234
+ const protocol = createHeyboxProtocol(createMiniProgramDevShellOpenWindowPayload(appUrl, { ...options, encodeMiniUrl: false }));
1235
+ return options.bareProtocol ? protocol : `${OPEN_IN_APP_URL}#${protocol}`;
1234
1236
  }
1235
1237
  function createMiniProgramDevShellOpenWindowPayload(appUrl, options = {}) {
1236
1238
  const devShellUrl = options.encodeMiniUrl === false
@@ -1259,7 +1261,8 @@ function createPartiallyEncodedMiniProgramDevShellUrl(appUrl, options) {
1259
1261
  devShellUrl += `&mini_program_id=${encodeURIComponent(miniProgramId)}`;
1260
1262
  }
1261
1263
  if (hasRuntimeUrl(options.runtimeUrl)) {
1262
- devShellUrl += `&${MINI_PROGRAM_RUNTIME_URL_QUERY_PARAM}=${encodeURIComponent(options.runtimeUrl)}`;
1264
+ const runtimeUrl = buildRuntimeUrlWithLaunchParams(options.runtimeUrl, appUrl, options);
1265
+ devShellUrl += `&${MINI_PROGRAM_RUNTIME_URL_QUERY_PARAM}=${encodeURIComponent(runtimeUrl)}`;
1263
1266
  }
1264
1267
  const sdkVersion = options.sdkVersion?.trim();
1265
1268
  if (sdkVersion) {
@@ -1275,7 +1278,7 @@ function createEncodedMiniProgramDevShellUrl(appUrl, options) {
1275
1278
  devShellUrl.searchParams.set('mini_program_id', miniProgramId);
1276
1279
  }
1277
1280
  if (hasRuntimeUrl(options.runtimeUrl)) {
1278
- devShellUrl.searchParams.set(MINI_PROGRAM_RUNTIME_URL_QUERY_PARAM, options.runtimeUrl);
1281
+ devShellUrl.searchParams.set(MINI_PROGRAM_RUNTIME_URL_QUERY_PARAM, buildRuntimeUrlWithLaunchParams(options.runtimeUrl, appUrl, options));
1279
1282
  }
1280
1283
  const sdkVersion = options.sdkVersion?.trim();
1281
1284
  if (sdkVersion) {
@@ -1286,6 +1289,32 @@ function createEncodedMiniProgramDevShellUrl(appUrl, options) {
1286
1289
  function hasRuntimeUrl(runtimeUrl) {
1287
1290
  return runtimeUrl !== undefined && runtimeUrl !== '';
1288
1291
  }
1292
+ /**
1293
+ * 客户端加载 runtime_url 时,常只打开该 URL 本身,不会把 sandbox 上的 mini_url 再拼进去。
1294
+ * 电脑浏览器手开 detail 能成功,是因为 URL 上已经带了 mini_url。
1295
+ * 因此 HTTP(S) runtime host 需要在 runtime_url 内预置启动参数。
1296
+ */
1297
+ function buildRuntimeUrlWithLaunchParams(runtimeUrl, appUrl, options) {
1298
+ try {
1299
+ const url = new URL(runtimeUrl);
1300
+ if (url.protocol !== 'http:' && url.protocol !== 'https:') {
1301
+ return runtimeUrl;
1302
+ }
1303
+ url.searchParams.set(MINI_PROGRAM_URL_QUERY_PARAM, appUrl);
1304
+ const miniProgramId = options.miniProgramId?.trim();
1305
+ if (miniProgramId) {
1306
+ url.searchParams.set('mini_program_id', miniProgramId);
1307
+ }
1308
+ const sdkVersion = options.sdkVersion?.trim();
1309
+ if (sdkVersion) {
1310
+ url.searchParams.set(MINI_PROGRAM_SDK_VERSION_QUERY_PARAM, sdkVersion);
1311
+ }
1312
+ return url.toString();
1313
+ }
1314
+ catch {
1315
+ return runtimeUrl;
1316
+ }
1317
+ }
1289
1318
  function createHeyboxProtocol(payload) {
1290
1319
  return `heybox://${encodeURIComponent(JSON.stringify(payload))}`;
1291
1320
  }
@@ -1293,7 +1322,7 @@ function createHeyboxProtocol(payload) {
1293
1322
  /** 构建时替换为当前发布包的实际版本。 */
1294
1323
  const HB_SDK_VERSION = typeof undefined === 'string'
1295
1324
  ? undefined
1296
- : '0.6.9';
1325
+ : '0.7.0-alpha.1';
1297
1326
 
1298
1327
  class DevPermissionOverrideStoreError extends Error {
1299
1328
  code;
@@ -1476,6 +1505,7 @@ async function runDevCommand(options, runtime = {}) {
1476
1505
  hmrHost: resolvedOptions.hmrHost,
1477
1506
  interfaces: networkInterfaceSnapshot,
1478
1507
  miniProgramId: devLaunchContext.miniProgramId,
1508
+ rawProtocol: options.rawProtocol,
1479
1509
  runtimeUrl: options.runtimeUrl,
1480
1510
  sdkVersion: HB_SDK_VERSION,
1481
1511
  viteNetworkUrls: appServer.resolvedUrls?.network ?? [],
@@ -1826,6 +1856,7 @@ function createLanAddressCandidates(options) {
1826
1856
  const runtimeUrl = rewriteLoopbackUrlHost(options.runtimeUrl, address);
1827
1857
  if (runtimeUrl !== undefined) {
1828
1858
  candidate.mobileAppQrPayload = createMobileAppQrPayload(appUrl, {
1859
+ bareProtocol: options.rawProtocol,
1829
1860
  miniProgramId: options.miniProgramId,
1830
1861
  runtimeUrl,
1831
1862
  sdkVersion: options.sdkVersion,
@@ -1833,6 +1864,7 @@ function createLanAddressCandidates(options) {
1833
1864
  }
1834
1865
  else {
1835
1866
  candidate.mobileAppQrPayload = createMobileAppQrPayload(appUrl, {
1867
+ bareProtocol: options.rawProtocol,
1836
1868
  miniProgramId: options.miniProgramId,
1837
1869
  sdkVersion: options.sdkVersion,
1838
1870
  });
@@ -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-tCURDEx8.cjs');
7
+ var index = require('./index-CjT2V5RD.cjs');
8
8
  require('node:module');
9
9
  require('path');
10
10
  require('os');
@@ -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-tCURDEx8.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-CjT2V5RD.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-tCURDEx8.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-CjT2V5RD.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-tCURDEx8.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-CjT2V5RD.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-tCURDEx8.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-CjT2V5RD.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-tCURDEx8.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-CjT2V5RD.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.6.9';
13350
+ const BUILT_CLI_VERSION = '0.7.0-alpha.1';
13351
13351
  const PACKAGE_JSON_CANDIDATES = [
13352
13352
  path.resolve(__dirname, '..', '..', 'package.json'),
13353
13353
  path.resolve(__dirname, '..', 'package.json'),
@@ -13436,6 +13436,7 @@ function createCliProgram(overrides = {}) {
13436
13436
  .option('--port <port>', 'App dev server 端口', parsePositivePort)
13437
13437
  .option('--mock-port <port>', 'Mock host 端口', parsePositivePort)
13438
13438
  .option('--runtime-url <url>', '真实客户端调试时使用的自定义 runtime 地址')
13439
+ .option('--raw-protocol', 'Mobile App 二维码使用裸 heybox:// 协议')
13439
13440
  .option('--no-open', '不自动打开浏览器调试页')).action(withUpdateReminder(async (options, command) => {
13440
13441
  const logger = resolveLogger(command);
13441
13442
  await handlers.runDevCommand(options, { logger });
@@ -13680,35 +13681,35 @@ function createCommandLoggerResolver(options) {
13680
13681
  };
13681
13682
  }
13682
13683
  const defaultClearLoginStatus = async (...args) => {
13683
- const { clearLoginStatus } = await Promise.resolve().then(function () { return require('./login-D60EJLgs.cjs'); });
13684
+ const { clearLoginStatus } = await Promise.resolve().then(function () { return require('./login-D775i7Ub.cjs'); });
13684
13685
  return clearLoginStatus(...args);
13685
13686
  };
13686
13687
  const defaultLoginToHeybox = async (...args) => {
13687
- const { loginToHeybox } = await Promise.resolve().then(function () { return require('./login-D60EJLgs.cjs'); });
13688
+ const { loginToHeybox } = await Promise.resolve().then(function () { return require('./login-D775i7Ub.cjs'); });
13688
13689
  return loginToHeybox(...args);
13689
13690
  };
13690
13691
  const defaultPrintLoginStatus = async (...args) => {
13691
- const { printLoginStatus } = await Promise.resolve().then(function () { return require('./login-D60EJLgs.cjs'); });
13692
+ const { printLoginStatus } = await Promise.resolve().then(function () { return require('./login-D775i7Ub.cjs'); });
13692
13693
  return printLoginStatus(...args);
13693
13694
  };
13694
13695
  const defaultRunBuildCommand = async (...args) => {
13695
- const { runBuildCommand } = await Promise.resolve().then(function () { return require('./build-BtGxhrcV.cjs'); });
13696
+ const { runBuildCommand } = await Promise.resolve().then(function () { return require('./build-CWBksuZX.cjs'); });
13696
13697
  return runBuildCommand(...args);
13697
13698
  };
13698
13699
  const defaultRunCreateCommand = async (...args) => {
13699
- const { runCreateCommand } = await Promise.resolve().then(function () { return require('./create-DAD0OF1r.cjs'); });
13700
+ const { runCreateCommand } = await Promise.resolve().then(function () { return require('./create-BdDwp1Qx.cjs'); });
13700
13701
  return runCreateCommand(...args);
13701
13702
  };
13702
13703
  const defaultRunDevCommand = async (...args) => {
13703
- const { runDevCommand } = await Promise.resolve().then(function () { return require('./dev-Dh4HY0I8.cjs'); });
13704
+ const { runDevCommand } = await Promise.resolve().then(function () { return require('./dev-PCY_9q8y.cjs'); });
13704
13705
  return runDevCommand(...args);
13705
13706
  };
13706
13707
  const defaultRunDoctorCommand = async (...args) => {
13707
- const { runDoctorCommand } = await Promise.resolve().then(function () { return require('./doctor-BfKdiD3H.cjs'); });
13708
+ const { runDoctorCommand } = await Promise.resolve().then(function () { return require('./doctor-DzEMXA58.cjs'); });
13708
13709
  return runDoctorCommand(...args);
13709
13710
  };
13710
13711
  const defaultRunRemoteCommand = async (...args) => {
13711
- const { runRemoteCommand } = await Promise.resolve().then(function () { return require('./remote-nQDniAUY.cjs'); });
13712
+ const { runRemoteCommand } = await Promise.resolve().then(function () { return require('./remote-3Zmtshjq.cjs'); });
13712
13713
  return runRemoteCommand(...args);
13713
13714
  };
13714
13715
  function resolveStandaloneLogger(options, verbose) {
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index$2 = require('./index-tCURDEx8.cjs');
3
+ var index$2 = require('./index-CjT2V5RD.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');
@@ -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-D6jOKXeu.cjs');
6
+ var session = require('./session-piLyMOuV.cjs');
7
7
  var browser = require('./browser-RAy8e8cV.cjs');
8
- var index = require('./index-tCURDEx8.cjs');
8
+ var index = require('./index-CjT2V5RD.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-tCURDEx8.cjs');
8
+ var index = require('./index-CjT2V5RD.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-tCURDEx8.cjs');
5
- var session = require('./session-D6jOKXeu.cjs');
4
+ var index = require('./index-CjT2V5RD.cjs');
5
+ var session = require('./session-piLyMOuV.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-DKrhgVM3.cjs');
11
11
  var runtimeGate = require('./runtime-gate-BWlU-R4h.cjs');
12
12
  var node_crypto = require('node:crypto');
13
- var context = require('./context-DX1KG-8A.cjs');
13
+ var context = require('./context-B3_TJIaj.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-DB6Q8HaC.cjs'); }).then(function (n) { return n.index; });
274
+ const cosModule = await Promise.resolve().then(function () { return require('./index-DmgF1ROG.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-tCURDEx8.cjs');
3
+ var index = require('./index-CjT2V5RD.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-tCURDEx8.cjs');
3
+ var index = require('./cli-chunks/index-CjT2V5RD.cjs');
4
4
  require('node:module');
5
5
  require('node:fs');
6
6
  require('node:fs/promises');
@@ -216,13 +216,20 @@
216
216
  }
217
217
 
218
218
  .mobile-qr img {
219
- width: 176px;
220
- height: 176px;
219
+ width: 320px;
220
+ height: 320px;
221
221
  border: 1px solid #d7dee8;
222
222
  border-radius: 6px;
223
223
  background: #fff;
224
224
  }
225
225
 
226
+ #mobile-qr-status {
227
+ max-width: 320px;
228
+ text-align: center;
229
+ font-size: 12px;
230
+ color: #6b7280;
231
+ }
232
+
226
233
  .logs {
227
234
  display: grid;
228
235
  gap: 8px;