@heybox/hb-sdk 0.8.2-alpha.5 → 0.8.2-alpha.6

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 (40) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +5 -2
  3. package/dist/cli-chunks/{build-D2T3ky_9.cjs → build-TOcahJhW.cjs} +5 -5
  4. package/dist/cli-chunks/{context-DEgmdpSL.cjs → context-Bk0adtVQ.cjs} +2 -2
  5. package/dist/cli-chunks/{create-DKqQhrG5.cjs → create-BxIgQ4SF.cjs} +1 -1
  6. package/dist/cli-chunks/{dev-BEXM7cmq.cjs → dev-CyhKTGGJ.cjs} +9 -9
  7. package/dist/cli-chunks/{doctor-B7UixGrd.cjs → doctor-ItlNn-K2.cjs} +25 -13
  8. package/dist/cli-chunks/{index-BtwfuoWI.cjs → index-CP14FXez.cjs} +16 -16
  9. package/dist/cli-chunks/{index-C69OtRug.cjs → index-CjWRMwuI.cjs} +2 -2
  10. package/dist/cli-chunks/{index.esm-C86KlVdK.cjs → index.esm-deP-KEyE.cjs} +7 -7
  11. package/dist/cli-chunks/{login-Bp_HMx-i.cjs → login-4B-2nqgd.cjs} +2 -2
  12. package/dist/cli-chunks/{project-vite-DZxipd13.cjs → project-vite-HKW4tSBX.cjs} +1 -1
  13. package/dist/cli-chunks/{remote-B_sVsbQP.cjs → remote-BLdGzViG.cjs} +7 -7
  14. package/dist/cli-chunks/{runtime-gate-GR9jZd37.cjs → runtime-gate-B_fHNic6.cjs} +1 -1
  15. package/dist/cli-chunks/{runtime-permission-env-COWketgE.cjs → runtime-permission-env-CAhESVDA.cjs} +1 -1
  16. package/dist/cli-chunks/{session-6-AApcTZ.cjs → session-COr9TQ6O.cjs} +1 -1
  17. package/dist/cli-chunks/{skill-CPDLk7t7.cjs → skill-DiZSczbw.cjs} +2 -2
  18. package/dist/cli-chunks/{version-hHrSPRwW.cjs → version-tRrcrp9F.cjs} +1 -1
  19. package/dist/cli.cjs +1 -1
  20. package/dist/devtools/browser-dev-host/assets/{browser-dev-host-CpwQQhA1.js → browser-dev-host-CF7IQARw.js} +1 -1
  21. package/dist/devtools/browser-dev-host/assets/{desktop-app-launch-BdWBOIvY.js → desktop-app-launch-CQmXIMyL.js} +1 -1
  22. package/dist/devtools/browser-dev-host/assets/{index-BQSEynx6.js → index-DdKYO0um.js} +3 -3
  23. package/dist/devtools/browser-dev-host/index.html +2 -2
  24. package/dist/index.cjs.js +1 -1
  25. package/dist/index.esm.js +1 -1
  26. package/dist/templates/vanilla-vite-js/README.md.ejs +3 -0
  27. package/dist/vite.cjs.js +1 -1
  28. package/dist/vite.esm.js +1 -1
  29. package/package.json +7 -7
  30. package/skill/SKILL.md +22 -128
  31. package/skill/skill.json +5 -5
  32. package/types/skill-metadata.d.ts +2 -2
  33. package/skill/references/api-protocol.md +0 -317
  34. package/skill/references/api-root.md +0 -1244
  35. package/skill/references/cli.md +0 -401
  36. package/skill/references/examples.md +0 -204
  37. package/skill/references/llms-index.md +0 -24
  38. package/skill/references/recipes.md +0 -855
  39. package/skill/references/safety-boundaries.md +0 -63
  40. package/skill/references/smoke-evaluation.md +0 -26
