@heybox/hb-sdk 0.8.0-alpha.9 → 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 +67 -0
- package/README.md +25 -19
- package/dist/cli-chunks/{build-DkokKVNy.cjs → build-PYCNacya.cjs} +8 -5
- package/dist/cli-chunks/{context-CKzZxKbF.cjs → context-m2W2XbL0.cjs} +42 -59
- package/dist/cli-chunks/{create-BQy5Jdmu.cjs → create-BdAg3WGA.cjs} +1 -1
- package/dist/cli-chunks/{dev-Dik2zr5R.cjs → dev-CyZuw7Yn.cjs} +26 -15
- package/dist/cli-chunks/{doctor-Byr4uwKG.cjs → doctor-DU8rCfUF.cjs} +1 -1
- package/dist/cli-chunks/{index-Cl0XaX8e.cjs → index-DATObqzK.cjs} +2 -2
- package/dist/cli-chunks/{index-BwGBr1ZA.cjs → index-MMW2ibQm.cjs} +15 -15
- package/dist/cli-chunks/{index.esm-BYifBABc.cjs → index.esm-BiAaAUFC.cjs} +8 -8
- package/dist/cli-chunks/{login-Dr9lclu3.cjs → login-B3TThMss.cjs} +2 -2
- package/dist/cli-chunks/{project-vite-BIPrOtRO.cjs → project-vite-BQj8YLI4.cjs} +1 -1
- package/dist/cli-chunks/{remote-DXxyA14a.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-B6Mo9eYW.cjs → session-DjBkjaF8.cjs} +1 -1
- package/dist/cli-chunks/{skill-f90sxv28.cjs → skill-cR_wnaw2.cjs} +2 -2
- package/dist/cli-chunks/{version-DDB_btOG.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-DaqmTjSF.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-wHgWRb7I.js → workbench-state-BwV7bm4n.js} +2 -2
- package/dist/devtools/browser-dev-host/index.html +3 -3
- package/dist/index.cjs.js +99 -1
- package/dist/index.esm.js +99 -1
- package/dist/protocol.cjs.js +189 -47
- package/dist/protocol.esm.js +189 -47
- package/dist/templates/vanilla-vite-js/package.json.ejs +2 -1
- package/dist/vite.cjs.js +281 -13
- package/dist/vite.esm.js +281 -13
- package/package.json +5 -5
- package/skill/SKILL.md +8 -9
- package/skill/references/api-protocol.md +1 -1
- package/skill/references/api-root.md +63 -21
- package/skill/references/cli.md +6 -6
- package/skill/references/examples.md +3 -3
- package/skill/references/recipes.md +35 -38
- 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/vite/index.d.ts +3 -1
- package/dist/devtools/browser-dev-host/assets/browser-dev-host-CbhA4h8z.js +0 -97
- package/dist/devtools/browser-dev-host/assets/index-DJFB5ySU.css +0 -1
|
@@ -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
|
|
|
@@ -441,7 +481,7 @@ hb-sdk build [--env <name>] [--verbose]
|
|
|
441
481
|
|
|
442
482
|
新项目可先运行 `hb-sdk create my-miniapp` 获得 Vanilla JavaScript + Vite HelloWorld;模板只演示 Toast,业务代码可以直接替换。
|
|
443
483
|
|
|
444
|
-
如果页面不需要小黑盒开放能力,可以不接入 SDK。SDK
|
|
484
|
+
如果页面不需要小黑盒开放能力,可以不接入 SDK。SDK 导入时会自动启动握手,能力调用会自动等待;使用受保护能力前需在 `package.json#heybox.permissions` 声明对应权限,详见[权限声明](https://docs.xiaoheihe.cn/hb_sdk/guide/permissions)。
|
|
445
485
|
|
|
446
486
|
## 交互控件与握手状态
|
|
447
487
|
|
|
@@ -462,9 +502,9 @@ onUnmounted(stopHandshakeState)
|
|
|
462
502
|
|
|
463
503
|
把 `sdkReady` 用作按钮的 `disabled` 条件。订阅会立即回放当前状态,因此晚挂载组件也能得到 `ready` 或 `failed` 终态。`ready` 生命周期事件只在握手成功瞬间派发且不会重放,不能作为当前状态来源。
|
|
464
504
|
|
|
465
|
-
##
|
|
505
|
+
## 读取当前用户
|
|
466
506
|
|
|
467
|
-
|
|
507
|
+
声明 `userInfo` 后,可以读取按小程序隔离的 `app_user_id` 和已授权资料。该能力不依赖公开 `network` 权限:
|
|
468
508
|
|
|
469
509
|
```ts
|
|
470
510
|
import hbSDK from '@heybox/hb-sdk'
|
|
@@ -477,9 +517,9 @@ async function getCurrentUser() {
|
|
|
477
517
|
|
|
478
518
|
`user.getInfo()` 不展示授权弹窗,也不要求可信用户手势。未登录时返回未登录状态;已登录时隐式授予当前本地用户 scopes(`identity`、`profile`),静默返回 `userInfo.app_user_id`、`profile.nickname` 和 `profile.avatar`。这条路径不能获取授权码或调用 OpenAPI,也不能把身份或资料发送到外部服务。
|
|
479
519
|
|
|
480
|
-
##
|
|
520
|
+
## 获取服务端授权码
|
|
481
521
|
|
|
482
|
-
|
|
522
|
+
声明 `userInfo` 后,可通过 `auth.login()` 获取短期授权码。登录可能展示 UI,因此应绑定到按钮点击等明确的用户操作。该调用内部使用 Host 受信请求,不依赖公开 `network` 权限;示例中的 `network.request()` 另需声明并获得 `network` 平台批准。
|
|
483
523
|
|
|
484
524
|
SDK 会自动完成握手。登录按钮应按上面的持久握手状态启用;点击回调直接调用 `auth.login()`,不要先等待其他异步任务,以免首次操作丢失可信手势。
|
|
485
525
|
|
|
@@ -548,15 +588,14 @@ try {
|
|
|
548
588
|
|
|
549
589
|
| Host | `files.sandbox` | 外部 picker | `network.download()` |
|
|
550
590
|
| ---------------- | --------------- | ----------- | -------------------- |
|
|
551
|
-
|
|
|
591
|
+
| 新 PC | 支持 | 支持 | 支持 |
|
|
552
592
|
| Mobile | 不支持 | 不支持 | 不支持 |
|
|
553
593
|
| Web | 不支持 | 不支持 | 不支持 |
|
|
554
594
|
| Browser Dev Host | 不支持 | 不支持 | 不支持 |
|
|
555
595
|
|
|
556
596
|
当前 Runtime 认识但 Host 未实现时返回 `METHOD_FORBIDDEN`;旧 Runtime 收到新 method 时返回
|
|
557
|
-
`METHOD_NOT_FOUND
|
|
558
|
-
|
|
559
|
-
当前任何 Host 都不提供 Blob 或内存假下载。
|
|
597
|
+
`METHOD_NOT_FOUND`。新 PC V1 注入真实文件与流式下载 primitive;其他当前 Host 未实现时仍不
|
|
598
|
+
提供 throwing stub、Blob 或内存假下载。
|
|
560
599
|
|
|
561
600
|
### 路径与创建
|
|
562
601
|
|
|
@@ -582,9 +621,10 @@ async function saveFromUserAction(text: string) {
|
|
|
582
621
|
}
|
|
583
622
|
```
|
|
584
623
|
|
|
585
|
-
`saveFile()`
|
|
586
|
-
|
|
587
|
-
|
|
624
|
+
`saveFile()` 请求 Host 返回精确 File 授权,不会同时创建或保留 Directory 授权。新 PC 当前先让
|
|
625
|
+
用户选择保存目录,再以 `suggestedName` 独占创建空文件;同名文件抛出 `FILE_ALREADY_EXISTS`,
|
|
626
|
+
不会静默覆盖。V1 不接受 `accept`;扩展名过滤只属于 `pickFiles({ accept: ['.json'] })`。外部授权
|
|
627
|
+
仅在当前 Runtime session 有效。
|
|
588
628
|
|
|
589
629
|
`pickFiles()` / `pickDirectory()` 默认返回 `mode: 'read'` 的授权;只有显式传入
|
|
590
630
|
`multiple: true` 时,`pickFiles()` 才允许 Host 返回多个文件。需要修改文件、在所选目录中创建
|
|
@@ -640,6 +680,8 @@ try {
|
|
|
640
680
|
|
|
641
681
|
- 根据 `error.code` 区分运行环境、权限、超时和业务失败,不要只比对错误文案。
|
|
642
682
|
- 权限失败时给出可理解的提示,不要将它当成未登录。
|
|
683
|
+
- `PERMISSION_NOT_DECLARED` 表示当前版本没有在 `package.json#heybox.permissions` 声明所需权限,应修改项目配置并重新构建、提交版本。
|
|
684
|
+
- `PERMISSION_DENIED` 表示权限已声明,但需要的平台批准缺失或批准配置不足。首期只有 `network` 需要平台批准。
|
|
643
685
|
- `USER_GESTURE_REQUIRED` 表示潜在授权 UI 缺少可信用户手势,应让用户点击按钮后重试。
|
|
644
686
|
- `AUTHORIZATION_CANCELLED` 表示用户取消、拒绝或关闭授权页面,应正常结束当前操作。
|
|
645
687
|
- `SERVER_API_REQUIRED` 表示当前用户数据必须经开发者服务端 OpenAPI 获取,不应在页面重试对应 Host API。
|
|
@@ -772,7 +814,7 @@ onUnmounted(stopLifecycleEvents)
|
|
|
772
814
|
- 当前握手状态只通过 `getHandshakeState()` 查询、通过 `onHandshakeStateChange()` 订阅;订阅会立即回放当前值并返回取消函数。
|
|
773
815
|
- `ready` 事件只在握手成功瞬间派发,不会向晚订阅者重放,不能用于驱动按钮可用状态或替代握手状态 API。
|
|
774
816
|
- UI 可见性相关逻辑放在 `show`、`hide`。
|
|
775
|
-
- 使用
|
|
817
|
+
- 使用 `user.getInfo()` 的小程序可以在 `heybox_app_login_change` 后刷新本地状态。需要开发者服务端会话时使用 `auth.login()` 获取 code;两者都不依赖公开 `network` 权限。
|
|
776
818
|
- 组件或页面销毁时清理 `on` 注册的监听,避免重复响应。
|
|
777
819
|
- 生命周期事件只派发给注册当时存在的监听器,不会重放;一次性 `launch` 信息应在页面启动阶段通过业务能力调用处理。
|
|
778
820
|
- 收到 `unload` 后,当前 SDK 上下文不可恢复,未完成请求会失败;不要在同一页面上下文继续重试能力调用。
|
package/skill/references/cli.md
CHANGED
|
@@ -76,7 +76,7 @@ Top-level `hb-sdk deploy` has been hard-cut and must not be documented as a vali
|
|
|
76
76
|
新项目可以直接从模板开始:
|
|
77
77
|
|
|
78
78
|
```bash
|
|
79
|
-
npx @heybox/hb-sdk@
|
|
79
|
+
npx @heybox/hb-sdk@latest create my-miniapp
|
|
80
80
|
cd my-miniapp
|
|
81
81
|
npm install
|
|
82
82
|
npm run dev
|
|
@@ -84,7 +84,7 @@ npm run dev
|
|
|
84
84
|
|
|
85
85
|
默认产物是 Vanilla JavaScript + Vite HelloWorld,只演示一次 `ui.showToast()` 调用,并预填 `android`、`ios`、`ohos` 三个平台。Demo 可以整体删除,项目不绑定 Vue、TypeScript 或测试框架。
|
|
86
86
|
|
|
87
|
-
当前 `0.8`
|
|
87
|
+
当前 `0.8` 已发布为稳定版本,本页使用 `@latest` 创建项目。
|
|
88
88
|
|
|
89
89
|
已有项目则在项目目录运行 `npm run dev` 或 `hb-sdk dev`。
|
|
90
90
|
|
|
@@ -105,7 +105,7 @@ Agent rules:
|
|
|
105
105
|
hb-sdk dev
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
-
CLI 会启动页面服务并自动打开 Vue 3
|
|
108
|
+
CLI 会启动页面服务并自动打开 Vue 3 本地调试台。左侧集中放置日志、Storage 和问题三个诊断页签,右侧保持稳定的小程序内容与设备预览。
|
|
109
109
|
|
|
110
110
|
默认终端只显示启动结果、调试页地址、小程序地址和手机调试入口。排查启动问题时使用 `hb-sdk dev --verbose` 查看完整启动阶段;手机扫码调试凭证连续重试失败时,默认只在失败和恢复两次状态变化时提示。
|
|
111
111
|
|
|
@@ -113,7 +113,7 @@ CLI 会启动页面服务并自动打开 Vue 3 本地调试台。左侧集中放
|
|
|
113
113
|
|
|
114
114
|
浏览器调试入口不要求 CLI 登录或项目绑定。没有账号、绑定小程序或远端 Dev Context 时,页面和基础 Browser Mock 仍可启动;依赖这些上下文的能力会返回明确失败。远端管理、部署和发布仍要求完成登录与绑定。
|
|
115
115
|
|
|
116
|
-
`hb-sdk dev`
|
|
116
|
+
`hb-sdk dev` 从项目 `package.json` 读取开发者声明,并在远端权限快照可用时读取平台批准结果。只有当前版本声明且平台已批准 `network` 时才跳过平台 CSP;`useOfficialDomain` 不参与该判定。调试台不提供权限或平台批准修改入口;快照缺失或无效时保留平台 CSP。
|
|
117
117
|
|
|
118
118
|
Browser Mock 会自动在实时与兼容链路间切换。手机调试使用 `open_inapp`/`openWindow` 包裹的 LAN 短链接二维码(先开普通 H5 跳转页,再进入小程序并关闭中间页)。
|
|
119
119
|
|
|
@@ -125,7 +125,7 @@ Browser Mock 会自动在实时与兼容链路间切换。手机调试使用 `op
|
|
|
125
125
|
- SDK 初始化与用户身份授权流程
|
|
126
126
|
- 生命周期、Storage 和排行榜等能力
|
|
127
127
|
|
|
128
|
-
|
|
128
|
+
调试台提供紧凑的日志、当前小程序隔离作用域内的 Storage 只读快照和问题聚合。日志与网络记录只保留脱敏的诊断字段,不展示 payload、结果、查询参数、凭据或原始错误信息。工坊小程序默认不能进行网络请求,网络权限暂未开放申请,不要把本地结果当成线上能力。
|
|
129
129
|
|
|
130
130
|
右侧可切换 iPhone 16 Pro Max(`387 x 821`)与 Pixel 9 Pro(`322 x 716`)两个设备预设。尺寸对应固定上游设备外框的真实屏幕 opening;预设同时决定外框、状态栏、安全区和 viewport。切换设备不会重新加载小程序或重启 Runtime,页面状态和调试会话保持不变。授权与操作弹窗、Toast、Loading 和振动反馈均显示在设备预览内部,不会覆盖整个调试台。
|
|
131
131
|
|
|
@@ -164,7 +164,7 @@ hb-sdk build [--env <name>] [--verbose]
|
|
|
164
164
|
|
|
165
165
|
`hb-sdk build` 直接使用项目安装的 Vite,先清理再生成固定的 `dist/`,并校验小程序入口、Manifest 和可上传产物。它不执行类型检查,不要求 CLI 登录或绑定小程序,也不访问远端服务。项目必须在 `vite.config.ts` 中显式注册 `miniappManifest()`。
|
|
166
166
|
|
|
167
|
-
直接运行 `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 构建检查始终保留。
|
|
168
168
|
|
|
169
169
|
推荐由项目的 `scripts.build` 保留类型检查:
|
|
170
170
|
|
|
@@ -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.
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
|
|
29
29
|
新项目可先运行 `hb-sdk create my-miniapp` 获得 Vanilla JavaScript + Vite HelloWorld;模板只演示 Toast,业务代码可以直接替换。
|
|
30
30
|
|
|
31
|
-
如果页面不需要小黑盒开放能力,可以不接入 SDK。SDK
|
|
31
|
+
如果页面不需要小黑盒开放能力,可以不接入 SDK。SDK 导入时会自动启动握手,能力调用会自动等待;使用受保护能力前需在 `package.json#heybox.permissions` 声明对应权限,详见[权限声明](https://docs.xiaoheihe.cn/hb_sdk/guide/permissions)。
|
|
32
32
|
|
|
33
33
|
## 交互控件与握手状态
|
|
34
34
|
|
|
@@ -49,9 +49,9 @@ onUnmounted(stopHandshakeState)
|
|
|
49
49
|
|
|
50
50
|
把 `sdkReady` 用作按钮的 `disabled` 条件。订阅会立即回放当前状态,因此晚挂载组件也能得到 `ready` 或 `failed` 终态。`ready` 生命周期事件只在握手成功瞬间派发且不会重放,不能作为当前状态来源。
|
|
51
51
|
|
|
52
|
-
##
|
|
52
|
+
## 读取当前用户
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
声明 `userInfo` 后,可以读取按小程序隔离的 `app_user_id` 和已授权资料。该能力不依赖公开 `network` 权限:
|
|
55
55
|
|
|
56
56
|
```ts
|
|
57
57
|
import hbSDK from '@heybox/hb-sdk'
|
|
@@ -64,9 +64,9 @@ async function getCurrentUser() {
|
|
|
64
64
|
|
|
65
65
|
`user.getInfo()` 不展示授权弹窗,也不要求可信用户手势。未登录时返回未登录状态;已登录时隐式授予当前本地用户 scopes(`identity`、`profile`),静默返回 `userInfo.app_user_id`、`profile.nickname` 和 `profile.avatar`。这条路径不能获取授权码或调用 OpenAPI,也不能把身份或资料发送到外部服务。
|
|
66
66
|
|
|
67
|
-
##
|
|
67
|
+
## 获取服务端授权码
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
声明 `userInfo` 后,可通过 `auth.login()` 获取短期授权码。登录可能展示 UI,因此应绑定到按钮点击等明确的用户操作。该调用内部使用 Host 受信请求,不依赖公开 `network` 权限;示例中的 `network.request()` 另需声明并获得 `network` 平台批准。
|
|
70
70
|
|
|
71
71
|
SDK 会自动完成握手。登录按钮应按上面的持久握手状态启用;点击回调直接调用 `auth.login()`,不要先等待其他异步任务,以免首次操作丢失可信手势。
|
|
72
72
|
|
|
@@ -135,15 +135,14 @@ try {
|
|
|
135
135
|
|
|
136
136
|
| Host | `files.sandbox` | 外部 picker | `network.download()` |
|
|
137
137
|
| ---------------- | --------------- | ----------- | -------------------- |
|
|
138
|
-
|
|
|
138
|
+
| 新 PC | 支持 | 支持 | 支持 |
|
|
139
139
|
| Mobile | 不支持 | 不支持 | 不支持 |
|
|
140
140
|
| Web | 不支持 | 不支持 | 不支持 |
|
|
141
141
|
| Browser Dev Host | 不支持 | 不支持 | 不支持 |
|
|
142
142
|
|
|
143
143
|
当前 Runtime 认识但 Host 未实现时返回 `METHOD_FORBIDDEN`;旧 Runtime 收到新 method 时返回
|
|
144
|
-
`METHOD_NOT_FOUND
|
|
145
|
-
|
|
146
|
-
当前任何 Host 都不提供 Blob 或内存假下载。
|
|
144
|
+
`METHOD_NOT_FOUND`。新 PC V1 注入真实文件与流式下载 primitive;其他当前 Host 未实现时仍不
|
|
145
|
+
提供 throwing stub、Blob 或内存假下载。
|
|
147
146
|
|
|
148
147
|
### 路径与创建
|
|
149
148
|
|
|
@@ -169,9 +168,10 @@ async function saveFromUserAction(text: string) {
|
|
|
169
168
|
}
|
|
170
169
|
```
|
|
171
170
|
|
|
172
|
-
`saveFile()`
|
|
173
|
-
|
|
174
|
-
|
|
171
|
+
`saveFile()` 请求 Host 返回精确 File 授权,不会同时创建或保留 Directory 授权。新 PC 当前先让
|
|
172
|
+
用户选择保存目录,再以 `suggestedName` 独占创建空文件;同名文件抛出 `FILE_ALREADY_EXISTS`,
|
|
173
|
+
不会静默覆盖。V1 不接受 `accept`;扩展名过滤只属于 `pickFiles({ accept: ['.json'] })`。外部授权
|
|
174
|
+
仅在当前 Runtime session 有效。
|
|
175
175
|
|
|
176
176
|
`pickFiles()` / `pickDirectory()` 默认返回 `mode: 'read'` 的授权;只有显式传入
|
|
177
177
|
`multiple: true` 时,`pickFiles()` 才允许 Host 返回多个文件。需要修改文件、在所选目录中创建
|
|
@@ -202,16 +202,17 @@ Runtime session 有效。
|
|
|
202
202
|
|
|
203
203
|
`app_user_id` 是平台为“用户 × 当前小程序”生成的稳定、隔离标识,不是黑盒用户 ID。它是不透明字符串,只能在当前小程序内使用,不能解析或跨小程序关联。
|
|
204
204
|
|
|
205
|
-
|
|
205
|
+
身份能力与公开 `network` 权限相互独立。根据业务需要选择入口,并在 `package.json#heybox.permissions` 声明对应权限:
|
|
206
206
|
|
|
207
|
-
|
|
|
208
|
-
|
|
|
209
|
-
|
|
|
210
|
-
|
|
|
207
|
+
| 身份入口 | 权限 | 结果用途 |
|
|
208
|
+
| ------------------------- | -------------- | ------------------------------------------------ |
|
|
209
|
+
| `auth.login({ scopes? })` | `userInfo` | 获取短期授权码,由开发者服务端换取 OpenAPI token |
|
|
210
|
+
| `user.getInfo()` | `userInfo` | 读取当前用户的隔离身份及已授权资料 |
|
|
211
|
+
| `user.getSteamGameList()` | `steamLibrary` | 读取当前用户的 Steam 游戏库 |
|
|
211
212
|
|
|
212
213
|
不要混用两条路径。SDK 不向小程序页面提供 token、cookie、黑盒用户 ID 或平台私有凭据。
|
|
213
214
|
|
|
214
|
-
##
|
|
215
|
+
## 获取服务端授权码
|
|
215
216
|
|
|
216
217
|
在登录、绑定账号或读取资料等明确的用户操作中调用 `auth.login()`:
|
|
217
218
|
|
|
@@ -265,9 +266,13 @@ async function loginFromUserAction() {
|
|
|
265
266
|
|
|
266
267
|
用户已授权所需 scope 时,`auth.login()` 可以不展示 UI,静默返回新的短期授权码。业务仍应把可能出现的授权 UI 设计在明确的用户操作之后,不要在页面初始化阶段自动调用。
|
|
267
268
|
|
|
269
|
+
`auth.login()` 内部使用 Host 的受信请求,不会调用小程序公开的 `network.request()`,因此不要求声明 `network`。如果页面需要把 code 通过 `network.request()` 发给开发者服务端,则该请求本身仍需声明并获得 `network` 的平台批准。
|
|
270
|
+
|
|
271
|
+
OpenAPI 凭据、授权码和 access token 的生命周期也不由 `network` 权限开启或关闭。
|
|
272
|
+
|
|
268
273
|
## 撤销当前小程序授权
|
|
269
274
|
|
|
270
|
-
|
|
275
|
+
任何小程序都可以在明确的用户操作中撤销授权;`user.revokeAuthorization()` 位于无需声明白名单:
|
|
271
276
|
|
|
272
277
|
```ts
|
|
273
278
|
async function revokeAuthorizationFromUserAction() {
|
|
@@ -281,22 +286,11 @@ async function revokeAuthorizationFromUserAction() {
|
|
|
281
286
|
|
|
282
287
|
`user.revokeAuthorization()` 不接收参数。小程序页面不能提交小程序 ID、黑盒用户 ID 或手势标记;Runtime 从 Host 启动上下文和用户操作状态注入可信值。调用缺少可信用户手势时返回 `USER_GESTURE_REQUIRED`。
|
|
283
288
|
|
|
284
|
-
撤销成功后,后续 `auth.login()`
|
|
285
|
-
|
|
286
|
-
## 当前用户资料由服务端读取
|
|
287
|
-
|
|
288
|
-
已开通网络权限后,页面不再直接读取 Host 当前用户资料。`@heybox/hb-sdk` 根包实际导出的以下调用统一返回 `SERVER_API_REQUIRED`:
|
|
289
|
-
|
|
290
|
-
- `user.getInfo()`
|
|
291
|
-
- `user.getSteamGameList(options)`
|
|
289
|
+
撤销成功后,后续 `auth.login()` 会重新进入授权流程;再次调用 `user.getInfo()` 时会按现有用户授权规则读取身份。业务必须立即停止使用并清理此前保存的 `app_user_id`、用户资料和开发者服务端会话;SDK 不会删除业务自己的 localStorage、数据库或 cookie。
|
|
292
290
|
|
|
293
|
-
|
|
291
|
+
## 读取当前用户资料
|
|
294
292
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
## 未开通网络权限
|
|
298
|
-
|
|
299
|
-
未开通网络权限的小程序不走授权码流程。需要当前用户在本小程序内的稳定隔离身份和公开资料时调用:
|
|
293
|
+
需要当前用户在本小程序内的稳定隔离身份和已授权资料时调用:
|
|
300
294
|
|
|
301
295
|
```ts
|
|
302
296
|
import hbSDK from '@heybox/hb-sdk'
|
|
@@ -307,14 +301,16 @@ async function getCurrentUser() {
|
|
|
307
301
|
}
|
|
308
302
|
```
|
|
309
303
|
|
|
310
|
-
`user.getInfo()`
|
|
304
|
+
`user.getInfo()` 不依赖 `network`,但必须声明 `userInfo`。它延续现有交互:不展示授权弹窗,也不要求可信用户手势。未登录时返回 `isHeyboxAppLoggedIn: false`;已登录时按现有用户授权状态返回当前小程序隔离的 `app_user_id`,以及已授权的 `profile.nickname` 和 `profile.avatar` 等可用资料。用户授权与开发者权限声明是两层独立门禁,不能用声明代替用户同意。
|
|
311
305
|
|
|
312
|
-
|
|
306
|
+
Steam 游戏库使用 `user.getSteamGameList(options)`,要求声明 `steamLibrary`,同样不依赖 `network`。Host current-user capabilities 的既有账号绑定和数据可用性规则保持不变。
|
|
313
307
|
|
|
314
308
|
## 网络请求边界
|
|
315
309
|
|
|
316
310
|
`network.request()` 只用于访问开发者自己的业务服务。平台保留的 runtime auth 与 OpenAPI 内部路径不能通过该能力访问;身份交换必须由开发者服务端按公开后端文档完成。
|
|
317
311
|
|
|
312
|
+
完整权限配置与错误区别见[权限声明](https://docs.xiaoheihe.cn/hb_sdk/guide/permissions)。
|
|
313
|
+
|
|
318
314
|
## CLI 登录与用户登录
|
|
319
315
|
|
|
320
316
|
`hb-sdk login` 只给本地开发和远端管理命令建立 CLI 登录态,与小程序页面的 `auth.login()`、`user.getInfo()` 和用户授权完全无关。
|
|
@@ -372,7 +368,7 @@ onUnmounted(stopLifecycleEvents)
|
|
|
372
368
|
- 当前握手状态只通过 `getHandshakeState()` 查询、通过 `onHandshakeStateChange()` 订阅;订阅会立即回放当前值并返回取消函数。
|
|
373
369
|
- `ready` 事件只在握手成功瞬间派发,不会向晚订阅者重放,不能用于驱动按钮可用状态或替代握手状态 API。
|
|
374
370
|
- UI 可见性相关逻辑放在 `show`、`hide`。
|
|
375
|
-
- 使用
|
|
371
|
+
- 使用 `user.getInfo()` 的小程序可以在 `heybox_app_login_change` 后刷新本地状态。需要开发者服务端会话时使用 `auth.login()` 获取 code;两者都不依赖公开 `network` 权限。
|
|
376
372
|
- 组件或页面销毁时清理 `on` 注册的监听,避免重复响应。
|
|
377
373
|
- 生命周期事件只派发给注册当时存在的监听器,不会重放;一次性 `launch` 信息应在页面启动阶段通过业务能力调用处理。
|
|
378
374
|
- 收到 `unload` 后,当前 SDK 上下文不可恢复,未完成请求会失败;不要在同一页面上下文继续重试能力调用。
|
|
@@ -411,6 +407,8 @@ try {
|
|
|
411
407
|
|
|
412
408
|
- 根据 `error.code` 区分运行环境、权限、超时和业务失败,不要只比对错误文案。
|
|
413
409
|
- 权限失败时给出可理解的提示,不要将它当成未登录。
|
|
410
|
+
- `PERMISSION_NOT_DECLARED` 表示当前版本没有在 `package.json#heybox.permissions` 声明所需权限,应修改项目配置并重新构建、提交版本。
|
|
411
|
+
- `PERMISSION_DENIED` 表示权限已声明,但需要的平台批准缺失或批准配置不足。首期只有 `network` 需要平台批准。
|
|
414
412
|
- `USER_GESTURE_REQUIRED` 表示潜在授权 UI 缺少可信用户手势,应让用户点击按钮后重试。
|
|
415
413
|
- `AUTHORIZATION_CANCELLED` 表示用户取消、拒绝或关闭授权页面,应正常结束当前操作。
|
|
416
414
|
- `SERVER_API_REQUIRED` 表示当前用户数据必须经开发者服务端 OpenAPI 获取,不应在页面重试对应 Host API。
|
|
@@ -475,7 +473,7 @@ picker 取消、授权撤销、文件缺失、quota、下载状态或取消,
|
|
|
475
473
|
|
|
476
474
|
# 服务端登录门禁
|
|
477
475
|
|
|
478
|
-
|
|
476
|
+
声明 `userInfo` 后,小程序可以把“取得授权码并交给开发者服务端”收敛成一个用户操作函数。`auth.login()` 本身不依赖 `network`;以下示例使用 `network.request()` 传递 code,因此还需声明并获得 `network` 的平台批准:
|
|
479
477
|
|
|
480
478
|
示例中的 URL 是开发者自己的后端接口,不是黑盒 OpenAPI 地址。
|
|
481
479
|
|
|
@@ -613,7 +611,6 @@ if (sharedState && typeof sharedState === 'object' && !Array.isArray(sharedState
|
|
|
613
611
|
|
|
614
612
|
```ts
|
|
615
613
|
import hbSDK from '@heybox/hb-sdk'
|
|
616
|
-
|
|
617
614
|
```
|
|
618
615
|
|
|
619
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;
|
|
@@ -1 +1,4 @@
|
|
|
1
|
+
import { type ParsedMiniappPermissions } from './permissions';
|
|
1
2
|
export declare function readMiniappVersionFromPackageJson(root: string): string;
|
|
3
|
+
export declare function readMiniappPermissionsFromPackageJson(root: string, sdkVersion: string): ParsedMiniappPermissions;
|
|
4
|
+
export declare function resolveMiniappSdkVersion(): string;
|