@heybox/hb-sdk 0.1.2 → 0.2.0-alpha.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.
Files changed (49) hide show
  1. package/README.md +172 -39
  2. package/bin/hb-sdk.cjs +3 -0
  3. package/dist/cli.cjs +9639 -0
  4. package/dist/devtools/mock-host/index.html +626 -0
  5. package/dist/index.cjs.js +513 -83
  6. package/dist/index.esm.js +499 -78
  7. package/dist/protocol.cjs.js +104 -0
  8. package/dist/protocol.esm.js +90 -0
  9. package/dist/templates/vue3-vite-ts/.gitignore.ejs +5 -0
  10. package/dist/templates/vue3-vite-ts/README.md.ejs +46 -0
  11. package/dist/templates/vue3-vite-ts/index.html.ejs +12 -0
  12. package/dist/templates/vue3-vite-ts/package.json.ejs +29 -0
  13. package/dist/templates/vue3-vite-ts/src/App.vue +63 -0
  14. package/dist/templates/vue3-vite-ts/src/__tests__/App.spec.ts +67 -0
  15. package/dist/templates/vue3-vite-ts/src/main.ts +5 -0
  16. package/dist/templates/vue3-vite-ts/src/styles.css +60 -0
  17. package/dist/templates/vue3-vite-ts/src/vite-env.d.ts +1 -0
  18. package/dist/templates/vue3-vite-ts/tsconfig.app.json +17 -0
  19. package/dist/templates/vue3-vite-ts/tsconfig.json +11 -0
  20. package/dist/templates/vue3-vite-ts/tsconfig.node.json +11 -0
  21. package/dist/templates/vue3-vite-ts/vite.config.ts +6 -0
  22. package/dist/templates/vue3-vite-ts/vitest.config.ts +10 -0
  23. package/package.json +28 -5
  24. package/types/core/client.d.ts +27 -4
  25. package/types/core/errors.d.ts +45 -2
  26. package/types/core/sdk.d.ts +78 -10
  27. package/types/core/singleton.d.ts +33 -7
  28. package/types/core/utils.d.ts +2 -0
  29. package/types/index.d.ts +10 -4
  30. package/types/modules/auth/index.d.ts +42 -0
  31. package/types/modules/network/index.d.ts +125 -0
  32. package/types/modules/share/index.d.ts +12 -2
  33. package/types/modules/share/screenshot.d.ts +14 -2
  34. package/types/modules/share/show-share-menu.d.ts +14 -2
  35. package/types/modules/share/types.d.ts +24 -4
  36. package/types/modules/storage/index.d.ts +70 -0
  37. package/types/modules/user/get-info.d.ts +11 -1
  38. package/types/modules/user/index.d.ts +13 -9
  39. package/types/modules/user/types.d.ts +1 -0
  40. package/types/modules/viewport/index.d.ts +78 -0
  41. package/types/protocol/guards.d.ts +6 -1
  42. package/types/protocol/types.d.ts +19 -4
  43. package/types/protocol.d.ts +18 -0
  44. package/types/modules/system/get-storage.d.ts +0 -15
  45. package/types/modules/system/get-window-info.d.ts +0 -16
  46. package/types/modules/system/index.d.ts +0 -23
  47. package/types/modules/system/set-storage.d.ts +0 -12
  48. package/types/modules/system/types.d.ts +0 -34
  49. package/types/modules/user/login.d.ts +0 -18
package/README.md CHANGED
@@ -1,24 +1,27 @@
1
1
  # @heybox/hb-sdk
2
2
 
3
- 面向黑盒外部小程序 iframe 沙盒的前端 SDK。它负责与父容器完成握手、收发 bridge 消息,并以受控模块的形式向外部小程序开放用户、分享、系统信息和隔离 storage 能力。
3
+ 面向黑盒外部小程序 iframe 沙盒的前端 SDK。它负责与父容器完成握手、收发 bridge 消息,并以受控模块的形式向外部小程序开放授权、用户、分享、视口、隔离 storage 与网络请求能力。
4
4
 
5
5
  ## 为什么需要它
6
6
 