@@ -1,1244 +0,0 @@
1
- # Root API reference
2
-
3
- > Generated by `node packages/hb-sdk/scripts/skill/sync-references.mjs` from the public hb-sdk source/docs. Do not edit by hand; update sources or this generator instead.
4
-
5
- ## Sources
6
-
7
- - packages/hb-sdk/package.json
8
- - packages/hb-sdk/src/index.ts
9
- - packages/hb-sdk/src/vite/index.ts
10
- - packages/hb-sdk/README.md
11
- - apps/docs/hb-sdk/guide/quick-start.md
12
- - apps/docs/hb-sdk/guide/environment.md
13
- - apps/docs/hb-sdk/guide/error-handling.md
14
- - apps/docs/hb-sdk/guide/lifecycle.md
15
- - apps/docs/hb-sdk/guide/companion.md
16
- - apps/docs/hb-sdk/guide/cli.md
17
-
18
- ## Contents
19
-
20
- - [Package metadata](#package-metadata)
21
- - [Public root entrypoint](#public-root-entrypoint)
22
- - [Vite plugin export](#vite-plugin-export)
23
- - [Project declarations](#project-declarations)
24
- - [App-facing concepts](#app-facing-concepts)
25
- - [Environment info](#environment-info)
26
- - [Public modules](#public-modules)
27
- - [Cloud leaderboard](#cloud-leaderboard)
28
- ## Package metadata
29
-
30
- - Package: `@heybox/hb-sdk`
31
- - Version at generation time: `0.8.2-alpha.5`
32
- - Public root export: `@heybox/hb-sdk`
33
- - Protocol export: `@heybox/hb-sdk/protocol`
34
- - Vite plugin export: `@heybox/hb-sdk/vite`
35
-
36
- ## Public root entrypoint
37
-
38
- ```ts
39
- export { HbMiniProgramSDKError, HbMiniProgramNetworkError } from './core/errors';
40
- export {
41
- getHandshakeState,
42
- onHandshakeStateChange,
43
- on,
44
- off,
45
- auth,
46
- user,
47
- share,
48
- viewport,
49
- storage,
50
- files,
51
- network,
52
- ui,
53
- device,
54
- environment,
55
- navigation,
56
- cloud,
57
- companion,
58
- } from './core/singleton';
59
- export type { MiniProgramSDKHandshakeState, MiniProgramSDKHandshakeStateHandler } from './core/handshake-state';
60
- export type { MiniProgramEventHandler, MiniProgramEventName, MiniProgramEventPayloadMap } from './protocol/types';
61
- export type { LoginOptions, LoginPayload, LoginResult, LoginScope, MiniProgramAuthModule } from './modules/auth';
62
- export type {
63
- CompanionAttachments,
64
- CompanionCapability,
65
- CompanionExit,
66
- CompanionExitHandler,
67
- CompanionInfo,
68
- CompanionNotification,
69
- CompanionNotificationCategory,
70
- CompanionNotifications,
71
- CompanionOutputHandler,
72
- CompanionOwnershipLostHandler,
73
- CompanionPreparationStatus,
74
- CompanionPrepareOptions,
75
- CompanionPrepareProgress,
76
- CompanionSession,
77
- CompanionStdio,
78
- CompanionState,
79
- CompanionStateChangeHandler,
80
- CompanionTarget,
81
- MiniProgramCompanionModule,
82
- } from './modules/companion';
83
- export type {
84
- DeleteCurrentUserLeaderboardEntryPayload,
85
- DeleteCurrentUserLeaderboardEntryResult,
86
- GetCurrentUserLeaderboardEntryPayload,
87
- GetCurrentUserLeaderboardEntryResult,
88
- GetLeaderboardInfoPayload,
89
- GetLeaderboardInfoResult,
90
- GetLeaderboardListPayload,
91
- GetLeaderboardListResult,
92
- LeaderboardEntry,
93
- LeaderboardOrder,
94
- MiniProgramCloudLeaderboardModule,
95
- MiniProgramCloudModule,
96
- SubmitLeaderboardEntryPayload,
97
- SubmitLeaderboardEntryResult,
98
- } from './modules/cloud';
99
- export type {
100
- AuthorizedUserInfo,
101
- GetUserInfoPayload,
102
- GetUserInfoResult,
103
- RevokeAuthorizationPayload,
104
- RevokeAuthorizationResult,
105
- GetSteamGameListOptions,
106
- GetSteamGameListPayload,
107
- GetSteamGameListResult,
108
- MiniProgramUserInfoResult,
109
- MiniProgramUserModule,
110
- UserInfoAuthorization,
111
- UserInfoAuthorizationStatus,
112
- SteamGameListData,
113
- SteamGameListItem,
114
- SteamGamePrice,
115
- SteamGameListSort,
116
- } from './modules/user';
117
- export { USER_INFO_AUTHORIZATION_SCOPES } from './modules/user';
118
- export type { UserInfoAuthorizationScope } from './modules/user';
119
- export type {
120
- CopyLinkPayload,
121
- CopyLinkResult,
122
- MiniProgramCopyLinkOptions,
123
- MiniProgramScreenshotOptions,
124
- MiniProgramScreenshotRect,
125
- MiniProgramShareChannel,
126
- MiniProgramShareExtraValue,
127
- MiniProgramShareModule,
128
- MiniProgramSharePostOptions,
129
- MiniProgramShowShareMenuOptions,
130
- ScreenshotPayload,
131
- ScreenshotResult,
132
- ShowShareMenuPayload,
133
- ShowShareMenuResult,
134
- } from './modules/share';
135
- export type {
136
- GetWindowInfoPayload,
137
- GetWindowInfoResult,
138
- MiniProgramNavigationBarForegroundStyle,
139
- MiniProgramSafeArea,
140
- MiniProgramSetNavigationBarStyleOptions,
141
- MiniProgramViewportModule,
142
- MiniProgramWindowInfoResult,
143
- SetNavigationBarStylePayload,
144
- SetNavigationBarStyleResult,
145
- } from './modules/viewport';
146
- export type { GetStoragePayload, GetStorageResult, MiniProgramStorageModule, SetStoragePayload } from './modules/storage';
147
- export type {
148
- DownloadBaseOptions,
149
- DownloadOptions,
150
- DownloadProgress,
151
- MiniProgramNetworkHeaders,
152
- MiniProgramNetworkModule,
153
- MiniProgramNetworkParams,
154
- MiniProgramNetworkRequestConfig,
155
- MiniProgramNetworkRequestMethod,
156
- MiniProgramNetworkResponse,
157
- MiniProgramNetworkValidateStatus,
158
- NetworkRequestPayload,
159
- NetworkResponsePayload,
160
- } from './modules/network';
161
- export type {
162
- CreateOptions,
163
- DirectoryHandle,
164
- FileHandle,
165
- FileMode,
166
- FileStat,
167
- FileSystem,
168
- FileSystemEntity,
169
- FilesModule,
170
- ListOptions,
171
- PathRoot,
172
- PickDirectoryOptions,
173
- PickFilesOptions,
174
- RemoveOptions,
175
- SaveFileOptions,
176
- } from './modules/files';
177
- export type {
178
- HideLoadingPayload,
179
- HideLoadingResult,
180
- MiniProgramToastStatus,
181
- MiniProgramUiModule,
182
- ShowLoadingPayload,
183
- ShowLoadingResult,
184
- ShowToastPayload,
185
- ShowToastResult,
186
- } from './modules/ui';
187
- export type {
188
- MiniProgramDeviceModule,
189
- MiniProgramVibrateIntensity,
190
- SetClipboardPayload,
191
- SetClipboardResult,
192
- VibratePayload,
193
- VibrateResult,
194
- } from './modules/device';
195
- export type {
196
- MiniProgramEnvironmentInfo,
197
- MiniProgramEnvironmentModule,
198
- MiniProgramOperatingSystemName,
199
- MiniProgramRuntimeMode,
200
- } from './modules/environment';
201
- export type {
202
- ClosePayload,
203
- CloseResult,
204
- MiniProgramAppPageTarget,
205
- MiniProgramGameDetailGameType,
206
- MiniProgramGameDetailPage,
207
- MiniProgramNavigationModule,
208
- OpenAppPageOptions,
209
- OpenAppPagePayload,
210
- OpenAppPageResult,
211
- OpenGameDetailAppPagePayload,
212
- OpenGameDetailAppPageOptions,
213
- OpenPostDetailAppPagePayload,
214
- OpenPostDetailAppPageOptions,
215
- OpenUserDetailAppPagePayload,
216
- OpenUserDetailAppPageOptions,
217
- ReloadPayload,
218
- ReloadResult,
219
- } from './modules/navigation';
220
-
221
- import {
222
- auth,
223
- cloud,
224
- companion,
225
- device,
226
- environment,
227
- getHandshakeState,
228
- navigation,
229
- network,
230
- off,
231
- on,
232
- onHandshakeStateChange,
233
- share,
234
- storage,
235
- files,
236
- ui,
237
- viewport,
238
- user,
239
- } from './core/singleton';
240
-
241
- const hbSDK = {
242
- getHandshakeState,
243
- onHandshakeStateChange,
244
- on,
245
- off,
246
- auth,
247
- user,
248
- share,
249
- viewport,
250
- storage,
251
- files,
252
- network,
253
- ui,
254
- device,
255
- environment,
256
- navigation,
257
- cloud,
258
- companion,
259
- };
260
-
261
- export default hbSDK;
262
- ```
263
-
264
- ## Vite plugin export
265
-
266
- Use `@heybox/hb-sdk/vite` only in `vite.config.ts`. Do not import it from iframe mini-program business code.
267
-
268
- ````ts
269
- /**
270
- * {@link miniappManifest} 返回的 Vite 插件契约。
271
- *
272
- * @remarks
273
- * 业务项目只需把 `miniappManifest()` 放入 `vite.config.ts` 的 `plugins` 数组,通常不需要直接构造该接口,
274
- * 也不应手动调用这些 Vite hook。该接口不包含小程序声明;目标平台、权限、窗口、游戏绑定和 Companion
275
- * 等配置统一来自距离 Vite `root` 最近的 `package.json#heybox`。
276
- */
277
- export interface MiniappManifestPlugin {
278
- /** 固定为 `heybox-miniapp-manifest`,同一份 Vite 配置必须且只能注册一个实例。 */
279
- name: string;
280
- /** 校验资源基准路径,并向 Vite 注入 SDK 版本和开发期日志开关。 */
281
- config: (config: MiniappManifestUserConfig, env?: {
282
- command: 'build' | 'serve';
283
- }) => MiniappManifestUserConfig | void;
284
- /** 记录 Vite 根目录、输出目录、运行命令和开发期 HMR 地址。 */
285
- configResolved: (resolved: MiniappManifestResolvedConfig) => void;
286
- /** 为 `hb-sdk dev` 注册本机调试能力;生产构建不会创建开发服务。 */
287
- configureServer: (server: MiniappManifestDevServer) => void;
288
- /** 保留 Rollup/Vite 已报告的构建错误,避免产物校验用二次错误掩盖原始原因。 */
289
- buildEnd: (error?: Error) => void;
290
- /** 向入口 HTML 注入 Runtime Gate 和平台 CSP;serve 时还会加入受限的 HMR 与日志调试支持。 */
291
- transformIndexHtml: (html: string) => string;
292
- /** serve 关闭时直接完成;生产构建结束时校验单页产物并写入 Manifest 和 Companion 归档。 */
293
- closeBundle: (this: MiniappManifestPluginContext) => Promise<void>;
294
- }
295
-
296
- /**
297
- * {@link MiniappManifestPlugin.configureServer} 消费的最小 Vite 开发服务形状。
298
- *
299
- * @remarks
300
- * 这是插件返回值暴露的 hook 类型,不是 `miniappManifest()` 的配置项。业务项目应让 Vite 创建并传入服务实例。
301
- */
302
- export interface MiniappManifestDevServer {
303
- /** Vite 底层 HTTP 服务;middleware mode 或尚未监听时可能为空。 */
304
- httpServer?: Server | null;
305
- /** Vite 配置重载入口;插件会在重载期间保留当前本地调试快照。 */
306
- restart?: (forceOptimize?: boolean) => Promise<void>;
307
- /** 用于挂载 `hb-sdk dev` 本机调试中间件的 Connect middleware 容器。 */
308
- middlewares: {
309
- use: (handler: (request: IncomingMessage, response: ServerResponse, next: () => void) => void) => void;
310
- };
311
- }
312
-
313
- /**
314
- * {@link MiniappManifestPlugin.config} 读取和返回的最小 Vite 用户配置形状。
315
- *
316
- * @remarks
317
- * 该接口描述 Vite hook 数据,不是插件 options;`miniappManifest()` 必须无参调用。小程序声明请写入
318
- * `package.json#heybox`,不要写入 Vite 配置。
319
- */
320
- export interface MiniappManifestUserConfig {
321
- /**
322
- * Vite 资源基准路径。省略时插件返回 `./`;显式配置只接受空字符串或 `./`,以便版本目录内相对加载资源。
323
- */
324
- base?: string;
325
- /** 插件返回给 Vite 的编译期常量;业务项目无需通过该接口传入或覆盖。 */
326
- define?: Record<string, string>;
327
- }
328
-
329
- /** {@link MiniappManifestPlugin.closeBundle} 使用的最小 Rollup 插件上下文。 */
330
- export interface MiniappManifestPluginContext {
331
- /** 输出缺少迁移期声明等非阻断构建警告。 */
332
- warn: (message: string) => void;
333
- }
334
-
335
- /**
336
- * {@link MiniappManifestPlugin.configResolved} 消费的最小 Vite 已解析配置形状。
337
- *
338
- * @remarks
339
- * 这是 Vite 传给插件的 hook 数据,不是应用作者需要创建的 options。插件从中确定项目根目录、输出目录、
340
- * serve/build 分支和 HMR WebSocket 白名单。
341
- */
342
- export interface MiniappManifestResolvedConfig {
343
- /** Vite 项目根目录;小程序配置从该目录向上找到的最近 `package.json` 读取。 */
344
- root: string;
345
- /** `serve` 只准备本地调试,`build` 还会校验产物并生成 `manifest.json`。 */
346
- command: 'build' | 'serve';
347
- /** Vite 构建输出目录;Manifest 和 Companion 归档写入该目录。 */
348
- build: {
349
- outDir: string;
350
- };
351
- /** 开发服务网络配置,用于收窄注入 HTML 的 HMR WebSocket CSP。 */
352
- server: {
353
- host?: string | boolean;
354
- https?: boolean | Record<string, unknown>;
355
- port?: number;
356
- hmr?: boolean | {
357
- clientPort?: number;
358
- host?: string;
359
- port?: number;
360
- protocol?: 'ws' | 'wss';
361
- };
362
- };
363
- /** 已解析插件列表;存在时用于拒绝重复注册 `miniappManifest()`。 */
364
- plugins?: readonly {
365
- name?: string;
366
- }[];
367
- }
368
-
369
- /**
370
- * 创建工坊小程序使用的 Vite 插件。
371
- *
372
- * @returns 可直接加入 Vite `plugins` 数组的
373
- * [MiniappManifestPlugin](https://docs.xiaoheihe.cn/hb_sdk/reference/symbols/vite/interfaces/MiniappManifestPlugin)。插件固定名为
374
- * `heybox-miniapp-manifest`,并提供 `config`、`configResolved`、`configureServer`、`buildEnd`、
375
- * `transformIndexHtml`、`closeBundle` hooks;这些 hooks 由 Vite 调用,应用代码不应手动调用。
376
- * @throws `Error` `config` 阶段发现 Vite `base` 不是 `''` 或 `'./'`,或无法解析当前 SDK 版本时抛出。
377
- * @throws `Error` `configResolved` 阶段发现已解析插件列表中 `miniappManifest()` 数量不是一个时抛出。
378
- * @throws `Error` HTML 缺少 `<head>`,包含 `meta refresh`、`<base>`、禁止的 resource hint,或资源 URL
379
- * 不符合小程序 HTML 策略时,`transformIndexHtml` / 生产产物复检抛出。
380
- * @throws `Error` 生产构建无法读取或解析最近的 `package.json`,`version`、`heybox.platforms`、
381
- * `heybox.permissions`、`heybox.window`、`heybox.bindAppIds` 或 `heybox.companions` 声明非法时抛出。
382
- * @throws `Error` 生产 `build.outDir` 缺少根 `index.html`、递归发现额外 HTML,或 Companion 权限、
383
- * 目标平台、来源目录、归档结构、入口二进制不符合约束时抛出;更早的 Rollup/Vite 错误会原样优先重抛。
384
- *
385
- * @remarks
386
- * 该函数必须从 `@heybox/hb-sdk/vite` 导入,在 `vite.config.ts` 中无参调用且只注册一次;它不是
387
- * iframe 业务代码 API,也没有 options 对象。小程序声明统一来自从 Vite `root` 向上找到的最近一个
388
- * `package.json`,插件只读取和规范化,不会改写源文件:
389
- *
390
- * - `version`:发布版本;trim 后必须是完整 SemVer,可含 prerelease,不允许 build metadata 或模板值
391
- * `0.0.0`;
392
- * - `heybox.platforms`:项目实际承诺适配的非空、无重复平台 allowlist;输出按平台词表规范排序;
393
- * - `heybox.permissions`:严格权限对象;未知权限/字段或错误类型会失败,`enabled: false` 项不写入
394
- * Manifest。旧版本缺失声明时可能警告,新硬切版本会失败;
395
- * - `heybox.window`:可选的新 PC 开窗初值、最小尺寸和 `resizable` 声明;省略时不写该字段;
396
- * - `heybox.bindAppIds`:可选的最多 20 个正 int32 字符串 App ID;校验、去重并按数值排序,空数组
397
- * 在本地产物中等同不写;
398
- * - `heybox.companions`:可选的受管桌面程序声明;`source` 相对上述 `package.json` 所在目录解析,
399
- * 必须同时声明启用的 `companion` 权限和匹配的 Windows/macOS 目标平台。
400
- *
401
- * 产物中的 `sdkVersion` 来自当前实际安装的 `@heybox/hb-sdk`,不是项目可配置字段。Vite options、页面
402
- * 代码和普通环境变量不能覆盖上述 package 声明;插件也不会联网确认 App ID、平台批准或远端版本状态。
403
- *
404
- * Hook 行为如下:
405
- *
406
- * - `config`:省略 `base` 时补为 `'./'`,显式值只接受 `''` / `'./'`;注入 SDK 构建版本,且仅
407
- * `vite serve` 注入开发日志编译常量;
408
- * - `configResolved`:确认插件唯一性,记录真实 `root`、`build.outDir`、`serve|build` 命令和精确 HMR
409
- * WebSocket 地址;直接 `vite build` 使用该实际 `outDir`,`hb-sdk build` 则由 CLI 固定为 `dist/`;
410
- * - `configureServer`:为 `hb-sdk dev` 注册设备日志、本地小程序 Manifest 与 Companion Manifest/ZIP
411
- * 中间件;敏感路由只接受数值 loopback socket/Host、`GET|HEAD` 和 CLI 注入的独立短期令牌,快照在
412
- * 配置重载时按 digest 保留,并在服务真正关闭时清理;
413
- * - `transformIndexHtml`:校验 HTML URL/标签策略,注入 Runtime Gate;默认注入平台 CSP,serve 时
414
- * `connect-src` 只开放解析出的 HMR WebSocket,并额外注入调试日志 bootstrap;
415
- * - `buildEnd`:记住更早的 Rollup/Vite 错误,避免 `closeBundle` 的二次产物错误遮盖根因;
416
- * - `closeBundle`:serve 时直接完成;build 时复检最终 HTML,要求整个输出树只有根 `index.html`,再于
417
- * `build.outDir` 写入 `manifest.json`,并把 Companion 目录打包成
418
- * `companions/<alias>/<target>.zip`,记录 size、SHA-256、固定入口与 args。
419
- *
420
- * HTML 策略会隔离业务 script/modulepreload,直到父 Runtime Gate 以 namespace、版本、nonce、source
421
- * 以及 referrer 可确定时的 origin 完成探测;失败时显示只能在小黑盒 App 内打开的安全页。策略拒绝自动跳转、`<base>`、危险
422
- * resource hints 和不受支持的外部 URL,并按标签只允许相对 URL、明确允许的 `data:` / `blob:` 或
423
- * 小黑盒官方 HTTPS 资源。开发者自行提供的 CSP 会保留;插件管理的 CSP marker 可重复转换而不会叠加。
424
- *
425
- * 平台 CSP 默认始终保留,直接 `vite build` / `hb-sdk build` 不会因项目声明
426
- * `heybox.permissions.network.useOfficialDomain` 而跳过。只有官方 `hb-sdk dev` 或
427
- * `hb-sdk remote deploy` 将当前版本的 `network` 声明与远端批准结果求交并确认最终启用后,才会
428
- * 建立 verified 上下文供插件读取内部
429
- * `HB_SDK_RUNTIME_PERMISSION_CONTEXT` + `HB_SDK_RUNTIME_USE_OFFICIAL_DOMAIN` 组合跳过平台 CSP;单独设置
430
- * 任一值无效。0.8 兼容期对完全缺失权限声明的项目仍按迁移规则处理;`useOfficialDomain` 不参与
431
- * CSP 跳过决定。Runtime Gate、HTML 校验和 Manifest 生成始终保留。
432
- *
433
- * `HB_SDK_COMPANION_ARTIFACT_ACCESS_TOKEN`、`HB_SDK_MINI_PROGRAM_MANIFEST_ACCESS_TOKEN`、
434
- * `HB_SDK_SKIP_COMPANIONS` 以及上述 CSP 上下文均是 CLI/发布链路内部开关,不是项目配置项。它们在
435
- * 插件创建时捕获;开发服务配置重载只会从同一服务的内存快照恢复 CLI 令牌。业务代码和 Vite 配置
436
- * 不应手工设置、读取、记录或转发令牌值。正式声明必须继续写在 `package.json#heybox`,内部环境变量
437
- * 不能替代声明校验。
438
- *
439
- * `manifest.json` 是 release pipeline 元数据,不是部署后供页面 fetch 的 CDN 资源。发布链路使用
440
- * [isValidVersion](https://docs.xiaoheihe.cn/hb_sdk/reference/symbols/miniapp-publish/functions/isValidVersion) 复核版本、
441
- * [resolveMiniappManifestPlatforms](https://docs.xiaoheihe.cn/hb_sdk/reference/symbols/miniapp-publish/functions/resolveMiniappManifestPlatforms)
442
- * 解析平台硬切规则、
443
- * [parseMiniappBindAppIds](https://docs.xiaoheihe.cn/hb_sdk/reference/symbols/miniapp-publish/functions/parseMiniappBindAppIds) 复核游戏绑定,
444
- * 并通过 [shouldUploadDistFile](https://docs.xiaoheihe.cn/hb_sdk/reference/symbols/miniapp-publish/functions/shouldUploadDistFile) 将根
445
- * `manifest.json` 排除出普通 CDN 文件。Web/Companion 上传预算由
446
- * [validateUploadTotalSize](https://docs.xiaoheihe.cn/hb_sdk/reference/symbols/miniapp-publish/functions/validateUploadTotalSize) 等发布 helper
447
- * 独立校验,不能用插件成功代替 deploy 预检。
448
- *
449
- * @example
450
- * ```ts
451
- * import vue from '@vitejs/plugin-vue'
452
- * import { miniappManifest } from '@heybox/hb-sdk/vite'
453
- * import { defineConfig } from 'vite'
454
- *
455
- * export default defineConfig({
456
- * // base 省略时 miniappManifest() 会补为 './'
457
- * plugins: [vue(), miniappManifest()],
458
- * })
459
- * ```
460
- *
461
- * @see [MiniappManifestPlugin](https://docs.xiaoheihe.cn/hb_sdk/reference/symbols/vite/interfaces/MiniappManifestPlugin) 返回插件及各 hook 类型。
462
- * @see [安装](https://docs.xiaoheihe.cn/hb_sdk/guide/installation) Vite 接入、相对资源路径和构建命令。
463
- * @see [权限声明](https://docs.xiaoheihe.cn/hb_sdk/guide/permissions) `heybox.permissions` 严格 schema 与迁移规则。
464
- * @see [窗口尺寸与可缩放性](https://docs.xiaoheihe.cn/hb_sdk/guide/window-size) `heybox.window` 字段与 Host 消费语义。
465
- * @see [受管桌面程序](https://docs.xiaoheihe.cn/hb_sdk/guide/companion) Companion 声明、归档和本地联调边界。
466
- */
467
- export declare function miniappManifest(): MiniappManifestPlugin;
468
- ````
469
-
470
- ## 生产构建
471
-
472
- ```bash
473
- hb-sdk build [--env <name>] [--verbose]
474
- ```
475
-
476
- `hb-sdk build` 直接使用项目安装的 Vite,先清理再生成固定的 `dist/`,并校验小程序入口、Manifest 和可上传产物。它不执行类型检查,不要求 CLI 登录或绑定小程序,也不访问远端服务。项目必须在 `package.json#heybox.platforms` 声明目标平台,并在 `vite.config.ts` 中显式注册无参的 `miniappManifest()`;配置与构建产物不一致时构建失败。
477
-
478
- `hb-sdk remote info` 会只读展示 `package.json#heybox.bindAppIds`、当前线上绑定以及新增/移除差异。`bindAppIds` 每项必须是规范十进制字符串(拒绝前导零与空串),不超过正 int32 上限 `2147483647`,数组内不允许重复,最多 20 项;`hb-sdk build` 在构建期即校验。修改绑定必须更新项目配置并重新提交版本;CLI、Open 和 COA 都不提供第二个写入入口。普通 deploy 在上传文件前把实际构建 Manifest 交给服务端预检,提审必须重新构建。
479
-
480
- 直接运行 `hb-sdk build` 或 `vite build` 时默认注入平台 CSP。`hb-sdk remote deploy` 会在构建前读取绑定小程序的远端批准结果,并与当前版本声明取交集;仅当有效 `network` 权限启用时才跳过平台 CSP,`useOfficialDomain` 不参与该判定。权限缺失、非法或读取失败时继续注入,Runtime Gate、Manifest 与 HTML 构建检查始终保留。
481
-
482
- 推荐由项目的 `scripts.build` 保留类型检查:
483
-
484
- ```json
485
- {
486
- "scripts": {
487
- "build": "vue-tsc --noEmit && hb-sdk build"
488
- }
489
- }
490
- ```
491
-
492
- 构建命令只支持 `--env` 和 `--verbose`。已有项目继续使用 `vite build` 仍然兼容,不会自动迁移。
493
-
494
- 平台解析的唯一实现是 `@heybox/hb-sdk/miniapp-publish` 导出的 `resolveMiniappManifestPlatforms(sdkVersion, manifest)`;调用方不要自行比较版本或补默认值:
495
-
496
- - Manifest 显式声明 `platforms` 时按规范化顺序使用;空数组、非数组、未知值或重复值都会抛错,不会回退到历史兼容。
497
- - 未声明 `platforms` 且产物 hb-sdk 版本缺失或低于 `0.9.0`(`MINIAPP_PLATFORM_HARD_CUT_SDK_VERSION`)时,按历史移动端平台 `android` / `ios` / `ohos` 兼容。
498
- - 达到 `0.9.0` 起仍未声明 `platforms` 会直接抛错;任何非法的 `sdkVersion` 也会抛错,不做字符串比较。
499
-
500
- ## Project declarations
501
-
502
- `package.json#heybox.*` 是小程序项目的构建期声明面,不是 Runtime 权限或门禁:`platforms` 声明目标平台,`permissions` 声明受控能力,`companions` 声明随版本发布的桌面辅助程序,`bindAppIds` 声明版本关联的游戏,`window` 声明窗口尺寸与可缩放性。声明不合法时由 `hb-sdk build` / `hb-sdk remote deploy` 在构建期直接失败。
503
-
504
-
505
- # 窗口尺寸与可缩放性
506
-
507
- 新 PC 工坊小程序在 `package.json#heybox.window` 声明开窗默认尺寸与可缩放性,随包发布,遵循**开发者声明优先、用户拖动次之、平台兜底**。
508
-
509
- 窗口**位置不对开发者开放**:不能声明、不能设置。位置只由用户原生拖拽产生,由 Host 按小程序身份本地记忆,并在下次开窗时恢复。
510
-
511
- ## 声明默认尺寸
512
-
513
- ```json
514
- {
515
- "heybox": {
516
- "platforms": ["android", "ios", "ohos", "windows", "macos"],
517
- "window": {
518
- "defaultWidth": 480,
519
- "defaultHeight": 900,
520
- "minWidth": 360,
521
- "minHeight": 600,
522
- "resizable": true
523
- }
524
- }
525
- }
526
- ```
527
-
528
- `window` 整体可选。省略时使用宿主 Manifest 的兜底尺寸,行为与未提供声明时完全一致;声明后写入 `dist/manifest.json`,所有平台都会写入,由各宿主自行决定是否消费。
529
-
530
- ### 字段
531
-
532
- | 字段 | 类型 | 必填 | 含义 |
533
- | --------------- | ------ | ---- | --------------------------------------------------------- |
534
- | `defaultWidth` | 正整数 | 否 | 默认窗口内容宽度(逻辑像素) |
535
- | `defaultHeight` | 正整数 | 否 | 默认窗口内容高度(逻辑像素) |
536
- | `minWidth` | 正整数 | 否 | 用户拖拽不得低于的宽度下限 |
537
- | `minHeight` | 正整数 | 否 | 用户拖拽不得低于的高度下限 |
538
- | `resizable` | 布尔 | 否 | 是否允许**用户手动拖拽**改变尺寸;省略时取平台默认 `true` |
539
-
540
- 字段命名为 `defaultWidth` / `defaultHeight` 而不是 `width` / `height`,因为它表达的是**开窗初值**,不是窗口当前尺寸:用户可能拖过,运行时真实尺寸请用 `viewport.getWindowInfo()` 读取。
541
-
542
- ### 构建期校验
543
-
544
- `window` 按与 `heybox.permissions` 相同的严格风格校验,未知字段直接失败,不做静默忽略:
545
-
546
- - `{}` 等空声明会被拒绝,至少声明一个字段。
547
- - 数值字段必须是正整数(拒绝字符串、小数、`null`、布尔),并且不得大于 `16384`。真正的上限是宿主侧显示器工作区,不在声明里表达。
548
- - `resizable` 必须是布尔,拒绝 `0` / `1` / `"true"`。
549
- - `minWidth` 必须与 `defaultWidth` 同时声明,`minHeight` 必须与 `defaultHeight` 同时声明,且 `min ≤ default`。
550
- - 显式拒绝 `width` / `height` 写法,并提示改用 `defaultWidth` / `defaultHeight`。
551
- - `x` / `y` 会作为未知字段显式报错,不会静默忽略:位置不开放声明。
552
-
553
- `hb-sdk build` 与 `hb-sdk remote deploy` 还会校验 `dist/manifest.json.window` 与 `package.json#heybox.window` 一致,不一致时要求重新构建。
554
-
555
- ## `resizable` 语义
556
-
557
- `resizable` 只约束**用户手动拖拽**:
558
-
559
- | 场景 | `resizable: true` | `resizable: false` |
560
- | -------------------- | ----------------- | ------------------ |
561
- | 用户拖拽边缘改变尺寸 | 允许,受包络夹取 | 禁止 |
562
- | 用户拖拽窗口位置 | 允许 | 仍允许 |
563
- | 尺寸写入用户本地记忆 | 会 | 不会 |
564
-
565
- `minWidth` / `minHeight` 是用户拖拽的下限,声明后与开窗默认尺寸一起构成宿主使用的尺寸包络。
566
-
567
- 写入规则与 `resizable` 正交:**只有 `source === 'user'`(用户原生拖拽)产生的几何变化才允许写入用户本地记忆**;程序化变更(宿主恢复上次尺寸、响应系统缩放等)只更新当前运行时几何,不会覆盖本地记忆。Host/Runtime 集成侧的页面通道合同(`window.getGeometry` 请求与 `window.geometryChanged` 上报及其 `source` 归因)见 `@heybox/hb-sdk` 包内 `docs/runtime-host-migration.md`。
568
-
569
- ## App-facing concepts
570
-
571
-
572
- # 快速开始
573
-
574
- 新项目可先运行 `hb-sdk create my-miniapp` 获得 Vanilla JavaScript + Vite HelloWorld;模板只演示 Toast,业务代码可以直接替换。
575
-
576
- 如果页面不需要小黑盒开放能力,可以不接入 SDK。SDK 导入时会自动启动握手,能力调用会自动等待;使用受保护能力前需在 `package.json#heybox.permissions` 声明对应权限,详见[权限声明](https://docs.xiaoheihe.cn/hb_sdk/guide/permissions)。
577
-
578
- ## 交互控件与握手状态
579
-
580
- `auth.login()` 等可能展示授权 UI 的能力必须保留原始可信用户手势。不要在点击回调中等待握手;页面加载时读取并订阅持久握手状态,只在 `status === 'ready'` 时启用按钮:
581
-
582
- ```ts
583
- import hbSDK, { type MiniProgramSDKHandshakeState } from '@heybox/hb-sdk'
584
- import { computed, onUnmounted, ref } from 'vue'
585
-
586
- const handshakeState = ref<MiniProgramSDKHandshakeState>(hbSDK.getHandshakeState())
587
- const stopHandshakeState = hbSDK.onHandshakeStateChange(state => {
588
- handshakeState.value = state
589
- })
590
- const sdkReady = computed(() => handshakeState.value.status === 'ready')
591
-
592
- onUnmounted(stopHandshakeState)
593
- ```
594
-
595
- 把 `sdkReady` 用作按钮的 `disabled` 条件。订阅会立即回放当前状态,因此晚挂载组件也能得到 `ready` 或 `failed` 终态。`ready` 生命周期事件只在握手成功瞬间派发且不会重放,不能作为当前状态来源。
596
-
597
- ## 读取当前用户
598
-
599
- 声明 `userInfo` 后,可以读取按小程序隔离的 `app_user_id` 和已授权资料。该能力不依赖公开 `network` 权限:
600
-
601
- ```ts
602
- import hbSDK from '@heybox/hb-sdk'
603
-
604
- async function getCurrentUser() {
605
- const result = await hbSDK.user.getInfo()
606
- return result.userInfo
607
- }
608
- ```
609
-
610
- `user.getInfo()` 不展示授权弹窗,也不要求可信用户手势。未登录时返回未登录状态;已登录时隐式授予当前本地用户 scopes(`identity`、`profile`),静默返回 `userInfo.app_user_id`、`profile.nickname` 和 `profile.avatar`。平台为当前版本启用 Steam 账号能力且小程序未开通网络权限时,还会授予 `steam_account`,已绑定用户返回可选 `userInfo.steam_id`。这条路径不能获取授权码或调用 OpenAPI,也不能把身份或资料发送到外部服务。
611
-
612
- ## 获取服务端授权码
613
-
614
- 声明 `userInfo` 后,可通过 `auth.login()` 获取短期授权码。登录可能展示 UI,因此应绑定到按钮点击等明确的用户操作。平台为当前版本启用 Steam 账号能力后,联网小程序可在 `scopes` 中按需加入 `steam_account`,并由开发者服务端通过 OpenAPI 读取 `steam_id`。该调用内部使用 Host 受信请求,不依赖公开 `network` 权限;示例中的 `network.request()` 另需声明并获得 `network` 平台批准。
615
-
616
- SDK 会自动完成握手。登录按钮应按上面的持久握手状态启用;点击回调直接调用 `auth.login()`,不要先等待其他异步任务,以免首次操作丢失可信手势。
617
-
618
- ```ts
619
- import hbSDK, { HbMiniProgramSDKError } from '@heybox/hb-sdk'
620
-
621
- // 这是你自己的后端接口,不是黑盒 OpenAPI 地址。
622
-
623
- async function loginFromUserAction() {
624
- try {
625
- const result = await hbSDK.auth.login({ scopes: ['profile'] })
626
-
627
- await hbSDK.network.request({
628
- url: 'https://api.example.com/session/heybox',
629
- method: 'POST',
630
- data: { code: result.code },
631
- })
632
- } catch (error) {
633
- if (error instanceof HbMiniProgramSDKError && error.code === 'AUTHORIZATION_CANCELLED') {
634
- return
635
- }
636
- throw error
637
- }
638
- }
639
- ```
640
-
641
- 返回值与边界以[用户身份与登录](https://docs.xiaoheihe.cn/hb_sdk/guide/auth)为准。页面只把 `code` 提交给自己的服务端。不要在页面初始化阶段自动调用 `auth.login()`。
642
-
643
- ## 文件与下载
644
-
645
- 文件能力的完整用法、沙箱模型、路径规则、配额与错误码见[文件能力与沙箱](https://docs.xiaoheihe.cn/hb_sdk/guide/files-and-sandbox);本节只给最短上手路径。
646
-
647
- `files.sandbox` 是当前小程序隔离的逻辑根。`file()` / `directory()` 只创建 lazy proxy,不执行
648
- I/O;第一次真实 I/O 仍由 Runtime 和 Host 校验当前 session、授权、mode、kind 和路径。
649
-
650
- ```ts
651
- import hbSDK, { HbMiniProgramSDKError } from '@heybox/hb-sdk'
652
-
653
- const exportDirectory = hbSDK.files.sandbox.directory('exports')
654
- await exportDirectory.create({ recursive: true })
655
-
656
- const controller = new AbortController()
657
-
658
- try {
659
- const file = await hbSDK.network.download({
660
- url: 'https://cdn.example.com/report.json',
661
- to: exportDirectory,
662
- suggestedName: 'report.json',
663
- overwrite: true,
664
- maxBytes: 8 * 1024 * 1024,
665
- signal: controller.signal,
666
- onProgress({ loaded, total, lengthComputable }) {
667
- console.log(lengthComputable ? `${loaded}/${total}` : loaded)
668
- },
669
- })
670
-
671
- console.log(await file.readText())
672
- } catch (error) {
673
- if (error instanceof HbMiniProgramSDKError && error.code === 'METHOD_FORBIDDEN') {
674
- // 当前 Host 不支持 V1 文件能力。
675
- return
676
- }
677
- throw error
678
- }
679
- ```
680
-
681
- 当前平台状态如下:
682
-
683
- | Host | `files.sandbox` | 外部 picker | `files.saveFile()` | `network.download()` |
684
- | ---------------- | --------------- | ----------- | ------------------ | -------------------- |
685
- | 新 PC | 支持 | 支持 | 支持 | 支持 |
686
- | Mobile | 支持 | 支持 | 仅 iOS | 支持 |
687
- | Web | 不支持 | 不支持 | 不支持 | 不支持 |
688
- | Browser Dev Host | 不支持 | 不支持 | 不支持 | 不支持 |
689
-
690
- 当前 Runtime 认识但 Host 未实现时返回 `METHOD_FORBIDDEN`;旧 Runtime 收到新 method 时返回
691
- `METHOD_NOT_FOUND`。新 PC 注入真实文件与流式下载 primitive;Android/iOS `1.3.396+` 还需在
692
- 启动时通过 `system.describe` 宣告对应 Native operations。缺失 handler、协商超时或 operation
693
- 不完整时对应能力保持关闭,且不提供 throwing stub、Blob 或内存假下载。
694
-
695
- Mobile 的可用性完全由 Host 宣告的 operation 集决定,Runtime/H5 不按操作系统分支判断能力:
696
- Android 端不提供 `files.saveFile`,`pickFiles()` 选中的 Android 精确 SAF 文件仅支持只读
697
- (对这类目标请求 `mode: 'readwrite'` 会返回 `FILE_ACCESS_DENIED`)。
698
-
699
- ### 路径与创建
700
-
701
- - 逻辑相对路径统一使用 `/`。拒绝空字符串、绝对路径、空 segment、`.`、`..`、反斜杠、尾分隔符、NUL 和控制字符。
702
- - `create()` 的 `recursive` 与 `exclusive` 默认均为 `false`。默认行为是不截断内容的 ensure-exists;`exclusive: true` 在同名实体已存在时失败。
703
- - `writeText()` / `writeBytes()` 可以在父目录存在时隐式创建目标,但不会自动创建父目录。
704
- - `exists()` 在祖先/目标缺失或 kind mismatch 时返回 `false`;授权撤销、quota 与 I/O 错误仍抛出。
705
- - `file.remove()` 与 `directory.remove()` 只删除 sandbox 对象;外部 picker/saveFile 授权调用删除时抛出 `FILE_ACCESS_DENIED`。
706
- - 非空目录默认不能删除并抛出 `DIRECTORY_NOT_EMPTY`;确认删除整个目录树后显式调用 `directory.remove({ recursive: true })`。
707
- - `directory.list()` 默认最多返回 1000 项,显式 `limit` 也不能超过 1000;超限抛出 `DIRECTORY_LIST_LIMIT_EXCEEDED`。
708
- - Host 文件错误只暴露稳定 code 与 canonical 安全文案;原始 message、data、native path 和 credential 不会进入小程序。
709
- - `FileStat.size` 是字节数;`modifiedAt` / `createdAt` 若存在,单位为 Unix epoch milliseconds。
710
-
711
- ### 外部授权与保存
712
-
713
- `pickFiles()`、`pickDirectory()` 和 `saveFile()` 必须直接从按钮点击等可信用户操作调用。picker
714
- 取消会抛 `FILE_PICKER_CANCELLED`,不会返回空数组或 `undefined`。
715
-
716
- ```ts
717
- async function saveFromUserAction(text: string) {
718
- const file = await hbSDK.files.saveFile({ suggestedName: 'report.json' })
719
- await file.writeText(text)
720
- }
721
- ```
722
-
723
- `saveFile()` 请求 Host 返回精确 File 授权,不会同时创建或保留 Directory 授权。新 PC 当前先让
724
- 用户选择保存目录,再以 `suggestedName` 独占创建空文件;同名文件抛出 `FILE_ALREADY_EXISTS`,
725
- 不会静默覆盖。V1 不接受 `accept`;扩展名过滤只属于 `pickFiles({ accept: ['.json'] })`。外部授权
726
- 仅在当前 Runtime session 有效。
727
-
728
- `pickFiles()` / `pickDirectory()` 默认返回 `mode: 'read'` 的授权;只有显式传入
729
- `multiple: true` 时,`pickFiles()` 才允许 Host 返回多个文件。需要修改文件、在所选目录中创建
730
- 文件,或把外部授权用作下载目标时,必须在 picker options 中显式请求 `mode: 'readwrite'`。
731
-
732
- 单个 Runtime session 最多保留 1024 个 picker/saveFile direct handle;整批选择超过剩余额度时抛出 `FILE_QUOTA_EXCEEDED`,不会保留部分授权。Sandbox 派生项与目录枚举结果使用逻辑引用,不持续占用该额度。
733
-
734
- ### 下载边界
735
-
736
- - 下载固定使用 GET,不接受 method、body、上传或 Range 字段。
737
- - File target 必须已存在且为 `readwrite`,成功后返回同一个 File proxy;Directory target 必须存在且为 `readwrite`,成功后返回新的子 File proxy。
738
- - Directory 默认不覆盖同名文件;只有显式 `overwrite: true` 才允许原子替换。
739
- - Directory target 的子文件名按安全的 `Content-Disposition filename*` / `filename`、`suggestedName`、URL basename、`download.bin` 依次选择。
740
- - `timeout` 是网络空闲超时,不是整个下载总时长。取消或失败不会改动原目标。
741
- - `AbortSignal` 只发出取消意图并等待 Host 终态;如果 Host 已先完成原子提交,Promise 仍以成功结果 resolve,否则抛出 `DOWNLOAD_CANCELLED`。
742
- - 公开 request 与 download 都不跟随重定向;3xx 或 partial representation 会失败。
743
- - 进度从 `loaded: 0` 开始并单调不减;原子提交后、Promise resolve 前会再发送一次 final progress,因此空文件或 Host 已报告最终值时允许相邻值相同。只有无歧义、identity-encoded 的 `Content-Length` 才使 `lengthComputable=true`;压缩、chunked 或重复长度都视为未知 total,可信长度必须在提交前与实际字节数一致。
744
- - `onProgress` 在本地同步执行;回调异常不会中断下载。成功时最后一次回调发生在文件提交后、Promise resolve 前。
745
-
746
- ## 默认单例
747
-
748
- 大多数小程序页面都应该使用默认实例。0.6 起不再对业务代码提供独立实例工厂。
749
-
750
- ## Environment info
751
-
752
-
753
- # 环境信息
754
-
755
- `environment` 模块提供当前小程序实例的静态环境快照,包括运行模式、小黑盒 App 版本、canonical 小程序身份、操作系统和 SDK 版本。该能力无需在 `heybox.permissions` 中声明,也不会触发用户授权。
756
-
757
- ## 推荐用法
758
-
759
- 优先使用异步方法。SDK 尚未完成握手时,`getInfo()` 会自动等待:
760
-
761
- ```ts
762
- import { environment } from '@heybox/hb-sdk'
763
-
764
- const info = await environment.getInfo()
765
-
766
- console.log(info.runtime.mode)
767
- console.log(info.host.appVersion)
768
- console.log(info.miniProgram.id, info.miniProgram.version)
769
- console.log(info.operatingSystem.name, info.operatingSystem.version)
770
- console.log(info.sdk.version)
771
- ```
772
-
773
- 返回对象采用固定结构并深度冻结:
774
-
775
- ```ts
776
- interface MiniProgramEnvironmentInfo {
777
- readonly runtime: {
778
- readonly mode: 'production' | 'preview' | 'development' | 'unknown'
779
- }
780
- readonly host: {
781
- readonly appVersion: string | null
782
- }
783
- readonly miniProgram: {
784
- readonly id: string | null
785
- readonly version: string | null
786
- }
787
- readonly operatingSystem: {
788
- readonly name: 'android' | 'ios' | 'ohos' | 'windows' | 'macos' | 'linux' | 'unknown'
789
- readonly version: string | null
790
- }
791
- readonly sdk: {
792
- readonly version: string
793
- }
794
- }
795
- ```
796
-
797
- ## 同步读取
798
-
799
- 只有已经确认 SDK 为 `ready` 时才能调用 `getInfoSync()`。SDK 会在派发 `ready` 状态前缓存环境快照,因此可以在握手状态订阅中同步读取:
800
-
801
- ```ts
802
- import { environment, onHandshakeStateChange } from '@heybox/hb-sdk'
803
-
804
- const unsubscribe = onHandshakeStateChange(state => {
805
- if (state.status !== 'ready') return
806
-
807
- const info = environment.getInfoSync()
808
- console.log(info.operatingSystem.name)
809
- })
810
- ```
811
-
812
- 握手完成前调用会抛出 `HbMiniProgramSDKError`,错误码为 `ENVIRONMENT_NOT_READY`。通常不需要自行等待握手;不要求同步执行的代码直接使用 `await environment.getInfo()`。
813
-
814
- ## 字段语义
815
-
816
- | 字段 | 语义 |
817
- | ------------------------- | -------------------------------------------------------------------------------------------------------------- |
818
- | `runtime.mode` | 当前实例的粗粒度运行模式。正式发布为 `production`,版本预览为 `preview`,本地或 Dev Session 为 `development`。 |
819
- | `host.appVersion` | 当前小黑盒 App 版本。它是 Host 提供的不透明字符串。 |
820
- | `miniProgram.id` | 平台确认的 canonical `mini_program_id`,不返回数字 ID、用户 ID 或其他旧 ID。 |
821
- | `miniProgram.version` | 当前加载的小程序版本,是不透明字符串。 |
822
- | `operatingSystem.name` | Host 明确提供的标准系统枚举,不从小程序 iframe 的 UA 推断。 |
823
- | `operatingSystem.version` | Host 明确提供的系统版本;当前 Host 未提供时为 `null`。 |
824
- | `sdk.version` | 当前页面实际运行的 `@heybox/hb-sdk` 版本,遵循 npm SemVer。 |
825
-
826
- 除 `sdk.version` 外,其他版本字段均不承诺 SemVer 或大小比较语义。需要判断某项能力是否可用时,应依据能力调用结果进行降级,不要仅比较 App 或系统版本。
827
-
828
- ## 缺失与兼容
829
-
830
- 旧 Host、匿名本地调试或未提供某个字段的 Host 仍会返回完整结构:缺失字符串为 `null`,未知枚举为 `'unknown'`。非法 Host 字段只会被逐项降级,不会阻断 SDK 握手。
831
-
832
- Browser Mock 在 Runtime 启动时使用当前设备预设作为操作系统名称,不读取开发者电脑的 UA。切换设备预设会保留当前 Runtime 和页面状态;需要重新生成环境快照时,使用调试台的重启操作。
833
-
834
- ## 信任边界
835
-
836
- 环境信息仅用于界面适配、兼容降级、埋点和诊断,不能用于鉴权、权限控制或风控。小程序提交给服务端的任何环境字段都可能被修改;服务端安全判断必须使用自身认证上下文或平台受信数据。
837
-
838
- 该 API 不提供设备型号、品牌、UA、CPU、内存、设备唯一标识、账号信息或凭据。屏幕和安全区域继续通过 [`viewport.getWindowInfo()`](https://docs.xiaoheihe.cn/hb_sdk/reference/sdk/viewport/getWindowInfo/) 获取。
839
-
840
-
841
- # 错误处理
842
-
843
- SDK 公开两类标准错误:
844
-
845
- - `HbMiniProgramSDKError`:SDK 初始化或开放能力调用失败。
846
- - `HbMiniProgramNetworkError`:网络请求已返回,但 HTTP 状态未通过 `validateStatus`。
847
-
848
- ```ts
849
- import { HbMiniProgramNetworkError, HbMiniProgramSDKError, network } from '@heybox/hb-sdk'
850
-
851
- try {
852
- await network.request({ url: 'https://api.example.com/data' })
853
- } catch (error) {
854
- if (error instanceof HbMiniProgramNetworkError) {
855
- console.log(error.status, error.data, error.headers)
856
- return
857
- }
858
-
859
- if (error instanceof HbMiniProgramSDKError) {
860
- console.log(error.code, error.message, error.data)
861
- return
862
- }
863
-
864
- throw error
865
- }
866
- ```
867
-
868
- ## 错误边界
869
-
870
- | 结果 | 表示什么 | 常见处理 |
871
- | --------------------------------------- | ------------------------------------------------------------------- | --------------------------------------------------- |
872
- | `HbMiniProgramSDKError` | 握手、参数、权限、Host 能力或模块操作失败 | 按稳定 `code` 分支,`message` 仅用于开发者提示 |
873
- | `HbMiniProgramNetworkError` | `network.request()` 已获得 HTTP 响应,但状态未通过 `validateStatus` | 读取 `status`、`data` 和安全响应头 |
874
- | `undefined` / `deleted: false` 等空结果 | API 明确定义的正常结果,例如排行榜中没有当前用户记录 | 正常渲染空态,不进入错误上报 |
875
- | 其他异常 | 业务回调、页面代码或非 SDK 依赖抛出的错误 | 不要伪装成 SDK 错误;保留原异常继续交给统一错误边界 |
876
-
877
- `HbMiniProgramNetworkError` 不是“所有网络失败”的父类:只有已形成标准 HTTP 响应且状态校验失败时才使用它。
878
- 握手、bridge、Host transport 或权限失败仍属于 `HbMiniProgramSDKError`。业务不应通过 `status === 0` 猜测网络错误。
879
-
880
- `HbMiniProgramSDKError.data` 是按错误码提供的可选诊断信息,不保证所有 Host 版本结构一致。读取前应做类型收窄,
881
- 日志上报也必须先移除 token、授权码、文件路径、请求正文和用户隐私数据。
882
-
883
- ## 处理原则
884
-
885
- - 根据 `error.code` 区分运行环境、权限、超时和业务失败,不要只比对错误文案。
886
- - 对未知 `code` 使用通用失败 UI 并保留诊断信息;不要用穷举 `switch` 的 `default` 自动重试。
887
- - 权限失败时给出可理解的提示,不要将它当成未登录。
888
- - `PERMISSION_NOT_DECLARED` 表示当前版本没有在 `package.json#heybox.permissions` 声明所需权限,应修改项目配置并重新构建、提交版本。
889
- - `PERMISSION_DENIED` 表示权限已声明,但需要的平台批准缺失或批准配置不足。首期只有 `network` 需要平台批准。
890
- - `USER_GESTURE_REQUIRED` 表示潜在授权 UI 缺少可信用户手势,应让用户点击按钮后重试。
891
- - `AUTHORIZATION_CANCELLED` 表示用户取消、拒绝或关闭授权页面,应正常结束当前操作。
892
- - `SERVER_API_REQUIRED` 表示当前用户数据必须经开发者服务端 OpenAPI 获取,不应在页面重试对应 Host API。
893
- - `METHOD_FORBIDDEN` 表示当前 Host 未实现或关闭对应能力。V1 files/download 在 Web、Browser Dev Host 和未实现该能力的旧版 Host 会得到该错误;Android/iOS `1.3.396+` 需先经 `system.describe` 协商到对应 operation 集。
894
- - `ENVIRONMENT_NOT_READY` 表示在 SDK 完成握手前调用了 `environment.getInfoSync()`;一般改用会自动等待的 `environment.getInfo()`。
895
- - `FILE_PICKER_CANCELLED` 表示用户取消了外部文件或目录选择,应正常结束当前操作。
896
- - `DOWNLOAD_CANCELLED` 表示取消意图先于 Host 提交生效;Host 已完成提交时仍返回成功。`DOWNLOAD_TIMEOUT` 表示网络空闲超时,失败不会改动原目标。
897
- - `COMPANION_NOT_PREPARED` 表示启动前尚未显式准备;应由新的用户操作调用 `companion.prepare()`,不要在 `launch()` 中自动重试。
898
- - `COMPANION_PREPARATION_CANCELLED` 表示取消意图已结束当前观察;原子提交可能已完成,应重新查询准备状态再更新 UI。
899
- - `COMPANION_SESSION_OWNERSHIP_LOST` 表示 Session controller 已由新的 Runtime generation 接管;停止旧 controller 写入,需要继续取得控制权时重新取得活动 Session。
900
- - `COMPANION_SESSION_EXITED` / `COMPANION_PIPE_CLOSED` 表示当前 Session 或 stdin 已进入终态;不要对同一 controller 重放写入。
901
- - `COMPANION_PROCESS_CRASHED` / `COMPANION_OUTPUT_LIMIT` 表示进程异常退出或输出越界;先展示退出状态并保存诊断,再由新的用户操作决定是否重启。
902
- - `COMPANION_DESCRIPTOR_UNAVAILABLE` 表示授权或描述符暂时不可用,Runtime 会保留 `retryable: true`。
903
- - `COMPANION_INTEGRITY_FAILED`、`COMPANION_ARCHIVE_INVALID` 或操作系统拦截都不能绕过;停止重试并修正归档后提交新审核版本。
904
- - `DOWNLOAD_HTTP_STATUS` 的 `data` 只包含脱敏后的 `status`、可选 `statusText` 和安全响应头。
905
- - 超时或运行环境不可用时,允许用户重试或退出当前流程。
906
- - 上报 `code`、`message` 和必要的业务上下文,不要上报用户凭据或敏感数据。
907
-
908
- 完整错误码和字段见 [HbMiniProgramSDKError](api-root.md) 与 [HbMiniProgramNetworkError](api-root.md)。
909
-
910
- ## 业务层建议
911
-
912
- ```ts
913
- import hbSDK, { HbMiniProgramSDKError } from '@heybox/hb-sdk'
914
-
915
- type LoginViewState =
916
- | { status: 'ready' }
917
- | { status: 'cancelled' }
918
- | { status: 'failed'; error: HbMiniProgramSDKError }
919
-
920
- async function loginFromUserAction(): Promise<LoginViewState> {
921
- try {
922
- const result = await hbSDK.auth.login()
923
- await exchangeCodeWithDeveloperServer(result.code)
924
- return { status: 'ready' }
925
- } catch (error) {
926
- if (error instanceof HbMiniProgramSDKError) {
927
- if (error.code === 'AUTHORIZATION_CANCELLED') {
928
- return { status: 'cancelled' }
929
- }
930
- reportSDKError(error.code, error.message, error.data)
931
- return { status: 'failed', error }
932
- }
933
-
934
- throw error
935
- }
936
- }
937
-
938
- async function exchangeCodeWithDeveloperServer(code: string) {
939
- await hbSDK.network.request({
940
- url: 'https://api.example.com/session/heybox',
941
- method: 'POST',
942
- data: { code },
943
- })
944
- }
945
-
946
- function reportSDKError(errorCode: string, message: string, data?: unknown) {
947
- console.log('[hb-sdk]', errorCode, message, data)
948
- }
949
- ```
950
-
951
- 授权码在取得后立即交给开发者服务端交换,不要写入页面状态、DOM、日志或持久化存储。UI 只处理服务端会话是否建立成功。
952
-
953
- 文件与下载仍使用 `HbMiniProgramSDKError`,不会新增第三种错误类。业务根据 `error.code` 处理
954
- picker 取消、授权撤销、文件缺失、quota、下载状态或取消,不依赖 `message` 文案,也不要记录
955
- 真实路径、内部 handle 或响应凭据头。
956
-
957
- Companion 失败仍使用 `HbMiniProgramSDKError`。prepare 与 launch 的授权取消属于两次独立用户决定;业务不得在一次点击中自动串联授权,也不得用 Browser Fake 成功替代 Windows/macOS 真机错误处理验证。完整状态机见[受管桌面程序](https://docs.xiaoheihe.cn/hb_sdk/guide/companion)。
958
-
959
- ## Public modules
960
-
961
- ## 能力概览
962
-
963
- SDK 还提供 `getHandshakeState()` / `onHandshakeStateChange()` 管理持久握手状态,并通过 `on()` / `off()` 处理前后台、登录态等生命周期事件。
964
-
965
- | 模块 | 用途 |
966
- | ------------ | ----------------------------------------------- |
967
- | `auth` | 获取交给开发者服务端交换的短期授权码 |
968
- | `environment` | 读取当前实例的冻结环境快照 |
969
- | `user` | 读取 Host 当前用户资料、隔离身份或撤销授权 |
970
- | `share` | 打开分享、复制链接或截图分享流程 |
971
- | `ui` | 展示 Toast 和 Loading |
972
- | `device` | 调用振动和剪贴板能力 |
973
- | `navigation` | 关闭、刷新页面或打开小黑盒页面 |
974
- | `viewport` | 读取窗口信息和设置导航栏样式 |
975
- | `storage` | 读写当前小程序的隔离存储 |
976
- | `files` | 声明受控 sandbox 与用户选择授权的文件、目录操作 |
977
- | `cloud` | 使用小程序云端排行榜 |
978
- | `network` | 发起经过平台授权的网络请求,并声明受控流式下载 |
979
- | `companion` | 准备、启动并控制当前版本审核过的桌面辅助应用 |
980
-
981
- 具体方法、参数和返回值以 [API Reference](https://docs.xiaoheihe.cn/hb_sdk/reference/) 为准,常见组合写法见 [Recipes](https://docs.xiaoheihe.cn/hb_sdk/recipes/)。
982
-
983
-
984
- # 事件与生命周期
985
-
986
- SDK 通过 `on` 监听小程序生命周期和业务事件。
987
-
988
- ```ts
989
- import { onUnmounted } from 'vue'
990
- import { on } from '@heybox/hb-sdk'
991
-
992
- function handleShow(payload: { timestamp: number; source?: string }) {
993
- console.log('show from', payload.source)
994
- }
995
-
996
- const stopShow = on('show', handleShow)
997
- const stopHide = on('hide', () => {
998
- console.log('小程序页面隐藏')
999
- })
1000
-
1001
- function stopLifecycleEvents() {
1002
- stopShow()
1003
- stopHide()
1004
- }
1005
-
1006
- onUnmounted(stopLifecycleEvents)
1007
- ```
1008
-
1009
- 框架外也可以保存 `on()` 返回的取消函数,在页面或业务模块真正销毁时调用。需要按 handler 精确移除时再使用 `off(event, handler)`;不要在注册后的同一执行流里立即取消。
1010
-
1011
- ## 事件列表
1012
-
1013
- | 事件 | 触发时机 | 典型用途 |
1014
- | ------------------------- | ------------------------ | -------------------------------- |
1015
- | `launch` | 小程序首次启动 | 初始化一次性数据 |
1016
- | `ready` | SDK 握手成功瞬间 | 不可重放的边沿通知 |
1017
- | `show` | 小程序页面展示 | 刷新可见态数据 |
1018
- | `hide` | 小程序页面隐藏 | 暂停轮询、暂停播放 |
1019
- | `unload` | 当前小程序运行环境终止 | 清理资源并停止请求 |
1020
- | `error` | 小程序或开放能力运行异常 | 统一错误上报 |
1021
- | `heybox_app_login_change` | 黑盒 APP 登录状态变化 | 刷新依赖 Host 当前用户的本地能力 |
1022
-
1023
- 完整载荷与事件名见:
1024
-
1025
- - [MiniProgramEventPayloadMap](api-root.md)
1026
- - [MiniProgramEventName](api-root.md)
1027
-
1028
- ## 生命周期建议
1029
-
1030
- - SDK 导入时自动启动握手,能力调用会自动等待;不要在用户手势回调中额外等待握手。
1031
- - 当前握手状态只通过 `getHandshakeState()` 查询、通过 `onHandshakeStateChange()` 订阅;订阅会立即回放当前值并返回取消函数。
1032
- - `ready` 事件只在握手成功瞬间派发,不会向晚订阅者重放,不能用于驱动按钮可用状态或替代握手状态 API。
1033
- - UI 可见性相关逻辑放在 `show`、`hide`。
1034
- - 使用 `user.getInfo()` 的小程序可以在 `heybox_app_login_change` 后刷新本地状态。需要开发者服务端会话时使用 `auth.login()` 获取 code;两者都不依赖公开 `network` 权限。
1035
- - 组件或页面销毁时清理 `on` 注册的监听,避免重复响应。
1036
- - 生命周期事件只派发给注册当时存在的监听器,不会重放;一次性 `launch` 信息应在页面启动阶段通过业务能力调用处理。
1037
- - 收到 `unload` 后,当前 SDK 上下文不可恢复,未完成请求会失败;不要在同一页面上下文继续重试能力调用。
1038
- - Companion preparation 与进程 Session 由 Host 持有,页面 `hide` 或 reload 不会自动取消或终止;新页面分别通过 `getPreparationStatus()` 与 `getActiveSession()` 恢复观察和控制。
1039
- - 新 Runtime generation 取得活动 Companion Session 后,旧 controller 会收到 ownership-lost 并失去写权限;stdio 输出可能 at-least-once 重放,业务必须按自身协议去重。
1040
-
1041
-
1042
- # 受管桌面程序
1043
-
1044
- `companion` 用于准备和启动随当前小程序审核版本发布的桌面辅助应用。V1 仅支持新 PC Host 的
1045
- `windows-x64` 与 `macos-arm64`;老 PC、Mobile、Web 和 Linux 不在支持范围内。
1046
-
1047
- ## 声明与构建
1048
-
1049
- 项目必须在 `package.json` 显式声明高风险权限:
1050
-
1051
- ```json
1052
- {
1053
- "heybox": {
1054
- "permissions": {
1055
- "companion": { "enabled": true }
1056
- },
1057
- "companions": {
1058
- "runner": {
1059
- "displayName": "桌面辅助程序",
1060
- "capabilities": ["stdio"],
1061
- "targets": {
1062
- "windows-x64": {
1063
- "source": "companion/runner-windows-x64",
1064
- "entrypoint": { "kind": "executable", "path": "runner.exe" },
1065
- "elevation": "none",
1066
- "args": []
1067
- }
1068
- }
1069
- }
1070
- }
1071
- }
1072
- }
1073
- ```
1074
-
1075
- 归档统一通过 `package.json#heybox.companions` 配置,`source` 相对该 `package.json` 所在目录解析。
1076
- 目标平台写在 `package.json#heybox.platforms`;Vite 中只注册无参的 `miniappManifest()`,不要在 Vite 配置中复制 Companion 声明或平台声明。
1077
- 构建和本地调试读取同一份声明。构建会检查 ZIP 结构和固定入口,复制到
1078
- `dist/companions/<alias>/<target>.zip`,并生成大小与 SHA-256;Web 文件和 Companion 文件进入同一上传
1079
- session 与同一审核版本。页面不能读取部署后的 `manifest.json`,也不能取得真实 CDN URL 或本机安装路径。
1080
-
1081
- `dist/companions/` 下全部归档的**总大小**上限为 500 MiB(`500 × 1024 × 1024` bytes);该上限针对归档总量,
1082
- 不是单个文件。超限时 `hb-sdk build` 以“Companion 归档总大小超过 500MiB 上限,请缩减归档后重新 build”
1083
- 失败,`hb-sdk remote deploy` 以“Companion 归档总大小超过 500MiB 上限,请缩减归档后重新 deploy”失败,
1084
- 需要先缩减桌面辅助应用产物再重新构建或部署。
1085
-
1086
- `hb-sdk dev` 的真实 PC 联调可以直接使用这里声明的本地 ZIP,不要求先上传版本,但项目必须已绑定且 COA
1087
- 批准 `companion`。dev server 只向 loopback 提供固定 Manifest/ZIP 路由,CLI 用短期票据绑定当前 dev
1088
- 进程的 canonical snapshot。ZIP 或配置变化后会校验并切换到新快照,已有 Session 保持原有产物;
1089
- 新产物必须重新准备并启动。校验失败时调试台显示阻塞原因,不会悄悄使用旧文件或线上产物。
1090
- 单次开发服务最多保留 32 份快照、累计 ZIP 大小 1 GiB;达到上限后停止接纳新快照,
1091
- 请先结束调试 Session,再重启开发服务,已有快照不会被自动逐出。
1092
- 未配置本地 Companion 时使用 Browser Fake 做状态联调,真实 PC 不会回退到线上 candidate。
1093
-
1094
- 构建与 PC 安装都会检查真实二进制格式:Windows 为 AMD64 PE,macOS 为包含 arm64 的 Mach-O;
1095
- 脚本即使改名或有执行权限也会被拒绝。授权弹窗展示产物来源、签名状态、目标平台、人类可读归档
1096
- 大小、精确字节数与完整 SHA-256;本地 ZIP 明确标记“本地开发产物,未经过版本审核”。SHA-256
1097
- 只用于 Host 可信授权展示,不进入小程序可读取的 `CompanionInfo`。
1098
- `.app` 从 XML 或 binary Info.plist 的 `CFBundleExecutable` 精确选择主入口。
1099
-
1100
- Manifest 只接受固定入口和固定 args。V1 仅支持普通权限启动,`elevation` 只能省略或设为 `none`;
1101
- `required` 会在构建时明确失败,管理员权限启动留待后续版本。公开 API 不接受 executable path、动态 args、
1102
- cwd、environment、shell 或任意命令;不要把 `files.sandbox` 中的普通文件当作可执行对象。
1103
- `displayName` 最多 120 个 Unicode code point;args 最多 64 项,单项最多 1024 UTF-8 bytes、总计最多
1104
- 16384 UTF-8 bytes,并拒绝 NUL、CR 和 LF。
1105
-
1106
- ## 准备与启动
1107
-
1108
- ```ts
1109
- import { companion } from '@heybox/hb-sdk'
1110
-
1111
- // 分别绑定到「准备」与「启动」按钮,不能在一个点击中串联。
1112
- function prepareFromUserAction() {
1113
- return companion.prepare('runner', {
1114
- onProgress(progress) {
1115
- renderProgress(progress)
1116
- },
1117
- })
1118
- }
1119
-
1120
- function launchFromUserAction() {
1121
- return companion.launch('runner')
1122
- }
1123
- ```
1124
-
1125
- `prepare()` 和 `launch()` 必须分别由新的可信用户手势触发。每次真正开始新的准备操作前,Runtime 展示一次
1126
- Host 可信授权;已 ready 或加入同一在途准备时不会重复授权。每次真正创建新进程前,`launch()` 再展示独立
1127
- 授权,不能复用 prepare 的手势或授权。`launch()` 不会隐式调用 `prepare()`,未准备时稳定失败。
1128
-
1129
- 准备操作属于 Host:页面 reload、最小化或进入后台不会取消。新页面可用
1130
- `getPreparationStatus()` 查询状态,并通过相同 alias 加入在途操作;显式取消使用
1131
- `cancelPreparation(alias)` 或 `AbortSignal`。页面 reload 只断开观察者,不会向 Host 发送取消;原子提交已经开始时,最终提交结果优先于取消意图。
1132
-
1133
- `prepare()` 与 `getInfo()` 返回的 `CompanionInfo.source` 标明 Host 确认的产物来源:`local-dev` 是本地开发产物,`preview` 是审核前预览产物,`released` 是已发布版本产物;旧 Host 缺省时 `source` 为 `undefined`,表示来源未知。不要用 `alias`、`displayName` 或文件路径自行推断来源,也不要把 `preview` 产物当作已发布版本;当前 PC Host 不支持审核前预览时以 `COMPANION_PREVIEW_UNSUPPORTED` 失败。
1134
-
1135
- 准备状态是可恢复的 Host 状态,不等于当前页面 Promise 的状态:
1136
-
1137
- | `getPreparationStatus()` 状态 | 含义 | 推荐动作 |
1138
- | ----------------------------- | ------------------------------------- | ---------------------------------------------------------------- |
1139
- | `not-prepared` | 当前版本产物尚未准备 | 等待新的可信用户操作调用 `prepare()` |
1140
- | `preparing` | Host 正在下载、校验或解压 | 展示 `progress`;需要继续观察时再次调用 `prepare()` 加入同一操作 |
1141
- | `ready` | 产物已原子提交,可独立触发 `launch()` | 展示可启动状态;`preparedAt` 是 Host 提供的时间戳 |
1142
- | `failed` | 最近一次准备失败 | 根据 `error.retryable` 和 `error.code` 决定重试或停止 |
1143
-
1144
- `AbortSignal` 取消的是当前调用并向 Host 发出取消意图,不是页面本地的同步回滚。若原子提交已开始,当前 Promise
1145
- 可能因取消而失败,但稍后查询仍可能得到 `ready`;取消后需要用 `getPreparationStatus()` 对账,不要直接把 UI 固定为
1146
- `not-prepared`。
1147
-
1148
- ## Session 与 stdio
1149
-
1150
- 同一小程序 identity 与 alias 同时最多有一个活动 Session。`getActiveSession(alias)` 会取得当前活动 Session
1151
- 的控制权;新 Runtime generation 接管后,旧 controller 的写入、关闭 stdin、终止、附件和通知操作都会失败。
1152
- 进程退出后 `getActiveSession()` 返回 `undefined`,业务结果应由小程序自行持久化。
1153
-
1154
- `CompanionSession.state` 只有 `running` 和 `exited`。`onExit()` 在 Session 已退出后注册时会立即收到保存的退出结果,
1155
- `waitForExit()` 对同一 Session 始终等待同一次退出;组件销毁时仍应调用所有 `on*()` 返回的取消订阅函数。
1156
- 失去 controller 不等于进程退出,也不会让 `waitForExit()` 提前完成。收到 `onOwnershipLost()` 后应停止写入;确有继续
1157
- 控制的需要时重新调用 `getActiveSession(alias)`,不要对旧 controller 操作做无界重试。
1158
-
1159
- stdio 仅在 Manifest 声明 `stdio` 时存在,输入输出都是原始 `Uint8Array`。SDK 不做 UTF-8、换行、NDJSON、
1160
- RPC 或业务状态解析。输出采用 at-least-once 投递,收到 chunk 后 SDK 会确认 sequence;断连与重取控制权可能
1161
- 导致重复,因此业务 framing 必须携带可去重标识,并能处理拆包、粘包和重放。
1162
-
1163
- ```ts
1164
- const session = await companion.getActiveSession('runner')
1165
- if (session?.stdio) {
1166
- const stopOutput = session.stdio.onStdout(bytes => decodeBusinessFrame(bytes))
1167
- const stopOwnership = session.onOwnershipLost(() => setControlsEnabled(false))
1168
- await session.stdio.write(encodeBusinessFrame({ type: 'status' }))
1169
- // 组件销毁时调用 stopOutput() 和 stopOwnership();业务退出协议可先写入,再 closeStdin()。
1170
- }
1171
- ```
1172
-
1173
- 平台不提供语义跨平台不稳定的 request-close。业务可先通过自身 stdio 协议请求正常退出,或关闭 stdin;
1174
- `terminate()` 是强制结束完整受管进程树。页面隐藏或 reload 不结束 Session,用户真正关闭小程序窗口时由 Host
1175
- 处理完整进程树生命周期。
1176
-
1177
- ## 可选能力
1178
-
1179
- - `attachments`:`session.attachments.open(id)` 返回只读 `FileHandle`;opaque id 来自桌面程序自身业务协议,页面无法指定物理路径。
1180
- - `notifications`:页面解析业务协议后,可请求 Host 展示固定类别通知;页面完全断开时不承诺业务通知。
1181
- - `stdio`:仅提供原始字节双向流,不提供文本编码或 RPC。
1182
-
1183
- 只有 Manifest 声明且 Host 实现的能力才出现在 Session。不要根据操作系统或属性存在性猜测支持情况。
1184
-
1185
- ## 调试与验收
1186
-
1187
- 调试台分别显示浏览器、手机与 PC Companion 的就绪状态,以及本地 alias、平台和产物摘要短前缀。
1188
- PC 会在页面闲置时继续复核授权;明确撤销权限会结束进程树,临时网络故障只允许有时限的宽限,
1189
- 不会让已失去授权的进程无限运行。关闭开发服务前请先停止调试进程。
1190
-
1191
- Browser Dev Host 只提供确定性的 Fake 场景,用于开发准备进度、Session 状态、stdio framing、错误 UI 与恢复逻辑。
1192
- Fake 不选择、不下载、不解压、不启动本机程序,也不经过操作系统安全检查或真实进程组。
1193
- 因此 Browser Fake、Mobile 或 Web 的结果不能作为桌面发布证据;发布前必须分别在目标 Windows/macOS 新 PC Host
1194
- 完成归档摘要、准备取消、启动、stdio、退出与进程树清理验收。
1195
-
1196
- ## 失败处理
1197
-
1198
- - `USER_GESTURE_REQUIRED`:当前 prepare 或 launch 缺少新的可信用户手势。
1199
- - `USER_CANCELLED`:用户拒绝或关闭本次 Host 授权,应正常结束流程。
1200
- - `COMPANION_NOT_PREPARED`:先由新的用户操作显式调用 `prepare()`。
1201
- - `COMPANION_INTEGRITY_FAILED` / `COMPANION_ARCHIVE_INVALID`:停止重试并提交新审核版本,不能绕过摘要或系统安全检查。
1202
- - `COMPANION_SESSION_OWNERSHIP_LOST`:当前 Runtime 已失去 controller;需要时重新调用 `getActiveSession()`。
1203
- - `COMPANION_DESCRIPTOR_UNAVAILABLE`:授权或描述符暂时不可用,可在有界重试策略下重试。
1204
- - `COMPANION_ELEVATION_DENIED`:为未来管理员权限启动保留的兼容错误码;V1 构建不接受 `elevation: 'required'`。
1205
- - `METHOD_FORBIDDEN` / `COMPANION_UNSUPPORTED`:当前 Host 或平台未实现,不要循环重试或用任意执行替代。
1206
- - `COMPANION_PREVIEW_UNSUPPORTED`:当前 PC Host 不支持审核前预览 Companion,需要升级客户端后重试。
1207
-
1208
- 完整类型与方法见 [API Reference](https://docs.xiaoheihe.cn/hb_sdk/reference/)。
1209
-
1210
- ## 完成检查
1211
-
1212
- - 权限、目标 ZIP、固定入口和固定参数都随同一版本提交审核。
1213
- - prepare 与 launch 使用两次独立可信用户操作和 Host 授权。
1214
- - stdio 业务协议处理了原始字节 framing、at-least-once 去重和断连恢复。
1215
- - 未向页面暴露或传入 URL、物理路径、动态 args、环境变量、shell 或 PID。
1216
- - Browser Fake 只用于开发,目标平台均已完成新 PC 真机验收。
1217
-
1218
- ## 云端排行榜
1219
-
1220
- 删除当前用户的排行榜成绩属于破坏性操作,只能在明确的用户操作和二次确认后执行:
1221
-
1222
- ```ts
1223
- async function deleteMyLeaderboardEntryFromUserAction() {
1224
- const confirmed = window.confirm('确定删除自己的榜单成绩吗?');
1225
- if (!confirmed) return;
1226
-
1227
- try {
1228
- await hbSDK.cloud.leaderboard.deleteCurrentUserEntry({ key: 'cube_run_total' });
1229
- } catch (error) {
1230
- if (error instanceof HbMiniProgramSDKError) {
1231
- console.error(error.code, error.message);
1232
- }
1233
- throw error;
1234
- }
1235
- }
1236
- ```
1237
-
1238
- 排行榜记录的 `extra` 会展示给榜单中的其他读取者,只能包含公开展示必需的数据;不得写入个人身份信息(PII)、token、设备标识或非必要行为数据。
1239
-
1240
- 管理员删除完整榜单及其排名记录时,必须显式传入匹配的榜单 key 进行确认:
1241
-
1242
- ```bash
1243
- hb-sdk remote cloud leaderboard delete <key> --confirm <key>
1244
- ```