@heybox/hb-sdk 0.8.0-alpha.3 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +136 -422
- package/README.md +28 -18
- package/dist/cli-chunks/{build-qWzAbpS7.cjs → build-PYCNacya.cjs} +8 -5
- package/dist/cli-chunks/{context-CtS2Thp0.cjs → context-m2W2XbL0.cjs} +42 -59
- package/dist/cli-chunks/{create-PV5ua977.cjs → create-BdAg3WGA.cjs} +2 -2
- package/dist/cli-chunks/{dev-CwKbAm_H.cjs → dev-CyZuw7Yn.cjs} +76 -64
- package/dist/cli-chunks/{doctor-tJUGOYrm.cjs → doctor-DU8rCfUF.cjs} +1 -1
- package/dist/cli-chunks/{index-DVuD75Hr.cjs → index-DATObqzK.cjs} +2 -2
- package/dist/cli-chunks/{index-De687C6-.cjs → index-MMW2ibQm.cjs} +32 -21
- package/dist/cli-chunks/{index.esm-B-4yrLNm.cjs → index.esm-BiAaAUFC.cjs} +8 -8
- package/dist/cli-chunks/{login-DolpqD8K.cjs → login-B3TThMss.cjs} +2 -2
- package/dist/cli-chunks/{project-vite-1rvkK-M8.cjs → project-vite-BQj8YLI4.cjs} +1 -1
- package/dist/cli-chunks/{remote-rIAQE_G2.cjs → remote-DNvI7tHH.cjs} +57 -25
- package/dist/cli-chunks/{runtime-gate-DFjw66kF.cjs → runtime-gate-BEFp1w_s.cjs} +11 -3
- package/dist/cli-chunks/{runtime-permission-env-CjsCe5bp.cjs → runtime-permission-env-CtL8rsjB.cjs} +351 -0
- package/dist/cli-chunks/{session-CzaM2Cq3.cjs → session-DjBkjaF8.cjs} +1 -1
- package/dist/cli-chunks/{skill-CM40_9WH.cjs → skill-cR_wnaw2.cjs} +2 -2
- package/dist/cli-chunks/{version-Bz-AfXQU.cjs → version-yEn1E2Bg.cjs} +1 -1
- package/dist/cli.cjs +1 -1
- package/dist/devtools/browser-dev-host/assets/browser-dev-host-TzYf9L6C.js +99 -0
- package/dist/devtools/browser-dev-host/assets/{index-CeP6SLB3.js → index-C5MZZDa5.js} +4 -4
- package/dist/devtools/browser-dev-host/assets/index-P-ra4m1y.css +1 -0
- package/dist/devtools/browser-dev-host/assets/workbench-state-BwV7bm4n.js +5 -0
- package/dist/devtools/browser-dev-host/index.html +3 -3
- package/dist/index.cjs.js +100 -2
- package/dist/index.esm.js +100 -2
- package/dist/protocol.cjs.js +189 -47
- package/dist/protocol.esm.js +189 -47
- package/dist/templates/{vue3-vite-ts → vanilla-vite-js}/.gitignore.ejs +0 -1
- package/dist/templates/vanilla-vite-js/README.md.ejs +14 -0
- package/dist/templates/vanilla-vite-js/index.html.ejs +20 -0
- package/dist/templates/vanilla-vite-js/package.json.ejs +22 -0
- package/dist/templates/vanilla-vite-js/src/assets/heybox-logo.svg +8 -0
- package/dist/templates/vanilla-vite-js/src/main.js +39 -0
- package/dist/templates/vanilla-vite-js/src/styles.css +155 -0
- package/dist/templates/{vue3-vite-ts/vite.config.ts → vanilla-vite-js/vite.config.js} +1 -2
- package/dist/vite.cjs.js +281 -13
- package/dist/vite.esm.js +281 -13
- package/package.json +13 -9
- package/skill/SKILL.md +8 -9
- package/skill/references/api-protocol.md +1 -3
- package/skill/references/api-root.md +65 -21
- package/skill/references/cli.md +17 -5
- package/skill/references/examples.md +3 -3
- package/skill/references/recipes.md +40 -41
- package/skill/references/safety-boundaries.md +9 -5
- package/skill/skill.json +5 -5
- package/types/core/mini-dev-console.d.ts +36 -0
- package/types/miniapp-manifest/index.d.ts +1 -0
- package/types/miniapp-manifest/node.d.ts +3 -0
- package/types/miniapp-manifest/permissions.d.ts +37 -0
- package/types/miniapp-manifest/schema.d.ts +5 -0
- package/types/modules/share/index.d.ts +1 -1
- package/types/modules/share/show-share-menu.d.ts +1 -1
- package/types/modules/share/types.d.ts +2 -4
- package/types/vite/index.d.ts +3 -1
- package/dist/devtools/browser-dev-host/assets/browser-dev-host-uq-Wac6k.js +0 -97
- package/dist/devtools/browser-dev-host/assets/index-KD2f3Jdz.css +0 -1
- package/dist/devtools/browser-dev-host/assets/workbench-state-D-1U0JRq.js +0 -5
- package/dist/templates/vue3-vite-ts/README.md.ejs +0 -47
- package/dist/templates/vue3-vite-ts/index.html.ejs +0 -12
- package/dist/templates/vue3-vite-ts/package.json.ejs +0 -33
- package/dist/templates/vue3-vite-ts/src/App.vue +0 -78
- package/dist/templates/vue3-vite-ts/src/__tests__/App.spec.ts +0 -148
- package/dist/templates/vue3-vite-ts/src/auth-handoff.ts +0 -46
- package/dist/templates/vue3-vite-ts/src/main.ts +0 -5
- package/dist/templates/vue3-vite-ts/src/styles.css +0 -60
- package/dist/templates/vue3-vite-ts/src/vite-env.d.ts +0 -1
- package/dist/templates/vue3-vite-ts/tsconfig.app.json +0 -17
- package/dist/templates/vue3-vite-ts/tsconfig.json +0 -11
- package/dist/templates/vue3-vite-ts/tsconfig.node.json +0 -11
- package/dist/templates/vue3-vite-ts/vitest.config.ts +0 -10
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
## Package metadata
|
|
25
25
|
|
|
26
26
|
- Package: `@heybox/hb-sdk`
|
|
27
|
-
- Version at generation time: `0.8.0
|
|
27
|
+
- Version at generation time: `0.8.0`
|
|
28
28
|
- Public root export: `@heybox/hb-sdk`
|
|
29
29
|
- Protocol export: `@heybox/hb-sdk/protocol`
|
|
30
30
|
- Vite plugin export: `@heybox/hb-sdk/vite`
|
|
@@ -232,6 +232,7 @@ Use `@heybox/hb-sdk/vite` only in `vite.config.ts`. Do not import it from iframe
|
|
|
232
232
|
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
|
|
233
233
|
import path from 'node:path';
|
|
234
234
|
import { HB_SDK_VERSION } from '../core/version';
|
|
235
|
+
import { MINI_DEV_CONSOLE_EVENT_TYPE, MINI_DEV_IFRAME_WINDOW_NAME, MINI_DEV_CONSOLE_INSTALL_FLAG } from '../core/mini-dev-console';
|
|
235
236
|
import {
|
|
236
237
|
MINIAPP_PLATFORM_VALUES,
|
|
237
238
|
renderMiniappManifest,
|
|
@@ -240,12 +241,14 @@ import {
|
|
|
240
241
|
type MiniappPlatform,
|
|
241
242
|
} from '../miniapp-manifest/schema';
|
|
242
243
|
import { readMiniappVersionFromPackageJson } from '../miniapp-manifest/node';
|
|
244
|
+
import { readMiniappPermissionsFromPackageJson } from '../miniapp-manifest/node';
|
|
245
|
+
import { getMissingPermissionsWarning } from '../miniapp-manifest/permissions';
|
|
243
246
|
import { enforceMiniappHtmlPolicy } from './html-policy';
|
|
244
247
|
import { shouldSkipMiniappPlatformCspFromEnv } from './runtime-permission-env';
|
|
245
248
|
|
|
246
249
|
export interface MiniappManifestPlugin {
|
|
247
250
|
name: string;
|
|
248
|
-
config: (config: MiniappManifestUserConfig) => MiniappManifestUserConfig | void;
|
|
251
|
+
config: (config: MiniappManifestUserConfig, env?: { command: 'build' | 'serve' }) => MiniappManifestUserConfig | void;
|
|
249
252
|
configResolved: (resolved: MiniappManifestResolvedConfig) => void;
|
|
250
253
|
/** Rollup 在构建失败后仍会跑 closeBundle;用 buildEnd 记录真实错误,避免二次校验掩盖原因。 */
|
|
251
254
|
buildEnd: (error?: Error) => void;
|
|
@@ -287,12 +290,34 @@ export interface MiniappManifestResolvedConfig {
|
|
|
287
290
|
export { MINIAPP_PLATFORM_VALUES };
|
|
288
291
|
export type { MiniappPlatform };
|
|
289
292
|
|
|
293
|
+
/**
|
|
294
|
+
* dev serve 时在入口 HTML 最早位置注入无依赖 console 捕获 bootstrap。
|
|
295
|
+
*
|
|
296
|
+
* 必须内联完整 patch 逻辑而非等 SDK 模块加载:vite client、业务代码的 console 调用
|
|
297
|
+
* 都可能早于 SDK 单例初始化(如 [vite] connecting)。捕获条件:
|
|
298
|
+
* 1. 构建期只有 vite serve 走到本分支(生产构建无此代码,双保险之 define 常量仍注入给 SDK 侧);
|
|
299
|
+
* 2. 运行期仅调试 iframe(window.name 标记由调试台 iframe.name 与本 bootstrap 设置)激活。
|
|
300
|
+
* 转发经 window.parent.postMessage(CSP connect-src 不约束 postMessage),失败静默,
|
|
301
|
+
* 严禁回打 console 造成自触发循环。SDK 侧 installMiniDevConsoleForwarding 安装时
|
|
302
|
+
* 检测同款 INSTALL_FLAG,不会重复 patch。
|
|
303
|
+
*/
|
|
304
|
+
function injectMiniDevConsoleBootstrap(html: string): string {
|
|
305
|
+
const bootstrap = `<script>(function(){var LEVELS=['log','debug','info','warn','error'];var FLAG='${MINI_DEV_CONSOLE_INSTALL_FLAG}';var TYPE='${MINI_DEV_CONSOLE_EVENT_TYPE}';if(window.name!=='${MINI_DEV_IFRAME_WINDOW_NAME}')window.name='${MINI_DEV_IFRAME_WINDOW_NAME}';if(window[FLAG])return;var patched=false;for(var i=0;i<LEVELS.length;i++)(function(level){var original=console[level];if(typeof original!=='function')return;console[level]=function(){try{parent.postMessage({type:TYPE,detail:{level:level,args:Array.prototype.slice.call(arguments),timestamp:Date.now()}},'*')}catch(e){}return original.apply(this,arguments)};patched=true})(LEVELS[i]);if(patched)window[FLAG]=true})();</script>`;
|
|
306
|
+
const headIndex = html.indexOf('<head>');
|
|
307
|
+
if (headIndex < 0) {
|
|
308
|
+
return html;
|
|
309
|
+
}
|
|
310
|
+
const insertAt = headIndex + '<head>'.length;
|
|
311
|
+
return `${html.slice(0, insertAt)}${bootstrap}${html.slice(insertAt)}`;
|
|
312
|
+
}
|
|
313
|
+
|
|
290
314
|
export interface MiniappManifestOptions {
|
|
291
315
|
platforms: readonly MiniappPlatform[];
|
|
292
316
|
}
|
|
293
317
|
|
|
294
318
|
const sdkVersionPlaceholder = ['__HB_SDK', 'VERSION__'].join('_');
|
|
295
319
|
const sdkVersionBuildConstant = ['__HB_SDK_BUILD', 'VERSION__'].join('_');
|
|
320
|
+
const miniDevLoggingConstant = ['__HB_SDK_DEV', 'LOGGING__'].join('_');
|
|
296
321
|
|
|
297
322
|
export function miniappManifest(options: MiniappManifestOptions): MiniappManifestPlugin {
|
|
298
323
|
const platforms = validateMiniappPlatforms(options?.platforms, 'miniappManifest().platforms');
|
|
@@ -306,12 +331,17 @@ export function miniappManifest(options: MiniappManifestOptions): MiniappManifes
|
|
|
306
331
|
|
|
307
332
|
return {
|
|
308
333
|
name: 'heybox-miniapp-manifest',
|
|
309
|
-
config(config) {
|
|
334
|
+
config(config, env) {
|
|
310
335
|
assertMiniappViteBase(config.base);
|
|
336
|
+
// command 在本钩子时序早于 configResolved,必须取自 env 命令而非闭包;
|
|
337
|
+
// 旧调用方(测试等)未传 env 时按 build 处理。
|
|
338
|
+
const isServe = env?.command === 'serve';
|
|
311
339
|
return {
|
|
312
340
|
...(config.base === undefined ? { base: './' } : {}),
|
|
313
341
|
define: {
|
|
314
342
|
[sdkVersionBuildConstant]: JSON.stringify(resolveSdkVersion()),
|
|
343
|
+
// 仅 vite serve(hb-sdk dev)注入;vite build / hb-sdk build 永不注入,捕获模块被死代码消除。
|
|
344
|
+
...(isServe ? { [miniDevLoggingConstant]: 'true' } : {}),
|
|
315
345
|
},
|
|
316
346
|
};
|
|
317
347
|
},
|
|
@@ -333,12 +363,12 @@ export function miniappManifest(options: MiniappManifestOptions): MiniappManifes
|
|
|
333
363
|
}
|
|
334
364
|
},
|
|
335
365
|
transformIndexHtml(html) {
|
|
336
|
-
|
|
366
|
+
const enforced = enforceMiniappHtmlPolicy(html, {
|
|
337
367
|
...(command === 'serve' ? { hmrWebSocketUrl } : {}),
|
|
338
368
|
skipPlatformCsp,
|
|
339
369
|
});
|
|
340
|
-
|
|
341
|
-
async closeBundle() {
|
|
370
|
+
return command === 'serve' ? injectMiniDevConsoleBootstrap(enforced) : enforced;
|
|
371
|
+
}, async closeBundle() {
|
|
342
372
|
// Rollup 在 buildStart/transform 失败后仍会调用 closeBundle。
|
|
343
373
|
// 若此时再抛「缺 index.html」等二次错误,会掩盖真实失败原因。
|
|
344
374
|
if (priorBuildError) {
|
|
@@ -347,6 +377,8 @@ export function miniappManifest(options: MiniappManifestOptions): MiniappManifes
|
|
|
347
377
|
|
|
348
378
|
const version = validateMiniappPackageVersionForBuild(readMiniappVersionFromPackageJson(root));
|
|
349
379
|
const sdkVersion = resolveSdkVersion();
|
|
380
|
+
const parsedPermissions = readMiniappPermissionsFromPackageJson(root, sdkVersion);
|
|
381
|
+
if (!parsedPermissions.declared) this.warn(getMissingPermissionsWarning());
|
|
350
382
|
const outputRoot = path.resolve(root, outDir);
|
|
351
383
|
const htmlFiles = collectHtmlFiles(outputRoot);
|
|
352
384
|
const unexpectedHtmlFiles = htmlFiles.filter((file) => path.relative(outputRoot, file) !== 'index.html');
|
|
@@ -365,7 +397,15 @@ export function miniappManifest(options: MiniappManifestOptions): MiniappManifes
|
|
|
365
397
|
|
|
366
398
|
const manifestPath = path.join(outputRoot, 'manifest.json');
|
|
367
399
|
mkdirSync(path.dirname(manifestPath), { recursive: true });
|
|
368
|
-
writeFileSync(
|
|
400
|
+
writeFileSync(
|
|
401
|
+
manifestPath,
|
|
402
|
+
renderMiniappManifest({
|
|
403
|
+
version,
|
|
404
|
+
sdkVersion,
|
|
405
|
+
platforms,
|
|
406
|
+
...(parsedPermissions.permissions === undefined ? {} : { permissions: parsedPermissions.permissions }),
|
|
407
|
+
}),
|
|
408
|
+
);
|
|
369
409
|
},
|
|
370
410
|
};
|
|
371
411
|
}
|
|
@@ -420,7 +460,7 @@ hb-sdk build [--env <name>] [--verbose]
|
|
|
420
460
|
|
|
421
461
|
`hb-sdk build` 直接使用项目安装的 Vite,先清理再生成固定的 `dist/`,并校验小程序入口、Manifest 和可上传产物。它不执行类型检查,不要求 CLI 登录或绑定小程序,也不访问远端服务。项目必须在 `vite.config.ts` 中显式注册 `miniappManifest()`。
|
|
422
462
|
|
|
423
|
-
直接运行 `hb-sdk build` 或 `vite build` 时默认注入平台 CSP。`hb-sdk remote deploy`
|
|
463
|
+
直接运行 `hb-sdk build` 或 `vite build` 时默认注入平台 CSP。`hb-sdk remote deploy` 会在构建前读取绑定小程序的远端批准结果,并与当前版本声明取交集;仅当有效 `network` 权限启用时才跳过平台 CSP,`useOfficialDomain` 不参与该判定。权限缺失、非法或读取失败时继续注入,Runtime Gate、Manifest 与 HTML 构建检查始终保留。
|
|
424
464
|
|
|
425
465
|
推荐由项目的 `scripts.build` 保留类型检查:
|
|
426
466
|
|
|
@@ -439,7 +479,9 @@ hb-sdk build [--env <name>] [--verbose]
|
|
|
439
479
|
|
|
440
480
|
# 快速开始
|
|
441
481
|
|
|
442
|
-
|
|
482
|
+
新项目可先运行 `hb-sdk create my-miniapp` 获得 Vanilla JavaScript + Vite HelloWorld;模板只演示 Toast,业务代码可以直接替换。
|
|
483
|
+
|
|
484
|
+
如果页面不需要小黑盒开放能力,可以不接入 SDK。SDK 导入时会自动启动握手,能力调用会自动等待;使用受保护能力前需在 `package.json#heybox.permissions` 声明对应权限,详见[权限声明](https://docs.xiaoheihe.cn/hb_sdk/guide/permissions)。
|
|
443
485
|
|
|
444
486
|
## 交互控件与握手状态
|
|
445
487
|
|
|
@@ -460,9 +502,9 @@ onUnmounted(stopHandshakeState)
|
|
|
460
502
|
|
|
461
503
|
把 `sdkReady` 用作按钮的 `disabled` 条件。订阅会立即回放当前状态,因此晚挂载组件也能得到 `ready` 或 `failed` 终态。`ready` 生命周期事件只在握手成功瞬间派发且不会重放,不能作为当前状态来源。
|
|
462
504
|
|
|
463
|
-
##
|
|
505
|
+
## 读取当前用户
|
|
464
506
|
|
|
465
|
-
|
|
507
|
+
声明 `userInfo` 后,可以读取按小程序隔离的 `app_user_id` 和已授权资料。该能力不依赖公开 `network` 权限:
|
|
466
508
|
|
|
467
509
|
```ts
|
|
468
510
|
import hbSDK from '@heybox/hb-sdk'
|
|
@@ -475,9 +517,9 @@ async function getCurrentUser() {
|
|
|
475
517
|
|
|
476
518
|
`user.getInfo()` 不展示授权弹窗,也不要求可信用户手势。未登录时返回未登录状态;已登录时隐式授予当前本地用户 scopes(`identity`、`profile`),静默返回 `userInfo.app_user_id`、`profile.nickname` 和 `profile.avatar`。这条路径不能获取授权码或调用 OpenAPI,也不能把身份或资料发送到外部服务。
|
|
477
519
|
|
|
478
|
-
##
|
|
520
|
+
## 获取服务端授权码
|
|
479
521
|
|
|
480
|
-
|
|
522
|
+
声明 `userInfo` 后,可通过 `auth.login()` 获取短期授权码。登录可能展示 UI,因此应绑定到按钮点击等明确的用户操作。该调用内部使用 Host 受信请求,不依赖公开 `network` 权限;示例中的 `network.request()` 另需声明并获得 `network` 平台批准。
|
|
481
523
|
|
|
482
524
|
SDK 会自动完成握手。登录按钮应按上面的持久握手状态启用;点击回调直接调用 `auth.login()`,不要先等待其他异步任务,以免首次操作丢失可信手势。
|
|
483
525
|
|
|
@@ -546,15 +588,14 @@ try {
|
|
|
546
588
|
|
|
547
589
|
| Host | `files.sandbox` | 外部 picker | `network.download()` |
|
|
548
590
|
| ---------------- | --------------- | ----------- | -------------------- |
|
|
549
|
-
|
|
|
591
|
+
| 新 PC | 支持 | 支持 | 支持 |
|
|
550
592
|
| Mobile | 不支持 | 不支持 | 不支持 |
|
|
551
593
|
| Web | 不支持 | 不支持 | 不支持 |
|
|
552
594
|
| Browser Dev Host | 不支持 | 不支持 | 不支持 |
|
|
553
595
|
|
|
554
596
|
当前 Runtime 认识但 Host 未实现时返回 `METHOD_FORBIDDEN`;旧 Runtime 收到新 method 时返回
|
|
555
|
-
`METHOD_NOT_FOUND
|
|
556
|
-
|
|
557
|
-
当前任何 Host 都不提供 Blob 或内存假下载。
|
|
597
|
+
`METHOD_NOT_FOUND`。新 PC V1 注入真实文件与流式下载 primitive;其他当前 Host 未实现时仍不
|
|
598
|
+
提供 throwing stub、Blob 或内存假下载。
|
|
558
599
|
|
|
559
600
|
### 路径与创建
|
|
560
601
|
|
|
@@ -580,9 +621,10 @@ async function saveFromUserAction(text: string) {
|
|
|
580
621
|
}
|
|
581
622
|
```
|
|
582
623
|
|
|
583
|
-
`saveFile()`
|
|
584
|
-
|
|
585
|
-
|
|
624
|
+
`saveFile()` 请求 Host 返回精确 File 授权,不会同时创建或保留 Directory 授权。新 PC 当前先让
|
|
625
|
+
用户选择保存目录,再以 `suggestedName` 独占创建空文件;同名文件抛出 `FILE_ALREADY_EXISTS`,
|
|
626
|
+
不会静默覆盖。V1 不接受 `accept`;扩展名过滤只属于 `pickFiles({ accept: ['.json'] })`。外部授权
|
|
627
|
+
仅在当前 Runtime session 有效。
|
|
586
628
|
|
|
587
629
|
`pickFiles()` / `pickDirectory()` 默认返回 `mode: 'read'` 的授权;只有显式传入
|
|
588
630
|
`multiple: true` 时,`pickFiles()` 才允许 Host 返回多个文件。需要修改文件、在所选目录中创建
|
|
@@ -638,6 +680,8 @@ try {
|
|
|
638
680
|
|
|
639
681
|
- 根据 `error.code` 区分运行环境、权限、超时和业务失败,不要只比对错误文案。
|
|
640
682
|
- 权限失败时给出可理解的提示,不要将它当成未登录。
|
|
683
|
+
- `PERMISSION_NOT_DECLARED` 表示当前版本没有在 `package.json#heybox.permissions` 声明所需权限,应修改项目配置并重新构建、提交版本。
|
|
684
|
+
- `PERMISSION_DENIED` 表示权限已声明,但需要的平台批准缺失或批准配置不足。首期只有 `network` 需要平台批准。
|
|
641
685
|
- `USER_GESTURE_REQUIRED` 表示潜在授权 UI 缺少可信用户手势,应让用户点击按钮后重试。
|
|
642
686
|
- `AUTHORIZATION_CANCELLED` 表示用户取消、拒绝或关闭授权页面,应正常结束当前操作。
|
|
643
687
|
- `SERVER_API_REQUIRED` 表示当前用户数据必须经开发者服务端 OpenAPI 获取,不应在页面重试对应 Host API。
|
|
@@ -770,7 +814,7 @@ onUnmounted(stopLifecycleEvents)
|
|
|
770
814
|
- 当前握手状态只通过 `getHandshakeState()` 查询、通过 `onHandshakeStateChange()` 订阅;订阅会立即回放当前值并返回取消函数。
|
|
771
815
|
- `ready` 事件只在握手成功瞬间派发,不会向晚订阅者重放,不能用于驱动按钮可用状态或替代握手状态 API。
|
|
772
816
|
- UI 可见性相关逻辑放在 `show`、`hide`。
|
|
773
|
-
- 使用
|
|
817
|
+
- 使用 `user.getInfo()` 的小程序可以在 `heybox_app_login_change` 后刷新本地状态。需要开发者服务端会话时使用 `auth.login()` 获取 code;两者都不依赖公开 `network` 权限。
|
|
774
818
|
- 组件或页面销毁时清理 `on` 注册的监听,避免重复响应。
|
|
775
819
|
- 生命周期事件只派发给注册当时存在的监听器,不会重放;一次性 `launch` 信息应在页面启动阶段通过业务能力调用处理。
|
|
776
820
|
- 收到 `unload` 后,当前 SDK 上下文不可恢复,未完成请求会失败;不要在同一页面上下文继续重试能力调用。
|
package/skill/references/cli.md
CHANGED
|
@@ -82,6 +82,10 @@ npm install
|
|
|
82
82
|
npm run dev
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
+
默认产物是 Vanilla JavaScript + Vite HelloWorld,只演示一次 `ui.showToast()` 调用,并预填 `android`、`ios`、`ohos` 三个平台。Demo 可以整体删除,项目不绑定 Vue、TypeScript 或测试框架。
|
|
86
|
+
|
|
87
|
+
当前 `0.8` 已发布为稳定版本,本页使用 `@latest` 创建项目。
|
|
88
|
+
|
|
85
89
|
已有项目则在项目目录运行 `npm run dev` 或 `hb-sdk dev`。
|
|
86
90
|
|
|
87
91
|
Agent rules:
|
|
@@ -101,13 +105,15 @@ Agent rules:
|
|
|
101
105
|
hb-sdk dev
|
|
102
106
|
```
|
|
103
107
|
|
|
104
|
-
CLI 会启动页面服务并自动打开 Vue 3
|
|
108
|
+
CLI 会启动页面服务并自动打开 Vue 3 本地调试台。左侧集中放置日志、Storage 和问题三个诊断页签,右侧保持稳定的小程序内容与设备预览。
|
|
109
|
+
|
|
110
|
+
默认终端只显示启动结果、调试页地址、小程序地址和手机调试入口。排查启动问题时使用 `hb-sdk dev --verbose` 查看完整启动阶段;手机扫码调试凭证连续重试失败时,默认只在失败和恢复两次状态变化时提示。
|
|
105
111
|
|
|
106
112
|
<img src="/assets/browser-dev-host-workbench.png" alt="小程序工坊 Vue 3 调试台" style="width: 100%; max-width: 1120px;" />
|
|
107
113
|
|
|
108
114
|
浏览器调试入口不要求 CLI 登录或项目绑定。没有账号、绑定小程序或远端 Dev Context 时,页面和基础 Browser Mock 仍可启动;依赖这些上下文的能力会返回明确失败。远端管理、部署和发布仍要求完成登录与绑定。
|
|
109
115
|
|
|
110
|
-
`hb-sdk dev`
|
|
116
|
+
`hb-sdk dev` 从项目 `package.json` 读取开发者声明,并在远端权限快照可用时读取平台批准结果。只有当前版本声明且平台已批准 `network` 时才跳过平台 CSP;`useOfficialDomain` 不参与该判定。调试台不提供权限或平台批准修改入口;快照缺失或无效时保留平台 CSP。
|
|
111
117
|
|
|
112
118
|
Browser Mock 会自动在实时与兼容链路间切换。手机调试使用 `open_inapp`/`openWindow` 包裹的 LAN 短链接二维码(先开普通 H5 跳转页,再进入小程序并关闭中间页)。
|
|
113
119
|
|
|
@@ -119,7 +125,7 @@ Browser Mock 会自动在实时与兼容链路间切换。手机调试使用 `op
|
|
|
119
125
|
- SDK 初始化与用户身份授权流程
|
|
120
126
|
- 生命周期、Storage 和排行榜等能力
|
|
121
127
|
|
|
122
|
-
|
|
128
|
+
调试台提供紧凑的日志、当前小程序隔离作用域内的 Storage 只读快照和问题聚合。日志与网络记录只保留脱敏的诊断字段,不展示 payload、结果、查询参数、凭据或原始错误信息。工坊小程序默认不能进行网络请求,网络权限暂未开放申请,不要把本地结果当成线上能力。
|
|
123
129
|
|
|
124
130
|
右侧可切换 iPhone 16 Pro Max(`387 x 821`)与 Pixel 9 Pro(`322 x 716`)两个设备预设。尺寸对应固定上游设备外框的真实屏幕 opening;预设同时决定外框、状态栏、安全区和 viewport。切换设备不会重新加载小程序或重启 Runtime,页面状态和调试会话保持不变。授权与操作弹窗、Toast、Loading 和振动反馈均显示在设备预览内部,不会覆盖整个调试台。
|
|
125
131
|
|
|
@@ -138,7 +144,7 @@ Browser Mock 会自动在实时与兼容链路间切换。手机调试使用 `op
|
|
|
138
144
|
| 参数 | 用途 |
|
|
139
145
|
| -------------------------------- | -------------------------------- |
|
|
140
146
|
| `--port <port>` | 指定页面开发服务端口。 |
|
|
141
|
-
| `--browser-dev-host-port <port>` |
|
|
147
|
+
| `--browser-dev-host-port <port>` | 指定浏览器调试页服务端口。 |
|
|
142
148
|
| `--no-open` | 启动后不自动打开浏览器。 |
|
|
143
149
|
| `--verbose` | 出现问题时输出更详细的诊断信息。 |
|
|
144
150
|
|
|
@@ -158,7 +164,7 @@ hb-sdk build [--env <name>] [--verbose]
|
|
|
158
164
|
|
|
159
165
|
`hb-sdk build` 直接使用项目安装的 Vite,先清理再生成固定的 `dist/`,并校验小程序入口、Manifest 和可上传产物。它不执行类型检查,不要求 CLI 登录或绑定小程序,也不访问远端服务。项目必须在 `vite.config.ts` 中显式注册 `miniappManifest()`。
|
|
160
166
|
|
|
161
|
-
直接运行 `hb-sdk build` 或 `vite build` 时默认注入平台 CSP。`hb-sdk remote deploy`
|
|
167
|
+
直接运行 `hb-sdk build` 或 `vite build` 时默认注入平台 CSP。`hb-sdk remote deploy` 会在构建前读取绑定小程序的远端批准结果,并与当前版本声明取交集;仅当有效 `network` 权限启用时才跳过平台 CSP,`useOfficialDomain` 不参与该判定。权限缺失、非法或读取失败时继续注入,Runtime Gate、Manifest 与 HTML 构建检查始终保留。
|
|
162
168
|
|
|
163
169
|
推荐由项目的 `scripts.build` 保留类型检查:
|
|
164
170
|
|
|
@@ -278,3 +284,9 @@ Agent rules:
|
|
|
278
284
|
- If doctor reports `SDK_MISMATCH`, upgrade the project dependency to the matching @heybox/hb-sdk version before reinstalling the skill.
|
|
279
285
|
|
|
280
286
|
## Update reminders
|
|
287
|
+
|
|
288
|
+
## 版本提醒
|
|
289
|
+
|
|
290
|
+
CLI 会从 npm 的 `latest` 标签检查稳定版更新,发现新版本时在命令结束后输出一行提醒,包含升级命令和目标版本的[更新日志](https://docs.xiaoheihe.cn/hb_sdk/changelog/)链接。提醒最多每 24 小时检查一次,请求超时或网络异常不会影响原命令;CI 环境默认不检查。
|
|
291
|
+
|
|
292
|
+
需要临时关闭本地检查时,设置 `HB_SDK_NO_UPDATE_CHECK=1`。版本提醒不会读取 Alpha、Beta 或 RC 等预发布标签。
|
|
@@ -105,7 +105,7 @@ try {
|
|
|
105
105
|
}
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
-
### Sandbox download contract (
|
|
108
|
+
### Sandbox download contract (new PC)
|
|
109
109
|
|
|
110
110
|
```ts
|
|
111
111
|
import { files, network, HbMiniProgramSDKError } from '@heybox/hb-sdk';
|
|
@@ -185,8 +185,8 @@ export default defineConfig({
|
|
|
185
185
|
- Do not call unsupported storage delete/clear/info operations.
|
|
186
186
|
- Do not pass raw internal share/network protocol fields from mini-program code.
|
|
187
187
|
- Do not send `multipart/form-data` (or handcrafted multipart bodies) through `network.request`; use form-urlencoded string body or a dedicated upload capability.
|
|
188
|
-
- Do not pass string paths, browser File System Access handles, Blob targets, Range/resume fields, or upload bodies to `network.download`; use SDK-created File/Directory handles
|
|
189
|
-
- Do not treat
|
|
188
|
+
- Do not pass string paths, browser File System Access handles, Blob targets, Range/resume fields, or upload bodies to `network.download`; use SDK-created File/Directory handles on new PC.
|
|
189
|
+
- Do not treat Mobile, Web, Browser Dev Host, or legacy PC as evidence for files/download support. Only new PC currently implements the retained contract; other Hosts return `METHOD_FORBIDDEN` and provide no memory fallback.
|
|
190
190
|
- Do not treat `hb-sdk login` as iframe SDK authentication state.
|
|
191
191
|
- Do not create a second mock runtime package when `hb-sdk dev` is the supported local mock workflow.
|
|
192
192
|
- Do not import `@heybox/hb-sdk/vite` from iframe business code or fetch a deployed `manifest.json` directly.
|
|
@@ -26,7 +26,9 @@
|
|
|
26
26
|
|
|
27
27
|
# 快速开始
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
新项目可先运行 `hb-sdk create my-miniapp` 获得 Vanilla JavaScript + Vite HelloWorld;模板只演示 Toast,业务代码可以直接替换。
|
|
30
|
+
|
|
31
|
+
如果页面不需要小黑盒开放能力,可以不接入 SDK。SDK 导入时会自动启动握手,能力调用会自动等待;使用受保护能力前需在 `package.json#heybox.permissions` 声明对应权限,详见[权限声明](https://docs.xiaoheihe.cn/hb_sdk/guide/permissions)。
|
|
30
32
|
|
|
31
33
|
## 交互控件与握手状态
|
|
32
34
|
|
|
@@ -47,9 +49,9 @@ onUnmounted(stopHandshakeState)
|
|
|
47
49
|
|
|
48
50
|
把 `sdkReady` 用作按钮的 `disabled` 条件。订阅会立即回放当前状态,因此晚挂载组件也能得到 `ready` 或 `failed` 终态。`ready` 生命周期事件只在握手成功瞬间派发且不会重放,不能作为当前状态来源。
|
|
49
51
|
|
|
50
|
-
##
|
|
52
|
+
## 读取当前用户
|
|
51
53
|
|
|
52
|
-
|
|
54
|
+
声明 `userInfo` 后,可以读取按小程序隔离的 `app_user_id` 和已授权资料。该能力不依赖公开 `network` 权限:
|
|
53
55
|
|
|
54
56
|
```ts
|
|
55
57
|
import hbSDK from '@heybox/hb-sdk'
|
|
@@ -62,9 +64,9 @@ async function getCurrentUser() {
|
|
|
62
64
|
|
|
63
65
|
`user.getInfo()` 不展示授权弹窗,也不要求可信用户手势。未登录时返回未登录状态;已登录时隐式授予当前本地用户 scopes(`identity`、`profile`),静默返回 `userInfo.app_user_id`、`profile.nickname` 和 `profile.avatar`。这条路径不能获取授权码或调用 OpenAPI,也不能把身份或资料发送到外部服务。
|
|
64
66
|
|
|
65
|
-
##
|
|
67
|
+
## 获取服务端授权码
|
|
66
68
|
|
|
67
|
-
|
|
69
|
+
声明 `userInfo` 后,可通过 `auth.login()` 获取短期授权码。登录可能展示 UI,因此应绑定到按钮点击等明确的用户操作。该调用内部使用 Host 受信请求,不依赖公开 `network` 权限;示例中的 `network.request()` 另需声明并获得 `network` 平台批准。
|
|
68
70
|
|
|
69
71
|
SDK 会自动完成握手。登录按钮应按上面的持久握手状态启用;点击回调直接调用 `auth.login()`,不要先等待其他异步任务,以免首次操作丢失可信手势。
|
|
70
72
|
|
|
@@ -133,15 +135,14 @@ try {
|
|
|
133
135
|
|
|
134
136
|
| Host | `files.sandbox` | 外部 picker | `network.download()` |
|
|
135
137
|
| ---------------- | --------------- | ----------- | -------------------- |
|
|
136
|
-
|
|
|
138
|
+
| 新 PC | 支持 | 支持 | 支持 |
|
|
137
139
|
| Mobile | 不支持 | 不支持 | 不支持 |
|
|
138
140
|
| Web | 不支持 | 不支持 | 不支持 |
|
|
139
141
|
| Browser Dev Host | 不支持 | 不支持 | 不支持 |
|
|
140
142
|
|
|
141
143
|
当前 Runtime 认识但 Host 未实现时返回 `METHOD_FORBIDDEN`;旧 Runtime 收到新 method 时返回
|
|
142
|
-
`METHOD_NOT_FOUND
|
|
143
|
-
|
|
144
|
-
当前任何 Host 都不提供 Blob 或内存假下载。
|
|
144
|
+
`METHOD_NOT_FOUND`。新 PC V1 注入真实文件与流式下载 primitive;其他当前 Host 未实现时仍不
|
|
145
|
+
提供 throwing stub、Blob 或内存假下载。
|
|
145
146
|
|
|
146
147
|
### 路径与创建
|
|
147
148
|
|
|
@@ -167,9 +168,10 @@ async function saveFromUserAction(text: string) {
|
|
|
167
168
|
}
|
|
168
169
|
```
|
|
169
170
|
|
|
170
|
-
`saveFile()`
|
|
171
|
-
|
|
172
|
-
|
|
171
|
+
`saveFile()` 请求 Host 返回精确 File 授权,不会同时创建或保留 Directory 授权。新 PC 当前先让
|
|
172
|
+
用户选择保存目录,再以 `suggestedName` 独占创建空文件;同名文件抛出 `FILE_ALREADY_EXISTS`,
|
|
173
|
+
不会静默覆盖。V1 不接受 `accept`;扩展名过滤只属于 `pickFiles({ accept: ['.json'] })`。外部授权
|
|
174
|
+
仅在当前 Runtime session 有效。
|
|
173
175
|
|
|
174
176
|
`pickFiles()` / `pickDirectory()` 默认返回 `mode: 'read'` 的授权;只有显式传入
|
|
175
177
|
`multiple: true` 时,`pickFiles()` 才允许 Host 返回多个文件。需要修改文件、在所选目录中创建
|
|
@@ -200,16 +202,17 @@ Runtime session 有效。
|
|
|
200
202
|
|
|
201
203
|
`app_user_id` 是平台为“用户 × 当前小程序”生成的稳定、隔离标识,不是黑盒用户 ID。它是不透明字符串,只能在当前小程序内使用,不能解析或跨小程序关联。
|
|
202
204
|
|
|
203
|
-
|
|
205
|
+
身份能力与公开 `network` 权限相互独立。根据业务需要选择入口,并在 `package.json#heybox.permissions` 声明对应权限:
|
|
204
206
|
|
|
205
|
-
|
|
|
206
|
-
|
|
|
207
|
-
|
|
|
208
|
-
|
|
|
207
|
+
| 身份入口 | 权限 | 结果用途 |
|
|
208
|
+
| ------------------------- | -------------- | ------------------------------------------------ |
|
|
209
|
+
| `auth.login({ scopes? })` | `userInfo` | 获取短期授权码,由开发者服务端换取 OpenAPI token |
|
|
210
|
+
| `user.getInfo()` | `userInfo` | 读取当前用户的隔离身份及已授权资料 |
|
|
211
|
+
| `user.getSteamGameList()` | `steamLibrary` | 读取当前用户的 Steam 游戏库 |
|
|
209
212
|
|
|
210
213
|
不要混用两条路径。SDK 不向小程序页面提供 token、cookie、黑盒用户 ID 或平台私有凭据。
|
|
211
214
|
|
|
212
|
-
##
|
|
215
|
+
## 获取服务端授权码
|
|
213
216
|
|
|
214
217
|
在登录、绑定账号或读取资料等明确的用户操作中调用 `auth.login()`:
|
|
215
218
|
|
|
@@ -263,9 +266,13 @@ async function loginFromUserAction() {
|
|
|
263
266
|
|
|
264
267
|
用户已授权所需 scope 时,`auth.login()` 可以不展示 UI,静默返回新的短期授权码。业务仍应把可能出现的授权 UI 设计在明确的用户操作之后,不要在页面初始化阶段自动调用。
|
|
265
268
|
|
|
269
|
+
`auth.login()` 内部使用 Host 的受信请求,不会调用小程序公开的 `network.request()`,因此不要求声明 `network`。如果页面需要把 code 通过 `network.request()` 发给开发者服务端,则该请求本身仍需声明并获得 `network` 的平台批准。
|
|
270
|
+
|
|
271
|
+
OpenAPI 凭据、授权码和 access token 的生命周期也不由 `network` 权限开启或关闭。
|
|
272
|
+
|
|
266
273
|
## 撤销当前小程序授权
|
|
267
274
|
|
|
268
|
-
|
|
275
|
+
任何小程序都可以在明确的用户操作中撤销授权;`user.revokeAuthorization()` 位于无需声明白名单:
|
|
269
276
|
|
|
270
277
|
```ts
|
|
271
278
|
async function revokeAuthorizationFromUserAction() {
|
|
@@ -279,22 +286,11 @@ async function revokeAuthorizationFromUserAction() {
|
|
|
279
286
|
|
|
280
287
|
`user.revokeAuthorization()` 不接收参数。小程序页面不能提交小程序 ID、黑盒用户 ID 或手势标记;Runtime 从 Host 启动上下文和用户操作状态注入可信值。调用缺少可信用户手势时返回 `USER_GESTURE_REQUIRED`。
|
|
281
288
|
|
|
282
|
-
撤销成功后,后续 `auth.login()`
|
|
283
|
-
|
|
284
|
-
## 当前用户资料由服务端读取
|
|
285
|
-
|
|
286
|
-
已开通网络权限后,页面不再直接读取 Host 当前用户资料。`@heybox/hb-sdk` 根包实际导出的以下调用统一返回 `SERVER_API_REQUIRED`:
|
|
289
|
+
撤销成功后,后续 `auth.login()` 会重新进入授权流程;再次调用 `user.getInfo()` 时会按现有用户授权规则读取身份。业务必须立即停止使用并清理此前保存的 `app_user_id`、用户资料和开发者服务端会话;SDK 不会删除业务自己的 localStorage、数据库或 cookie。
|
|
287
290
|
|
|
288
|
-
|
|
289
|
-
- `user.getSteamGameList(options)`
|
|
291
|
+
## 读取当前用户资料
|
|
290
292
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
`user.revokeAuthorization()` 是例外:它是授权变更操作,在两种网络模式下都可用,但始终要求可信用户手势。
|
|
294
|
-
|
|
295
|
-
## 未开通网络权限
|
|
296
|
-
|
|
297
|
-
未开通网络权限的小程序不走授权码流程。需要当前用户在本小程序内的稳定隔离身份和公开资料时调用:
|
|
293
|
+
需要当前用户在本小程序内的稳定隔离身份和已授权资料时调用:
|
|
298
294
|
|
|
299
295
|
```ts
|
|
300
296
|
import hbSDK from '@heybox/hb-sdk'
|
|
@@ -305,14 +301,16 @@ async function getCurrentUser() {
|
|
|
305
301
|
}
|
|
306
302
|
```
|
|
307
303
|
|
|
308
|
-
`user.getInfo()`
|
|
304
|
+
`user.getInfo()` 不依赖 `network`,但必须声明 `userInfo`。它延续现有交互:不展示授权弹窗,也不要求可信用户手势。未登录时返回 `isHeyboxAppLoggedIn: false`;已登录时按现有用户授权状态返回当前小程序隔离的 `app_user_id`,以及已授权的 `profile.nickname` 和 `profile.avatar` 等可用资料。用户授权与开发者权限声明是两层独立门禁,不能用声明代替用户同意。
|
|
309
305
|
|
|
310
|
-
|
|
306
|
+
Steam 游戏库使用 `user.getSteamGameList(options)`,要求声明 `steamLibrary`,同样不依赖 `network`。Host current-user capabilities 的既有账号绑定和数据可用性规则保持不变。
|
|
311
307
|
|
|
312
308
|
## 网络请求边界
|
|
313
309
|
|
|
314
310
|
`network.request()` 只用于访问开发者自己的业务服务。平台保留的 runtime auth 与 OpenAPI 内部路径不能通过该能力访问;身份交换必须由开发者服务端按公开后端文档完成。
|
|
315
311
|
|
|
312
|
+
完整权限配置与错误区别见[权限声明](https://docs.xiaoheihe.cn/hb_sdk/guide/permissions)。
|
|
313
|
+
|
|
316
314
|
## CLI 登录与用户登录
|
|
317
315
|
|
|
318
316
|
`hb-sdk login` 只给本地开发和远端管理命令建立 CLI 登录态,与小程序页面的 `auth.login()`、`user.getInfo()` 和用户授权完全无关。
|
|
@@ -370,7 +368,7 @@ onUnmounted(stopLifecycleEvents)
|
|
|
370
368
|
- 当前握手状态只通过 `getHandshakeState()` 查询、通过 `onHandshakeStateChange()` 订阅;订阅会立即回放当前值并返回取消函数。
|
|
371
369
|
- `ready` 事件只在握手成功瞬间派发,不会向晚订阅者重放,不能用于驱动按钮可用状态或替代握手状态 API。
|
|
372
370
|
- UI 可见性相关逻辑放在 `show`、`hide`。
|
|
373
|
-
- 使用
|
|
371
|
+
- 使用 `user.getInfo()` 的小程序可以在 `heybox_app_login_change` 后刷新本地状态。需要开发者服务端会话时使用 `auth.login()` 获取 code;两者都不依赖公开 `network` 权限。
|
|
374
372
|
- 组件或页面销毁时清理 `on` 注册的监听,避免重复响应。
|
|
375
373
|
- 生命周期事件只派发给注册当时存在的监听器,不会重放;一次性 `launch` 信息应在页面启动阶段通过业务能力调用处理。
|
|
376
374
|
- 收到 `unload` 后,当前 SDK 上下文不可恢复,未完成请求会失败;不要在同一页面上下文继续重试能力调用。
|
|
@@ -409,6 +407,8 @@ try {
|
|
|
409
407
|
|
|
410
408
|
- 根据 `error.code` 区分运行环境、权限、超时和业务失败,不要只比对错误文案。
|
|
411
409
|
- 权限失败时给出可理解的提示,不要将它当成未登录。
|
|
410
|
+
- `PERMISSION_NOT_DECLARED` 表示当前版本没有在 `package.json#heybox.permissions` 声明所需权限,应修改项目配置并重新构建、提交版本。
|
|
411
|
+
- `PERMISSION_DENIED` 表示权限已声明,但需要的平台批准缺失或批准配置不足。首期只有 `network` 需要平台批准。
|
|
412
412
|
- `USER_GESTURE_REQUIRED` 表示潜在授权 UI 缺少可信用户手势,应让用户点击按钮后重试。
|
|
413
413
|
- `AUTHORIZATION_CANCELLED` 表示用户取消、拒绝或关闭授权页面,应正常结束当前操作。
|
|
414
414
|
- `SERVER_API_REQUIRED` 表示当前用户数据必须经开发者服务端 OpenAPI 获取,不应在页面重试对应 Host API。
|
|
@@ -473,7 +473,7 @@ picker 取消、授权撤销、文件缺失、quota、下载状态或取消,
|
|
|
473
473
|
|
|
474
474
|
# 服务端登录门禁
|
|
475
475
|
|
|
476
|
-
|
|
476
|
+
声明 `userInfo` 后,小程序可以把“取得授权码并交给开发者服务端”收敛成一个用户操作函数。`auth.login()` 本身不依赖 `network`;以下示例使用 `network.request()` 传递 code,因此还需声明并获得 `network` 的平台批准:
|
|
477
477
|
|
|
478
478
|
示例中的 URL 是开发者自己的后端接口,不是黑盒 OpenAPI 地址。
|
|
479
479
|
|
|
@@ -523,7 +523,7 @@ async function handleSubmit() {
|
|
|
523
523
|
|
|
524
524
|
## 普通分享
|
|
525
525
|
|
|
526
|
-
|
|
526
|
+
普通分享的落地页固定为当前小程序的 `common_share`,不接受自定义 `url`。普通分享只支持一个默认分区,并且配置 `post` 时不要同时指定站外 `channel`。
|
|
527
527
|
|
|
528
528
|
```ts
|
|
529
529
|
import { share } from '@heybox/hb-sdk'
|
|
@@ -555,7 +555,7 @@ await share.screenshot({
|
|
|
555
555
|
|
|
556
556
|
## 恢复分享页面状态
|
|
557
557
|
|
|
558
|
-
|
|
558
|
+
通过固定通用分享链接分享时,可以使用 `extra` 携带由小程序自行定义的页面状态。分享方只负责写入状态,接收方负责决定如何使用:
|
|
559
559
|
|
|
560
560
|
```ts
|
|
561
561
|
await share.showShareMenu({
|
|
@@ -588,7 +588,7 @@ if (sharedState && typeof sharedState === 'object' && !Array.isArray(sharedState
|
|
|
588
588
|
}
|
|
589
589
|
```
|
|
590
590
|
|
|
591
|
-
`getExtra()` 不依赖异步请求;没有有效数据时返回 `undefined`,业务应回退到默认首页。`extra` 只支持 JSON-compatible 数据,最多 8 层,单个数组或对象最多 64 项,内容不超过 128
|
|
591
|
+
`getExtra()` 不依赖异步请求;没有有效数据时返回 `undefined`,业务应回退到默认首页。`extra` 只支持 JSON-compatible 数据,最多 8 层,单个数组或对象最多 64 项,内容不超过 128 字节,也不要存放 token、个人信息等敏感数据。`copyLink()` 不会继承当前启动链接中的 `extra`,只携带本次显式传入的数据。
|
|
592
592
|
|
|
593
593
|
## 参数边界
|
|
594
594
|
|
|
@@ -611,7 +611,6 @@ if (sharedState && typeof sharedState === 'object' && !Array.isArray(sharedState
|
|
|
611
611
|
|
|
612
612
|
```ts
|
|
613
613
|
import hbSDK from '@heybox/hb-sdk'
|
|
614
|
-
|
|
615
614
|
```
|
|
616
615
|
|
|
617
616
|
## 测试环境注入 window
|
|
@@ -15,16 +15,16 @@
|
|
|
15
15
|
- `ready` 生命周期事件是不可重放的边沿通知,不代表可查询状态,也不能替代握手状态 API。
|
|
16
16
|
- `auth.login({ scopes? })` 只返回 `{ code, expiresIn: 300, scopes }`;identity 隐式强制包含,code 只能提交给开发者服务端。
|
|
17
17
|
- 需要授权 UI 时,`auth.login()` 必须来自可信用户手势,否则返回 `USER_GESTURE_REQUIRED`;用户取消或关闭时返回 `AUTHORIZATION_CANCELLED`。已授权时可以静默返回新 code。
|
|
18
|
-
- `user.
|
|
19
|
-
- 已开通网络权限时,公开的 `user.getInfo()` 返回 `SERVER_API_REQUIRED`;对应身份和资料数据应由开发者服务端通过 OpenAPI 获取。
|
|
20
|
-
- 未开通网络权限时,`user.getInfo()` 隐式授予 `identity` 与 `profile`,静默返回 `userInfo.app_user_id`、昵称和头像;这条路径仍不能获取 code 或调用 OpenAPI。
|
|
18
|
+
- `auth.login()`、`user.getInfo()` 和 `user.getSteamGameList()` 的可用性不由 `network` 决定;它们分别要求 `userInfo` 或 `steamLibrary`,并继续遵循各自的用户授权和数据规则。
|
|
21
19
|
- `user.revokeAuthorization()` 在两种网络模式下都要求可信用户手势;成功后必须停止使用并清理业务缓存的旧身份、资料和服务端会话。
|
|
22
20
|
- `on()` 返回取消监听函数,组件卸载或页面销毁时需要调用。
|
|
23
21
|
- 业务网络请求使用 `network.request()`,不要依赖浏览器原生网络出口。
|
|
24
22
|
- 公开 `network.request()` 与 `network.download()` 均使用 no-follow redirect policy;3xx 不会在 Host 内静默跳转。
|
|
25
23
|
- `network.request()` 不能访问平台保留的 runtime auth 与 OpenAPI 内部路径;页面不得持有或交换服务端应用凭据。
|
|
26
24
|
- `network.request` 不支持 `multipart/form-data`;App Host 仅支持 form(`application/x-www-form-urlencoded`)与 JSON。表单请用 `URLSearchParams#toString()` 作为 `data`,文件上传请走专用上传能力。
|
|
27
|
-
-
|
|
25
|
+
- 新 PC 开放持久 sandbox、单文件/目录 picker、精确 File 保存与公网 `network.download()`;多选和小黑盒域名流式下载暂不支持。Mobile、Web 与 Browser Dev Host 仍未开放这些 primitive。
|
|
26
|
+
- 新 PC 支持 `network.request`,但会忽略 `withCredentials`;它不改变请求路由或凭据行为。其他平台继续遵循各自的 Host 语义。
|
|
27
|
+
- 新 PC 不支持振动、分享菜单和截图分享;`navigation.openAppPage` 仅支持 `game_detail`,用户/帖子详情会明确失败。调用平台相关能力时应处理 `METHOD_FORBIDDEN` 或 `REQUEST_UNSUPPORTED`。
|
|
28
28
|
- picker 必须来自可信用户手势;取消选择返回 `FILE_PICKER_CANCELLED`。`saveFile()` 只接受 `suggestedName`,不接受 `accept`。
|
|
29
29
|
- `pickFiles()` / `pickDirectory()` 默认只读;`pickFiles()` 仅在显式传入 `multiple: true` 时允许 Host 返回多个文件。要写入或作为下载目标时显式请求 `mode: 'readwrite'`。
|
|
30
30
|
- `file()` / `directory()` 只接受以 `/` 分隔的规范相对路径;拒绝绝对路径、空 segment、`.`、`..`、反斜杠、尾分隔符和控制字符。
|
|
@@ -34,9 +34,13 @@
|
|
|
34
34
|
- 单个 Runtime session 最多保留 1024 个 picker/saveFile direct handle;整批授权超限时返回 `FILE_QUOTA_EXCEEDED`,不会保留部分结果。
|
|
35
35
|
- Host 文件错误只保留稳定 code 与 canonical 安全文案;原始 message、data、native path 和 credential 不会进入小程序。
|
|
36
36
|
- `FileStat.size` 是非负 safe integer;`modifiedAt` / `createdAt` 若存在,单位为 Unix epoch milliseconds。
|
|
37
|
-
-
|
|
37
|
+
- 仅当当前版本声明且平台已批准 `network` 时,`hb-sdk dev` 与 `hb-sdk remote deploy` 构建才会跳过平台 CSP;其他构建继续注入平台 CSP。`useOfficialDomain` 不参与 CSP 跳过判定。
|
|
38
38
|
- 构建必须启用 `miniappManifest({ platforms })` 并显式声明实际承诺适配的平台,推荐统一使用 `hb-sdk build`。新项目模板中的 `['android', 'ios', 'ohos']` 只是初始配置,不代表已经完成真机验收。
|
|
39
39
|
|
|
40
|
+
私有 Page Channel 适配没有修改 `@heybox/hb-sdk` 公开 API 或 iframe wire;本次 files/download
|
|
41
|
+
Runtime 能力随 `0.8.0-alpha.11` release family 发布,部署 detail 前必须保证
|
|
42
|
+
`@heybox/hb-sdk`、`@heybox/hb-sdk-runtime` 与 `@heybox/hb-sdk-protocol` 三个 package 均可解析。
|
|
43
|
+
|
|
40
44
|
## Agent rules
|
|
41
45
|
|
|
42
46
|
- Do not instruct mini-program code to read, extract, forward, store, or depend on token, cookie, phone number, or private credentials.
|
package/skill/skill.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hb-sdk",
|
|
3
|
-
"skillVersion": "0.8.0
|
|
3
|
+
"skillVersion": "0.8.0+skill.7bb8515ab71e",
|
|
4
4
|
"sdk": {
|
|
5
5
|
"package": "@heybox/hb-sdk",
|
|
6
|
-
"version": "0.8.0
|
|
7
|
-
"compatibility": "0.8.0
|
|
6
|
+
"version": "0.8.0",
|
|
7
|
+
"compatibility": "0.8.0"
|
|
8
8
|
},
|
|
9
9
|
"distribution": {
|
|
10
10
|
"type": "npm",
|
|
11
11
|
"package": "@heybox/hb-sdk",
|
|
12
|
-
"version": "0.8.0
|
|
12
|
+
"version": "0.8.0",
|
|
13
13
|
"path": "skill"
|
|
14
14
|
},
|
|
15
|
-
"integrity": "sha256-
|
|
15
|
+
"integrity": "sha256-7bb8515ab71e004724601d7e09d0e5058888b53a7486b7ed15535ba9a8cdb93c"
|
|
16
16
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* iframe 与调试台页面的开发期 console 捕获转发。
|
|
3
|
+
*
|
|
4
|
+
* 双条件门控(iframe 转发):
|
|
5
|
+
* 1. 构建期:`hb-sdk dev`(vite serve)注入 `__HB_SDK_DEV_LOGGING__`;`hb-sdk build` /
|
|
6
|
+
* `vite build`(生产)永不注入或替换为 `false`,本模块被死代码消除。
|
|
7
|
+
* 2. 运行期:仅在 `window.name` 为 `__hb_sdk_mini_dev__` 的调试 iframe 中激活,
|
|
8
|
+
* 用户设备上的正式运行环境没有该标记。
|
|
9
|
+
*
|
|
10
|
+
* 无侵入 patch `console.log/debug/info/warn/error`:原样放行(DevTools 不受影响)+
|
|
11
|
+
* 通过 `window.parent.postMessage` 转发给调试台(CSP 的 connect-src 不约束 postMessage,
|
|
12
|
+
* 网络上报由调试台页面代理)。发送全程静默:失败不得回打 console,避免自触发死循环。
|
|
13
|
+
*
|
|
14
|
+
* 激活时机:由 SDK 默认单例初始化时调用(业务 `import '@heybox/hb-sdk'` 即生效);
|
|
15
|
+
* iframe 标记由调试台 `iframe.name` 与 vite dev 注入的无依赖 bootstrap 共同设置。
|
|
16
|
+
* 调试台页面自身(runtime 跑在这里,`[hb-sdk-runtime]` 日志不经过 iframe)另用
|
|
17
|
+
* `installMiniDevConsoleSelfCapture` 接入「日志」页签(source: 'host')。
|
|
18
|
+
*/
|
|
19
|
+
export declare const MINI_DEV_IFRAME_WINDOW_NAME = "__hb_sdk_mini_dev__";
|
|
20
|
+
export declare const MINI_DEV_CONSOLE_EVENT_TYPE = "hb-sdk:mini-dev-console";
|
|
21
|
+
/** 对外契约:调试台监听该 postMessage 读取转发日志;message 结构必须稳定。 */
|
|
22
|
+
export interface MiniDevConsoleMessage {
|
|
23
|
+
type: typeof MINI_DEV_CONSOLE_EVENT_TYPE;
|
|
24
|
+
detail: MiniDevConsoleEventDetail;
|
|
25
|
+
}
|
|
26
|
+
export type MiniDevConsoleLevel = 'log' | 'debug' | 'info' | 'warn' | 'error';
|
|
27
|
+
export interface MiniDevConsoleEventDetail {
|
|
28
|
+
level: MiniDevConsoleLevel;
|
|
29
|
+
args: unknown[];
|
|
30
|
+
timestamp: number;
|
|
31
|
+
}
|
|
32
|
+
/** 调试台页面与 iframe bootstrap 共用的已安装标记(window/console 上的属性名)。 */
|
|
33
|
+
export declare const MINI_DEV_CONSOLE_INSTALL_FLAG = "__hb_sdk_mini_dev_console_installed__";
|
|
34
|
+
/** 调试台页面(非 iframe)自捕获:runtime/host 侧 console 直接进「日志」页签。 */
|
|
35
|
+
export declare function installMiniDevConsoleSelfCapture(onLog: (level: MiniDevConsoleLevel, args: unknown[]) => void, consoleRef?: Console): void;
|
|
36
|
+
export declare function installMiniDevConsoleForwarding(consoleRef?: Console): void;
|