7
7
  外部小程序运行在父容器创建的 iframe 沙盒中,业务页面不能直接读取主站登录态,也不应该关心底层 `postMessage` 协议、nonce 校验、请求响应关联、超时清理、客户端协议参数过滤等细节。
8
8
 
9
- `@heybox/hb-sdk` 将这些通信细节封装为稳定接口,让小程序只通过被允许的能力访问父容器。父容器仍负责调用黑盒客户端协议,并在运行时过滤不适合开放给外部小程序的内部参数。
9
+ `@heybox/hb-sdk` 将这些通信细节封装为稳定接口,让小程序只通过被允许的能力访问父容器。父容器仍负责调用黑盒客户端协议,并在运行时过滤不适合开放给外部小程序的内部参数。网络请求能力同样遵循这个边界:SDK 提供 axios-like 的窄接口,运行时负责协议映射。
10
10
 
11
11
  ## 当前对外导出
12
12
 
13
13
  > 以 `src/index.ts` 为准;历史目录、旧示例或构建产物若与当前入口不一致,以当前源码导出能力为准。
14
14
 
15
- - 默认导出 `hbSDK`:包含 `ready`、`on`、`off`、`user`、`share`、`system`。
16
- - 命名导出 `ready` / `on` / `off` / `user` / `share` / `system`:默认 SDK 单例能力。
15
+ - 默认导出 `hbSDK`:包含 `ready`、`on`、`off`、`auth`、`user`、`share`、`viewport`、`storage`、`network`。
16
+ - 命名导出 `ready` / `on` / `off` / `auth` / `user` / `share` / `viewport` / `storage` / `network`:默认 SDK 单例能力。
17
17
  - `createMiniProgramSDK` / `MiniProgramSDK`:创建独立 SDK 实例,适合测试、多实例或显式生命周期管理场景。
18
- - `HbMiniProgramSDKError`:SDK 对外抛出的标准错误类型。
18
+ - `HbMiniProgramSDKError`:bridge / 运行时 / 协议失败时的标准错误类型。
19
+ - `HbMiniProgramNetworkError`:HTTP 已完成但未通过 SDK `validateStatus` 校验时的网络错误类型。
19
20
  - `MiniProgramRequester` / `MiniProgramSDKOptions`:底层请求与 SDK 初始化配置类型。
20
- - bridge 协议常量、类型与守卫:`MINI_PROGRAM_MESSAGE_NAMESPACE`、`MINI_PROGRAM_MESSAGE_VERSION`、`MINI_PROGRAM_BRIDGE_NONCE_PARAM`、`SDK_HANDSHAKE_METHOD`、`isMiniProgramBridgeMessage` 等。
21
- - 模块类型与方法常量:`MiniProgramUserModule`、`MiniProgramShareModule`、`MiniProgramSystemModule` 以及各模块 method 常量。
21
+ - bridge 协议常量、类型与守卫:根入口保留导出;运行时等宿主侧包应优先从 `@heybox/hb-sdk/protocol` 子入口导入,避免误依赖 SDK core / singleton。
22
+ - 模块类型与方法常量:`MiniProgramAuthModule`、`MiniProgramUserModule`、`MiniProgramShareModule`、`MiniProgramViewportModule`、`MiniProgramStorageModule`、`MiniProgramNetworkModule` 以及各模块 method 常量。
23
+
24
+ > 本版本为破坏性模块重排:登录归属 `auth`,窗口归属 `viewport`,存储归属 `storage`;旧的 `user.login()` 与 `system.*` 入口已移除。
22
25
 
23
26
  ## 快速开始
24
27
 
@@ -52,10 +55,18 @@ const currentUser = await user.getInfo();
52
55
  unsubscribe();
53
56
  ```
54
57
 
55
- 分享与 storage
58
+ 分享、storage 与 network
56
59
 
57
60
  ```ts
58
- import { share, system } from '@heybox/hb-sdk';
61
+ import { network, share, storage } from '@heybox/hb-sdk';
62
+
63
+ const response = await network.request<{ ok: boolean }>({
64
+ url: 'https://api.example.com/demo',
65
+ method: 'GET',
66
+ });
67
+
68
+ console.log(response.status, response.data.ok);
69
+
59
70
 
60
71
  await share.showShareMenu({
61
72
  title: '分享标题',
@@ -64,29 +75,31 @@ await share.showShareMenu({
64
75
  imageUrl: 'https://imgheybox.max-c.com/demo.png',
65
76
  });
66
77
 
67
- await system.setStorage({
78
+ await storage.setStorage({
68
79
  key: 'settings',
69
80
  data: {
70
81
  theme: 'dark',
71
82
  },
72
83
  });
73
84
 
74
- const { data } = await system.getStorage<{ theme: string }>({
85
+ const { data } = await storage.getStorage<{ theme: string }>({
75
86
  key: 'settings',
76
87
  });
77
88
  ```
78
89
 
90
+ 网络请求默认只把 `2xx` 视为成功;`4xx/5xx` 这类已完成 HTTP 响应会在 SDK 模块层抛出 `HbMiniProgramNetworkError`,而 bridge / 运行时 / 协议失败仍然抛出 `HbMiniProgramSDKError`。`validateStatus` 仅在 SDK 本地执行,不会把函数值透传给父容器。
91
+
79
92
  ## 核心概念
80
93
 
81
94
  ### 默认单例
82
95
 
83
- 普通小程序页面优先使用默认导出的 `hbSDK`,或直接按需导入 `ready`、`on`、`off`、`user`、`share`、`system`。默认单例会在首次调用时懒创建,业务不需要手动初始化。
96
+ 普通小程序页面优先使用默认导出的 `hbSDK`,或直接按需导入 `ready`、`on`、`off`、`auth`、`user`、`share`、`viewport`、`storage`。默认单例会在首次调用时懒创建,业务不需要手动初始化。
84
97
 
85
98
  ```ts
86
- import { ready, system } from '@heybox/hb-sdk';
99
+ import { ready, viewport } from '@heybox/hb-sdk';
87
100
 
88
101
  await ready();
89
- const windowInfo = await system.getWindowInfo();
102
+ const windowInfo = await viewport.getWindowInfo();
90
103
  ```
91
104
 
92
105
  ### 独立实例
@@ -102,7 +115,7 @@ const sdk = createMiniProgramSDK({
102
115
 
103
116
  await sdk.ready();
104
117
 
105
- const loginResult = await sdk.user.login();
118
+ const loginResult = await sdk.auth.login();
106
119
 
107
120
  sdk.destroy();
108
121
  ```
@@ -112,20 +125,23 @@ sdk.destroy();
112
125
  SDK 与父容器之间通过 `postMessage` 通信,消息会带上固定命名空间、协议版本与 iframe 实例 nonce。SDK 内部负责:
113
126
 
114
127
  - 从 URL query 读取 `hb_mini_bridge_nonce`,也支持通过 `MiniProgramSDKOptions.nonce` 显式传入。
115
- - 向父容器发送 `sdk.handshake` 握手消息,并等待 `ready` 事件。
128
+ - 支持通过 `MiniProgramSDKOptions.targetOrigin` 显式指定发往父容器的 `postMessage targetOrigin`;未传时会尝试推断父容器 origin,失败则兼容回退为 `*`。
129
+ - 向父容器发送 `sdk.handshake` 握手消息;如果还没有收到 `ready` 事件,会在总超时窗口内短间隔重试。
116
130
  - 为每次能力调用生成请求 ID,匹配父容器返回的 response。
117
131
  - 过滤非小程序消息、非当前 nonce 消息以及非目标父窗口消息。
118
- - 处理请求超时、握手超时和销毁后的未完成请求。
132
+ - 处理请求超时、握手总超时和销毁后的未完成请求。
133
+
134
+ 父容器应幂等响应握手:重复 `sdk.handshake` 只代表 SDK 在补偿早期消息丢失,父容器可以重复派发 `ready`,但不应重复执行一次性启动副作用。
119
135
 
120
136
  ### 标准错误
121
137
 
122
138
  请求失败和 SDK 内部错误会统一包装为 `HbMiniProgramSDKError`,包含稳定的 `code`、面向开发者的 `message` 和可选 `data`。
123
139
 
124
140
  ```ts
125
- import { HbMiniProgramSDKError, user } from '@heybox/hb-sdk';
141
+ import { HbMiniProgramSDKError, auth } from '@heybox/hb-sdk';
126
142
 
127
143
  try {
128
- await user.login();
144
+ await auth.login();
129
145
  } catch (error) {
130
146
  if (error instanceof HbMiniProgramSDKError) {
131
147
  console.log(error.code, error.message, error.data);
@@ -142,18 +158,25 @@ try {
142
158
  | 模块 | 作用 | 代表导出 |
143
159
  | --- | --- | --- |
144
160
  | `core/sdk` | SDK 实例封装 | `MiniProgramSDK`、`createMiniProgramSDK` |
145
- | `core/singleton` | 默认单例入口 | `ready`、`on`、`off`、`user`、`share`、`system` |
161
+ | `core/singleton` | 默认单例入口 | `ready`、`on`、`off`、`auth`、`user`、`share`、`viewport`、`storage` |
146
162
  | `core/client` | bridge 握手、请求响应、事件分发 | `MiniProgramSDKOptions`、`MiniProgramRequester` |
147
163
  | `core/errors` | 标准错误类型 | `HbMiniProgramSDKError` |
148
164
 
165
+ ### Auth
166
+
167
+ 授权模块位于 `src/modules/auth`,承载登录授权类能力。
168
+
169
+ | API | 对应父容器能力 | 说明 |
170
+ | --- | --- | --- |
171
+ | `auth.login()` | `auth.login` | 唤起黑盒登录流程,并返回登录后的最新用户公开资料。 |
172
+
149
173
  ### User
150
174
 
151
- 用户模块位于 `src/modules/user`,只暴露允许小程序访问的公开用户能力。
175
+ 用户模块位于 `src/modules/user`,只暴露允许小程序访问的公开用户资料能力。
152
176
 
153
177
  | API | 说明 |
154
178
  | --- | --- |
155
179
  | `user.getInfo()` | 获取当前用户登录态与公开基础资料。未登录时不会触发登录流程。 |
156
- | `user.login()` | 唤起黑盒登录流程,并返回登录后的最新用户公开资料。 |
157
180
 
158
181
  用户信息只包含允许暴露给外部小程序的公开字段:
159
182
 
@@ -172,6 +195,42 @@ interface MiniProgramUserInfoResult {
172
195
 
173
196
  SDK 不会向小程序暴露 token、cookie、手机号或任何可用于直接调用主站私有接口的凭据。
174
197
 
198
+ ### Network
199
+
200
+ 网络模块位于 `src/modules/network`,提供一个窄化的 axios-like `network.request()` 接口。SDK 只暴露公共请求字段,父容器运行时负责把这些字段映射到实际协议。
201
+
202
+ | API | 对应父容器能力 | 说明 |
203
+ | --- | --- | --- |
204
+ | `network.request(config)` | `network.request` | 发起网络请求;默认仅 `2xx` 视为成功。 |
205
+
206
+ ```ts
207
+ interface MiniProgramNetworkRequestConfig {
208
+ url: string;
209
+ method?: string;
210
+ params?: Record<string, unknown>;
211
+ data?: unknown;
212
+ headers?: Record<string, string>;
213
+ timeout?: number;
214
+ withCredentials?: boolean;
215
+ validateStatus?: (status: number) => boolean;
216
+ }
217
+
218
+ interface MiniProgramNetworkResponse<T = unknown> {
219
+ data: T;
220
+ status: number;
221
+ statusText?: string;
222
+ headers: Record<string, string>;
223
+ config: MiniProgramNetworkRequestConfig;
224
+ }
225
+ ```
226
+
227
+ 约束说明:
228
+
229
+ - `validateStatus` 只在 SDK 本地执行,不会跨 bridge 传输函数。
230
+ - `config` 是 SDK 公共请求配置快照,不包含任何原始 `sendRequestV2` 字段。
231
+ - 公开响应头为 `Record<string, string>`;无法可靠解析时应视为 `{}`。
232
+ - v1 不提供原始协议字段、回调函数、拦截器或上传下载进度等高级能力。
233
+
175
234
  ### Share
176
235
 
177
236
  分享模块位于 `src/modules/share`,对外提供简洁配置,父容器侧再映射到黑盒客户端协议。
@@ -210,15 +269,13 @@ interface MiniProgramScreenshotOptions {
210
269
 
211
270
  为了保持外部 API 稳定,`share` 模块不开放 raw protocol、JS callback、活动上报、发帖、自定义按钮、upload-only 等内部能力。
212
271
 
213
- ### System
272
+ ### Viewport
214
273
 
215
- 系统模块位于 `src/modules/system`,当前提供窗口信息与隔离 storage 能力。
274
+ Viewport 模块位于 `src/modules/viewport`,承载窗口、视口和安全区域相关能力。
216
275
 
217
276
  | API | 对应父容器能力 | 说明 |
218
277
  | --- | --- | --- |
219
- | `system.getWindowInfo()` | `system.getWindowInfo` | 获取窗口、屏幕、安全区域等信息。 |
220
- | `system.getStorage(options)` | `system.getStorage` -> `getStorage` 协议 | 读取小程序隔离 storage。 |
221
- | `system.setStorage(options)` | `system.setStorage` -> `setStorage` 协议 | 写入小程序隔离 storage。 |
278
+ | `viewport.getWindowInfo()` | `viewport.getWindowInfo` | 获取窗口、屏幕、安全区域等信息。 |
222
279
 
223
280
  `getWindowInfo()` 返回字段对齐微信小程序 `wx.getWindowInfo` 的常用字段:
224
281
 
@@ -242,17 +299,26 @@ interface MiniProgramWindowInfoResult {
242
299
  }
243
300
  ```
244
301
 
302
+ ### Storage
303
+
304
+ Storage 模块位于 `src/modules/storage`,承载小程序隔离存储能力。
305
+
306
+ | API | 对应父容器能力 | 说明 |
307
+ | --- | --- | --- |
308
+ | `storage.getStorage(options)` | `storage.getStorage` -> `getStorage` 协议 | 读取小程序隔离 storage。 |
309
+ | `storage.setStorage(options)` | `storage.setStorage` -> `setStorage` 协议 | 写入小程序隔离 storage。 |
310
+
245
311
  storage API:
246
312
 
247
313
  ```ts
248
- await system.setStorage({
314
+ await storage.setStorage({
249
315
  key: 'settings',
250
316
  data: {
251
317
  enabled: true,
252
318
  },
253
319
  });
254
320
 
255
- const result = await system.getStorage<{ enabled: boolean }>({
321
+ const result = await storage.getStorage<{ enabled: boolean }>({
256
322
  key: 'settings',
257
323
  });
258
324
  ```
@@ -295,10 +361,10 @@ renderUser(result.userInfo);
295
361
  ### 场景 2:点击按钮唤起登录
296
362
 
297
363
  ```ts
298
- import { user } from '@heybox/hb-sdk';
364
+ import { auth } from '@heybox/hb-sdk';
299
365
 
300
366
  async function handleLoginClick() {
301
- const result = await user.login();
367
+ const result = await auth.login();
302
368
 
303
369
  if (result.isLogin) {
304
370
  renderUser(result.userInfo);
@@ -351,9 +417,9 @@ await share.screenshot({
351
417
  ### 场景 5:读取窗口信息
352
418
 
353
419
  ```ts
354
- import { system } from '@heybox/hb-sdk';
420
+ import { viewport } from '@heybox/hb-sdk';
355
421
 
356
- const windowInfo = await system.getWindowInfo();
422
+ const windowInfo = await viewport.getWindowInfo();
357
423
 
358
424
  console.log(windowInfo.windowWidth, windowInfo.windowHeight, windowInfo.safeArea.top);
359
425
  ```
@@ -361,16 +427,16 @@ console.log(windowInfo.windowWidth, windowInfo.windowHeight, windowInfo.safeArea
361
427
  ### 场景 6:使用隔离 storage
362
428
 
363
429
  ```ts
364
- import { system } from '@heybox/hb-sdk';
430
+ import { storage } from '@heybox/hb-sdk';
365
431
 
366
- await system.setStorage({
432
+ await storage.setStorage({
367
433
  key: 'card_mode',
368
434
  data: {
369
435
  enabled: true,
370
436
  },
371
437
  });
372
438
 
373
- const { data } = await system.getStorage<{ enabled: boolean }>({
439
+ const { data } = await storage.getStorage<{ enabled: boolean }>({
374
440
  key: 'card_mode',
375
441
  });
376
442
 
@@ -426,20 +492,87 @@ await sdk.ready();
426
492
  sdk.destroy();
427
493
  ```
428
494
 
495
+ ## 与 `@heybox/hb-sdk-runtime` 的关系与兼容矩阵
496
+
497
+ `@heybox/hb-sdk` 是 iframe 内部使用的客户端 SDK,`@heybox/hb-sdk-runtime` 是 iframe 外部宿主壳层使用的运行时实现。当前仓库选择将 **协议 / 契约相关内容继续维护在 `@heybox/hb-sdk` 内部**,而不是额外拆出一个 contract 包,以减少包数量、发布面和维护成本。
498
+
499
+ 约定如下:
500
+
501
+ - `@heybox/hb-sdk-runtime` 可以依赖 `@heybox/hb-sdk` 中的 **协议常量、类型、消息守卫** 等契约层内容。
502
+ - `@heybox/hb-sdk-runtime` **不应依赖** `@heybox/hb-sdk` 的 `core/*`、默认单例、客户端请求实现等客户端运行时逻辑。
503
+ - 协议变更时,`@heybox/hb-sdk` 与 `@heybox/hb-sdk-runtime` 应按一组联动能力来评审和发布,而不是分别独立演进。
504
+
505
+ ### 兼容矩阵(当前约定)
506
+
507
+ | `@heybox/hb-sdk` | `@heybox/hb-sdk-runtime` | 说明 |
508
+ | --- | --- | --- |
509
+ | 同一仓库主线版本 | 同一仓库主线版本 | 默认开发模式,按同一批次代码联动验证 |
510
+ | 仅补丁级变更 | 仅补丁级变更 | 允许,但必须保持协议常量、消息结构、事件名和 payload 兼容 |
511
+ | 协议字段 / 方法名 / 事件名变更 | 需要同步升级 | 不允许单边发布后假定另一侧自动兼容 |
512
+
513
+ ### 后续 CI 兼容性检查(待补)
514
+
515
+ 后续补 CI 时,至少应增加以下检查:
516
+
517
+ 1. **依赖边界检查**
518
+ - 禁止 `@heybox/hb-sdk-runtime` 引用 `@heybox/hb-sdk/core/*`、默认单例或客户端实现层。
519
+ - 只允许引用协议 / 契约层入口(例如 `@heybox/hb-sdk/protocol`)。
520
+ 2. **协议兼容性检查**
521
+ - 当 `MINI_PROGRAM_MESSAGE_*` 常量、事件名、方法名、payload 类型变更时,要求 `hb-sdk` 与 `hb-sdk-runtime` 相关测试同时通过。
522
+ 3. **联动验证检查**
523
+ - 至少跑一组 `hb-sdk` 单测 + `hb-sdk-runtime` 单测,确保客户端与宿主运行时没有单边漂移。
524
+ 4. **导出面检查**
525
+ - 若协议层导出发生调整,CI 需提醒评审同步检查 runtime 使用面,而不是默认为向后兼容。
526
+
429
527
  ## 能力边界与注意事项
430
528
 
431
529
  - SDK 只能在父容器创建的小程序 iframe 沙盒中正常完成握手;非 iframe 环境会抛出 `NOT_IN_IFRAME`。
432
530
  - 父容器必须在小程序 URL 上注入 `hb_mini_bridge_nonce`,否则会抛出 `MISSING_NONCE`。
531
+ - 父容器需要幂等响应 `sdk.handshake`;SDK 会在收到 `ready` 前自动重试握手,不引用 SDK 的普通页面不会触发握手。
433
532
  - 调用模块能力前会自动等待 `ready()`,但业务仍建议在页面启动阶段显式 `await ready()`,便于集中处理握手失败。
434
533
  - `user.getInfo()` 只查询登录态,不会主动唤起登录。
435
- - `user.login()` 只返回公开用户资料,不返回 token、cookie 或私有凭据。
534
+ - `auth.login()` 只返回公开用户资料,不返回 token、cookie 或私有凭据。
436
535
  - `share.showShareMenu()` 只开放基础分享字段,不开放活动任务上报、发帖、自定义按钮等内部协议参数。
437
536
  - `share.screenshot()` 只做截图并分享,不开放 upload-only 和客户端 JS callback。
438
- - `system.getWindowInfo()` 的 `statusBarHeight`、`screenTop`、`safeArea.top` 在黑盒容器内按顶部可用偏移处理。
439
- - `system.getStorage()` / `system.setStorage()` 只访问小程序隔离 storage;业务 key 必须符合 `/^[A-Za-z0-9_-]{1,128}$/`。
537
+ - `viewport.getWindowInfo()` 的 `statusBarHeight`、`screenTop`、`safeArea.top` 在黑盒容器内按顶部可用偏移处理。
538
+ - `storage.getStorage()` / `storage.setStorage()` 只访问小程序隔离 storage;业务 key 必须符合 `/^[A-Za-z0-9_-]{1,128}$/`。
440
539
  - `on()` 会返回取消监听函数;页面卸载或组件销毁时应及时取消监听。
441
540
  - 独立实例不再使用时应调用 `destroy()`,以移除 message 监听并拒绝未完成请求。
442
541
 
542
+ ## CLI 创建外部小程序模板
543
+
544
+ `hb-sdk create <project-name>` 会生成一个外部独立小程序开发模板,默认使用 Vue 3、Vite、TypeScript 和 npm。
545
+
546
+ ```bash
547
+ hb-sdk create my-miniapp
548
+ cd my-miniapp
549
+ npm install
550
+ npm run dev:mock
551
+ ```
552
+
553
+ 生成规则:
554
+
555
+ - `project-name` 同时作为项目目录名和 `package.json` 的 `name`,必须是合法的非 scoped npm 包名,例如 `my-miniapp`。
556
+ - 目标目录不存在时会自动创建;目标目录已存在但非空时会拒绝覆盖。
557
+ - CLI 只生成文件,不会自动安装依赖、初始化 git 或打开编辑器。
558
+ - 模板内置轻量 SDK 能力演示页和 Vitest 单测配置;`npm run dev:mock` 会启动本地 Vite 服务和 hb-sdk mock runtime host。
559
+
560
+ ## CLI 登录态
561
+
562
+ `hb-sdk` CLI 内置 Heybox 浏览器登录流,登录态只保存在 `hb-sdk` 自己的本地缓存命名空间里,供 `hb-sdk` CLI 命令内部调用 Heybox 接口时复用。
563
+
564
+ ```bash
565
+ hb-sdk login
566
+ hb-sdk login status
567
+ hb-sdk login clear
568
+ ```
569
+
570
+ - `hb-sdk login` 会打开 `login.xiaoheihe.cn`,通过本地临时回调服务接收登录结果。
571
+ - `hb-sdk login status` 只展示脱敏状态、`heyboxId`、登录时间和 cache 路径,不输出 `pkey`、cookie 或完整请求头。
572
+ - `hb-sdk login clear` 只清理 `hb-sdk` 自己命名空间中的 Heybox 登录态。
573
+
574
+ 这份 CLI 登录态不会注入 iframe SDK,也不会改变 `hb-sdk dev --mock` 的 mock 用户、`auth.login()`、`user.getInfo()` 或 `network.request()` 行为。
575
+
443
576
  ## 开发命令
444
577
 
445
578
  优先使用仓库统一的 `hbexec` 入口:
package/bin/hb-sdk.cjs ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ require('../dist/cli.cjs');