@heybox/hb-sdk 0.8.0-alpha.10 → 0.8.0-alpha.13

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 (41) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +15 -9
  3. package/dist/cli-chunks/{build-aDJbiFqF.cjs → build-Bfm8_lwd.cjs} +5 -5
  4. package/dist/cli-chunks/{context-Dp36pZ9a.cjs → context-DKpo91h0.cjs} +2 -2
  5. package/dist/cli-chunks/{create-P3g0ricz.cjs → create-DaBc6N_y.cjs} +1 -1
  6. package/dist/cli-chunks/{dev-CisJkXuQ.cjs → dev-CQVme_RT.cjs} +17 -10
  7. package/dist/cli-chunks/{doctor-B-LF5-uj.cjs → doctor-Z28nbVwZ.cjs} +1 -1
  8. package/dist/cli-chunks/{index-CZGkk7fQ.cjs → index-BTtUJGMf.cjs} +2 -2
  9. package/dist/cli-chunks/{index-BDaeBI_B.cjs → index-CDyvjYvo.cjs} +15 -15
  10. package/dist/cli-chunks/{index.esm-NNLG29Tt.cjs → index.esm-D6VfG0x3.cjs} +7 -7
  11. package/dist/cli-chunks/{login-DTY5GolC.cjs → login-Ccwakey0.cjs} +2 -2
  12. package/dist/cli-chunks/{project-vite-DlCjHlu_.cjs → project-vite-Cw6AvXNS.cjs} +1 -1
  13. package/dist/cli-chunks/{remote-BBMr7j8W.cjs → remote-D51eSApF.cjs} +7 -7
  14. package/dist/cli-chunks/{runtime-gate-BppCl1r3.cjs → runtime-gate-DO9uSLbW.cjs} +1 -1
  15. package/dist/cli-chunks/{runtime-permission-env-CqsTHeas.cjs → runtime-permission-env-BJp9z8YR.cjs} +1 -1
  16. package/dist/cli-chunks/{session-CnGeZCRZ.cjs → session-2Y9_qjO5.cjs} +1 -1
  17. package/dist/cli-chunks/{skill-B0yAnPOJ.cjs → skill-D_ZY0m_b.cjs} +2 -2
  18. package/dist/cli-chunks/{version-DN5jrixS.cjs → version-DpF1KqoM.cjs} +1 -1
  19. package/dist/cli.cjs +1 -1
  20. package/dist/devtools/browser-dev-host/assets/browser-dev-host-TzYf9L6C.js +99 -0
  21. package/dist/devtools/browser-dev-host/assets/{index-Dh9H1JOm.js → index-C5MZZDa5.js} +4 -4
  22. package/dist/devtools/browser-dev-host/assets/index-P-ra4m1y.css +1 -0
  23. package/dist/devtools/browser-dev-host/assets/{workbench-state-wHgWRb7I.js → workbench-state-BwV7bm4n.js} +2 -2
  24. package/dist/devtools/browser-dev-host/index.html +3 -3
  25. package/dist/index.cjs.js +85 -1
  26. package/dist/index.esm.js +85 -1
  27. package/dist/vite.cjs.js +54 -5
  28. package/dist/vite.esm.js +54 -5
  29. package/package.json +6 -6
  30. package/skill/SKILL.md +1 -1
  31. package/skill/references/api-protocol.md +1 -1
  32. package/skill/references/api-root.md +41 -13
  33. package/skill/references/cli.md +2 -2
  34. package/skill/references/examples.md +3 -3
  35. package/skill/references/recipes.md +7 -7
  36. package/skill/references/safety-boundaries.md +7 -1
  37. package/skill/skill.json +5 -5
  38. package/types/core/mini-dev-console.d.ts +36 -0
  39. package/types/vite/index.d.ts +3 -1
  40. package/dist/devtools/browser-dev-host/assets/browser-dev-host-BhZGUyYw.js +0 -97
  41. package/dist/devtools/browser-dev-host/assets/index-DJFB5ySU.css +0 -1
package/dist/index.cjs.js CHANGED
@@ -799,7 +799,7 @@ function createMessageId() {
799
799
  /** 构建时替换为当前发布包的实际版本。 */
800
800
  const HB_SDK_VERSION = typeof undefined === 'string'
801
801
  ? undefined
802
- : '0.8.0-alpha.10';
802
+ : '0.8.0-alpha.13';
803
803
 
804
804
  const DEFAULT_TIMEOUT = 10000;
805
805
  const HANDSHAKE_RETRY_INTERVAL = 250;
@@ -3766,7 +3766,91 @@ function createMiniProgramSDK(options) {
3766
3766
  return new MiniProgramSDK(options);
3767
3767
  }
3768
3768
 
3769
+ /**
3770
+ * iframe 与调试台页面的开发期 console 捕获转发。
3771
+ *
3772
+ * 双条件门控(iframe 转发):
3773
+ * 1. 构建期:`hb-sdk dev`(vite serve)注入 `false`;`hb-sdk build` /
3774
+ * `vite build`(生产)永不注入或替换为 `false`,本模块被死代码消除。
3775
+ * 2. 运行期:仅在 `window.name` 为 `__hb_sdk_mini_dev__` 的调试 iframe 中激活,
3776
+ * 用户设备上的正式运行环境没有该标记。
3777
+ *
3778
+ * 无侵入 patch `console.log/debug/info/warn/error`:原样放行(DevTools 不受影响)+
3779
+ * 通过 `window.parent.postMessage` 转发给调试台(CSP 的 connect-src 不约束 postMessage,
3780
+ * 网络上报由调试台页面代理)。发送全程静默:失败不得回打 console,避免自触发死循环。
3781
+ *
3782
+ * 激活时机:由 SDK 默认单例初始化时调用(业务 `import '@heybox/hb-sdk'` 即生效);
3783
+ * iframe 标记由调试台 `iframe.name` 与 vite dev 注入的无依赖 bootstrap 共同设置。
3784
+ * 调试台页面自身(runtime 跑在这里,`[hb-sdk-runtime]` 日志不经过 iframe)另用
3785
+ * `installMiniDevConsoleSelfCapture` 接入「日志」页签(source: 'host')。
3786
+ */
3787
+ const MINI_DEV_IFRAME_WINDOW_NAME = '__hb_sdk_mini_dev__';
3788
+ const MINI_DEV_CONSOLE_EVENT_TYPE = 'hb-sdk:mini-dev-console';
3789
+ /** 调试台页面与 iframe bootstrap 共用的已安装标记(window/console 上的属性名)。 */
3790
+ const MINI_DEV_CONSOLE_INSTALL_FLAG = '__hb_sdk_mini_dev_console_installed__';
3791
+ /** 调试台页面自捕获(source: 'host')与 iframe 转发共用的已安装标记。 */
3792
+ const INSTALL_FLAG = MINI_DEV_CONSOLE_INSTALL_FLAG;
3793
+ function isDevLoggingEnabled() {
3794
+ if (typeof false !== 'undefined' && false !== true) {
3795
+ return false;
3796
+ }
3797
+ return typeof window !== 'undefined' && window.name === MINI_DEV_IFRAME_WINDOW_NAME;
3798
+ }
3799
+ const levels = ['log', 'debug', 'info', 'warn', 'error'];
3800
+ function patchConsoleLevels(consoleRef, deliver, owner) {
3801
+ if (!owner || owner[INSTALL_FLAG] === true) {
3802
+ return false;
3803
+ }
3804
+ let patched = false;
3805
+ for (const level of levels) {
3806
+ const original = consoleRef[level];
3807
+ if (typeof original !== 'function') {
3808
+ continue;
3809
+ }
3810
+ const forward = function (...args) {
3811
+ try {
3812
+ deliver(level, args);
3813
+ }
3814
+ catch {
3815
+ /* 转发失败必须静默,禁止回打 console 造成自触发循环。 */
3816
+ }
3817
+ return original.apply(this, args);
3818
+ };
3819
+ try {
3820
+ consoleRef[level] = forward;
3821
+ patched = true;
3822
+ }
3823
+ catch {
3824
+ return patched;
3825
+ }
3826
+ }
3827
+ if (patched) {
3828
+ owner[INSTALL_FLAG] = true;
3829
+ }
3830
+ return patched;
3831
+ }
3832
+ function installMiniDevConsoleForwarding(consoleRef = console) {
3833
+ if (!isDevLoggingEnabled()) {
3834
+ return;
3835
+ }
3836
+ patchConsoleLevels(consoleRef, (level, args) => {
3837
+ const message = {
3838
+ type: MINI_DEV_CONSOLE_EVENT_TYPE,
3839
+ detail: { level, args, timestamp: Date.now() },
3840
+ };
3841
+ window.parent?.postMessage(message, '*');
3842
+ }, typeof window === 'undefined' ? undefined : window);
3843
+ }
3844
+
3769
3845
  let defaultSDK = createMiniProgramSDK();
3846
+ // 开发期调试台 console 捕获:双条件门控(vite serve 注入 define + 调试 iframe 标记),
3847
+ // 生产构建被死代码消除,正式环境无副作用。失败静默,绝不影响 SDK 初始化。
3848
+ try {
3849
+ installMiniDevConsoleForwarding();
3850
+ }
3851
+ catch {
3852
+ /* 捕获层异常不得阻断 SDK 单例创建。 */
3853
+ }
3770
3854
  function getDefaultSDK() {
3771
3855
  if (!defaultSDK) {
3772
3856
  defaultSDK = createMiniProgramSDK();
package/dist/index.esm.js CHANGED
@@ -795,7 +795,7 @@ function createMessageId() {
795
795
  /** 构建时替换为当前发布包的实际版本。 */
796
796
  const HB_SDK_VERSION = typeof undefined === 'string'
797
797
  ? undefined
798
- : '0.8.0-alpha.10';
798
+ : '0.8.0-alpha.13';
799
799
 
800
800
  const DEFAULT_TIMEOUT = 10000;
801
801
  const HANDSHAKE_RETRY_INTERVAL = 250;
@@ -3762,7 +3762,91 @@ function createMiniProgramSDK(options) {
3762
3762
  return new MiniProgramSDK(options);
3763
3763
  }
3764
3764
 
3765
+ /**
3766
+ * iframe 与调试台页面的开发期 console 捕获转发。
3767
+ *
3768
+ * 双条件门控(iframe 转发):
3769
+ * 1. 构建期:`hb-sdk dev`(vite serve)注入 `false`;`hb-sdk build` /
3770
+ * `vite build`(生产)永不注入或替换为 `false`,本模块被死代码消除。
3771
+ * 2. 运行期:仅在 `window.name` 为 `__hb_sdk_mini_dev__` 的调试 iframe 中激活,
3772
+ * 用户设备上的正式运行环境没有该标记。
3773
+ *
3774
+ * 无侵入 patch `console.log/debug/info/warn/error`:原样放行(DevTools 不受影响)+
3775
+ * 通过 `window.parent.postMessage` 转发给调试台(CSP 的 connect-src 不约束 postMessage,
3776
+ * 网络上报由调试台页面代理)。发送全程静默:失败不得回打 console,避免自触发死循环。
3777
+ *
3778
+ * 激活时机:由 SDK 默认单例初始化时调用(业务 `import '@heybox/hb-sdk'` 即生效);
3779
+ * iframe 标记由调试台 `iframe.name` 与 vite dev 注入的无依赖 bootstrap 共同设置。
3780
+ * 调试台页面自身(runtime 跑在这里,`[hb-sdk-runtime]` 日志不经过 iframe)另用
3781
+ * `installMiniDevConsoleSelfCapture` 接入「日志」页签(source: 'host')。
3782
+ */
3783
+ const MINI_DEV_IFRAME_WINDOW_NAME = '__hb_sdk_mini_dev__';
3784
+ const MINI_DEV_CONSOLE_EVENT_TYPE = 'hb-sdk:mini-dev-console';
3785
+ /** 调试台页面与 iframe bootstrap 共用的已安装标记(window/console 上的属性名)。 */
3786
+ const MINI_DEV_CONSOLE_INSTALL_FLAG = '__hb_sdk_mini_dev_console_installed__';
3787
+ /** 调试台页面自捕获(source: 'host')与 iframe 转发共用的已安装标记。 */
3788
+ const INSTALL_FLAG = MINI_DEV_CONSOLE_INSTALL_FLAG;
3789
+ function isDevLoggingEnabled() {
3790
+ if (typeof false !== 'undefined' && false !== true) {
3791
+ return false;
3792
+ }
3793
+ return typeof window !== 'undefined' && window.name === MINI_DEV_IFRAME_WINDOW_NAME;
3794
+ }
3795
+ const levels = ['log', 'debug', 'info', 'warn', 'error'];
3796
+ function patchConsoleLevels(consoleRef, deliver, owner) {
3797
+ if (!owner || owner[INSTALL_FLAG] === true) {
3798
+ return false;
3799
+ }
3800
+ let patched = false;
3801
+ for (const level of levels) {
3802
+ const original = consoleRef[level];
3803
+ if (typeof original !== 'function') {
3804
+ continue;
3805
+ }
3806
+ const forward = function (...args) {
3807
+ try {
3808
+ deliver(level, args);
3809
+ }
3810
+ catch {
3811
+ /* 转发失败必须静默,禁止回打 console 造成自触发循环。 */
3812
+ }
3813
+ return original.apply(this, args);
3814
+ };
3815
+ try {
3816
+ consoleRef[level] = forward;
3817
+ patched = true;
3818
+ }
3819
+ catch {
3820
+ return patched;
3821
+ }
3822
+ }
3823
+ if (patched) {
3824
+ owner[INSTALL_FLAG] = true;
3825
+ }
3826
+ return patched;
3827
+ }
3828
+ function installMiniDevConsoleForwarding(consoleRef = console) {
3829
+ if (!isDevLoggingEnabled()) {
3830
+ return;
3831
+ }
3832
+ patchConsoleLevels(consoleRef, (level, args) => {
3833
+ const message = {
3834
+ type: MINI_DEV_CONSOLE_EVENT_TYPE,
3835
+ detail: { level, args, timestamp: Date.now() },
3836
+ };
3837
+ window.parent?.postMessage(message, '*');
3838
+ }, typeof window === 'undefined' ? undefined : window);
3839
+ }
3840
+
3765
3841
  let defaultSDK = createMiniProgramSDK();
3842
+ // 开发期调试台 console 捕获:双条件门控(vite serve 注入 define + 调试 iframe 标记),
3843
+ // 生产构建被死代码消除,正式环境无副作用。失败静默,绝不影响 SDK 初始化。
3844
+ try {
3845
+ installMiniDevConsoleForwarding();
3846
+ }
3847
+ catch {
3848
+ /* 捕获层异常不得阻断 SDK 单例创建。 */
3849
+ }
3766
3850
  function getDefaultSDK() {
3767
3851
  if (!defaultSDK) {
3768
3852
  defaultSDK = createMiniProgramSDK();
package/dist/vite.cjs.js CHANGED
@@ -8,7 +8,30 @@ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentS
8
8
  /** 构建时替换为当前发布包的实际版本。 */
9
9
  const HB_SDK_VERSION = typeof undefined === 'string'
10
10
  ? undefined
11
- : '0.8.0-alpha.10';
11
+ : '0.8.0-alpha.13';
12
+
13
+ /**
14
+ * iframe 与调试台页面的开发期 console 捕获转发。
15
+ *
16
+ * 双条件门控(iframe 转发):
17
+ * 1. 构建期:`hb-sdk dev`(vite serve)注入 `false`;`hb-sdk build` /
18
+ * `vite build`(生产)永不注入或替换为 `false`,本模块被死代码消除。
19
+ * 2. 运行期:仅在 `window.name` 为 `__hb_sdk_mini_dev__` 的调试 iframe 中激活,
20
+ * 用户设备上的正式运行环境没有该标记。
21
+ *
22
+ * 无侵入 patch `console.log/debug/info/warn/error`:原样放行(DevTools 不受影响)+
23
+ * 通过 `window.parent.postMessage` 转发给调试台(CSP 的 connect-src 不约束 postMessage,
24
+ * 网络上报由调试台页面代理)。发送全程静默:失败不得回打 console,避免自触发死循环。
25
+ *
26
+ * 激活时机:由 SDK 默认单例初始化时调用(业务 `import '@heybox/hb-sdk'` 即生效);
27
+ * iframe 标记由调试台 `iframe.name` 与 vite dev 注入的无依赖 bootstrap 共同设置。
28
+ * 调试台页面自身(runtime 跑在这里,`[hb-sdk-runtime]` 日志不经过 iframe)另用
29
+ * `installMiniDevConsoleSelfCapture` 接入「日志」页签(source: 'host')。
30
+ */
31
+ const MINI_DEV_IFRAME_WINDOW_NAME = '__hb_sdk_mini_dev__';
32
+ const MINI_DEV_CONSOLE_EVENT_TYPE = 'hb-sdk:mini-dev-console';
33
+ /** 调试台页面与 iframe bootstrap 共用的已安装标记(window/console 上的属性名)。 */
34
+ const MINI_DEV_CONSOLE_INSTALL_FLAG = '__hb_sdk_mini_dev_console_installed__';
12
35
 
13
36
  var re = {exports: {}};
14
37
 
@@ -11857,8 +11880,29 @@ function shouldSkipMiniappPlatformCspFromEnv(env = process.env) {
11857
11880
  return env[HB_SDK_RUNTIME_PERMISSION_CONTEXT_ENV] === VERIFIED_RUNTIME_PERMISSION_CONTEXT && env[HB_SDK_RUNTIME_USE_OFFICIAL_DOMAIN_ENV] === '1';
11858
11881
  }
11859
11882
 
11883
+ /**
11884
+ * dev serve 时在入口 HTML 最早位置注入无依赖 console 捕获 bootstrap。
11885
+ *
11886
+ * 必须内联完整 patch 逻辑而非等 SDK 模块加载:vite client、业务代码的 console 调用
11887
+ * 都可能早于 SDK 单例初始化(如 [vite] connecting)。捕获条件:
11888
+ * 1. 构建期只有 vite serve 走到本分支(生产构建无此代码,双保险之 define 常量仍注入给 SDK 侧);
11889
+ * 2. 运行期仅调试 iframe(window.name 标记由调试台 iframe.name 与本 bootstrap 设置)激活。
11890
+ * 转发经 window.parent.postMessage(CSP connect-src 不约束 postMessage),失败静默,
11891
+ * 严禁回打 console 造成自触发循环。SDK 侧 installMiniDevConsoleForwarding 安装时
11892
+ * 检测同款 INSTALL_FLAG,不会重复 patch。
11893
+ */
11894
+ function injectMiniDevConsoleBootstrap(html) {
11895
+ 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>`;
11896
+ const headIndex = html.indexOf('<head>');
11897
+ if (headIndex < 0) {
11898
+ return html;
11899
+ }
11900
+ const insertAt = headIndex + '<head>'.length;
11901
+ return `${html.slice(0, insertAt)}${bootstrap}${html.slice(insertAt)}`;
11902
+ }
11860
11903
  const sdkVersionPlaceholder = ['__HB_SDK', 'VERSION__'].join('_');
11861
11904
  const sdkVersionBuildConstant = ['__HB_SDK_BUILD', 'VERSION__'].join('_');
11905
+ const miniDevLoggingConstant = ['__HB_SDK_DEV', 'LOGGING__'].join('_');
11862
11906
  function miniappManifest(options) {
11863
11907
  const platforms = validateMiniappPlatforms(options?.platforms, 'miniappManifest().platforms');
11864
11908
  const skipPlatformCsp = shouldSkipMiniappPlatformCspFromEnv();
@@ -11870,12 +11914,17 @@ function miniappManifest(options) {
11870
11914
  let priorBuildError;
11871
11915
  return {
11872
11916
  name: 'heybox-miniapp-manifest',
11873
- config(config) {
11917
+ config(config, env) {
11874
11918
  assertMiniappViteBase(config.base);
11919
+ // command 在本钩子时序早于 configResolved,必须取自 env 命令而非闭包;
11920
+ // 旧调用方(测试等)未传 env 时按 build 处理。
11921
+ const isServe = env?.command === 'serve';
11875
11922
  return {
11876
11923
  ...(config.base === undefined ? { base: './' } : {}),
11877
11924
  define: {
11878
11925
  [sdkVersionBuildConstant]: JSON.stringify(resolveSdkVersion()),
11926
+ // 仅 vite serve(hb-sdk dev)注入;vite build / hb-sdk build 永不注入,捕获模块被死代码消除。
11927
+ ...(isServe ? { [miniDevLoggingConstant]: 'true' } : {}),
11879
11928
  },
11880
11929
  };
11881
11930
  },
@@ -11897,12 +11946,12 @@ function miniappManifest(options) {
11897
11946
  }
11898
11947
  },
11899
11948
  transformIndexHtml(html) {
11900
- return enforceMiniappHtmlPolicy(html, {
11949
+ const enforced = enforceMiniappHtmlPolicy(html, {
11901
11950
  ...(command === 'serve' ? { hmrWebSocketUrl } : {}),
11902
11951
  skipPlatformCsp,
11903
11952
  });
11904
- },
11905
- async closeBundle() {
11953
+ return command === 'serve' ? injectMiniDevConsoleBootstrap(enforced) : enforced;
11954
+ }, async closeBundle() {
11906
11955
  // Rollup 在 buildStart/transform 失败后仍会调用 closeBundle。
11907
11956
  // 若此时再抛「缺 index.html」等二次错误,会掩盖真实失败原因。
11908
11957
  if (priorBuildError) {
package/dist/vite.esm.js CHANGED
@@ -5,7 +5,30 @@ import { AsyncLocalStorage } from 'node:async_hooks';
5
5
  /** 构建时替换为当前发布包的实际版本。 */
6
6
  const HB_SDK_VERSION = typeof undefined === 'string'
7
7
  ? undefined
8
- : '0.8.0-alpha.10';
8
+ : '0.8.0-alpha.13';
9
+
10
+ /**
11
+ * iframe 与调试台页面的开发期 console 捕获转发。
12
+ *
13
+ * 双条件门控(iframe 转发):
14
+ * 1. 构建期:`hb-sdk dev`(vite serve)注入 `false`;`hb-sdk build` /
15
+ * `vite build`(生产)永不注入或替换为 `false`,本模块被死代码消除。
16
+ * 2. 运行期:仅在 `window.name` 为 `__hb_sdk_mini_dev__` 的调试 iframe 中激活,
17
+ * 用户设备上的正式运行环境没有该标记。
18
+ *
19
+ * 无侵入 patch `console.log/debug/info/warn/error`:原样放行(DevTools 不受影响)+
20
+ * 通过 `window.parent.postMessage` 转发给调试台(CSP 的 connect-src 不约束 postMessage,
21
+ * 网络上报由调试台页面代理)。发送全程静默:失败不得回打 console,避免自触发死循环。
22
+ *
23
+ * 激活时机:由 SDK 默认单例初始化时调用(业务 `import '@heybox/hb-sdk'` 即生效);
24
+ * iframe 标记由调试台 `iframe.name` 与 vite dev 注入的无依赖 bootstrap 共同设置。
25
+ * 调试台页面自身(runtime 跑在这里,`[hb-sdk-runtime]` 日志不经过 iframe)另用
26
+ * `installMiniDevConsoleSelfCapture` 接入「日志」页签(source: 'host')。
27
+ */
28
+ const MINI_DEV_IFRAME_WINDOW_NAME = '__hb_sdk_mini_dev__';
29
+ const MINI_DEV_CONSOLE_EVENT_TYPE = 'hb-sdk:mini-dev-console';
30
+ /** 调试台页面与 iframe bootstrap 共用的已安装标记(window/console 上的属性名)。 */
31
+ const MINI_DEV_CONSOLE_INSTALL_FLAG = '__hb_sdk_mini_dev_console_installed__';
9
32
 
10
33
  var re = {exports: {}};
11
34
 
@@ -11854,8 +11877,29 @@ function shouldSkipMiniappPlatformCspFromEnv(env = process.env) {
11854
11877
  return env[HB_SDK_RUNTIME_PERMISSION_CONTEXT_ENV] === VERIFIED_RUNTIME_PERMISSION_CONTEXT && env[HB_SDK_RUNTIME_USE_OFFICIAL_DOMAIN_ENV] === '1';
11855
11878
  }
11856
11879
 
11880
+ /**
11881
+ * dev serve 时在入口 HTML 最早位置注入无依赖 console 捕获 bootstrap。
11882
+ *
11883
+ * 必须内联完整 patch 逻辑而非等 SDK 模块加载:vite client、业务代码的 console 调用
11884
+ * 都可能早于 SDK 单例初始化(如 [vite] connecting)。捕获条件:
11885
+ * 1. 构建期只有 vite serve 走到本分支(生产构建无此代码,双保险之 define 常量仍注入给 SDK 侧);
11886
+ * 2. 运行期仅调试 iframe(window.name 标记由调试台 iframe.name 与本 bootstrap 设置)激活。
11887
+ * 转发经 window.parent.postMessage(CSP connect-src 不约束 postMessage),失败静默,
11888
+ * 严禁回打 console 造成自触发循环。SDK 侧 installMiniDevConsoleForwarding 安装时
11889
+ * 检测同款 INSTALL_FLAG,不会重复 patch。
11890
+ */
11891
+ function injectMiniDevConsoleBootstrap(html) {
11892
+ 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>`;
11893
+ const headIndex = html.indexOf('<head>');
11894
+ if (headIndex < 0) {
11895
+ return html;
11896
+ }
11897
+ const insertAt = headIndex + '<head>'.length;
11898
+ return `${html.slice(0, insertAt)}${bootstrap}${html.slice(insertAt)}`;
11899
+ }
11857
11900
  const sdkVersionPlaceholder = ['__HB_SDK', 'VERSION__'].join('_');
11858
11901
  const sdkVersionBuildConstant = ['__HB_SDK_BUILD', 'VERSION__'].join('_');
11902
+ const miniDevLoggingConstant = ['__HB_SDK_DEV', 'LOGGING__'].join('_');
11859
11903
  function miniappManifest(options) {
11860
11904
  const platforms = validateMiniappPlatforms(options?.platforms, 'miniappManifest().platforms');
11861
11905
  const skipPlatformCsp = shouldSkipMiniappPlatformCspFromEnv();
@@ -11867,12 +11911,17 @@ function miniappManifest(options) {
11867
11911
  let priorBuildError;
11868
11912
  return {
11869
11913
  name: 'heybox-miniapp-manifest',
11870
- config(config) {
11914
+ config(config, env) {
11871
11915
  assertMiniappViteBase(config.base);
11916
+ // command 在本钩子时序早于 configResolved,必须取自 env 命令而非闭包;
11917
+ // 旧调用方(测试等)未传 env 时按 build 处理。
11918
+ const isServe = env?.command === 'serve';
11872
11919
  return {
11873
11920
  ...(config.base === undefined ? { base: './' } : {}),
11874
11921
  define: {
11875
11922
  [sdkVersionBuildConstant]: JSON.stringify(resolveSdkVersion()),
11923
+ // 仅 vite serve(hb-sdk dev)注入;vite build / hb-sdk build 永不注入,捕获模块被死代码消除。
11924
+ ...(isServe ? { [miniDevLoggingConstant]: 'true' } : {}),
11876
11925
  },
11877
11926
  };
11878
11927
  },
@@ -11894,12 +11943,12 @@ function miniappManifest(options) {
11894
11943
  }
11895
11944
  },
11896
11945
  transformIndexHtml(html) {
11897
- return enforceMiniappHtmlPolicy(html, {
11946
+ const enforced = enforceMiniappHtmlPolicy(html, {
11898
11947
  ...(command === 'serve' ? { hmrWebSocketUrl } : {}),
11899
11948
  skipPlatformCsp,
11900
11949
  });
11901
- },
11902
- async closeBundle() {
11950
+ return command === 'serve' ? injectMiniDevConsoleBootstrap(enforced) : enforced;
11951
+ }, async closeBundle() {
11903
11952
  // Rollup 在 buildStart/transform 失败后仍会调用 closeBundle。
11904
11953
  // 若此时再抛「缺 index.html」等二次错误,会掩盖真实失败原因。
11905
11954
  if (priorBuildError) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heybox/hb-sdk",
3
- "version": "0.8.0-alpha.10",
3
+ "version": "0.8.0-alpha.13",
4
4
  "sideEffects": [
5
5
  "./src/index.ts",
6
6
  "./src/core/singleton.ts",
@@ -62,7 +62,7 @@
62
62
  "skills": "1.5.23",
63
63
  "undici": "^7.28.0",
64
64
  "ws": "^8.18.0",
65
- "@heybox/hb-sdk-protocol": "0.8.0-alpha.10"
65
+ "@heybox/hb-sdk-protocol": "0.8.0-alpha.13"
66
66
  },
67
67
  "peerDependencies": {
68
68
  "vite": ">=5"
@@ -113,13 +113,13 @@
113
113
  "vue-tsc": "^3.3.7",
114
114
  "vite": "^8.0.12",
115
115
  "vitest": "^3.2.4",
116
- "@heybox-domain/heybox-vue3-ui": "~0.1.0",
117
- "@heybox-domain/heybox-theme": "~0.1.0",
118
- "@heybox/hb-sdk-runtime": "~0.8.0-alpha.10",
119
116
  "@heybox/hb-api": "~1.28.2",
120
117
  "@heybox/runtime": "~0.2.0",
118
+ "@heybox/runtime-policy": "~0.2.0",
121
119
  "@heybox/runtime-transport-fetch": "~0.2.0",
122
- "@heybox/runtime-policy": "~0.2.0"
120
+ "@heybox/hb-sdk-runtime": "~0.8.0-alpha.13",
121
+ "@heybox-domain/heybox-theme": "~0.1.0",
122
+ "@heybox-domain/heybox-vue3-ui": "~0.1.0"
123
123
  },
124
124
  "publishConfig": {
125
125
  "registry": "https://registry.npmjs.org/",
package/skill/SKILL.md CHANGED
@@ -50,7 +50,7 @@ Apply these instructions when writing, reviewing, or debugging code that consume
50
50
  10. When authorization UI is required, call `auth.login()` from a trusted user action. Missing gesture returns `USER_GESTURE_REQUIRED`; cancelling, rejecting, or closing returns `AUTHORIZATION_CANCELLED` and does not confirm or change authorization. An already-authorized `auth.login()` request may return a new code silently.
51
51
  11. Use `share.showShareMenu({ post })` or `share.screenshot({ post })` to preset editable community destinations and topics. Pass partition IDs through `topicIds` and topic text without surrounding `#` through `topics`; do not construct the underlying client post protocol.
52
52
  12. Use `share.showShareMenu({ extra })` to open the share menu or `share.copyLink({ extra })` to copy and return the mini-program share link. `share.showShareMenu()` always uses the platform `common_share` landing page and does not accept a custom `url`. Read the JSON-compatible page state synchronously with `share.getExtra()` after launch, validate the developer-defined fields, and fall back to the default page when it returns `undefined`.
53
- 13. Treat `files` and `network.download()` as a retained public contract that is not yet enabled by a current Host. The legacy PC adapter was dropped because the new PC will implement the Host ports directly. Until then, legacy PC, Mobile, Web, and Browser Dev Host return `METHOD_FORBIDDEN` and provide no memory/Blob fallback. Once a supporting Host is available, call `files.pickFiles()` / `pickDirectory()` / `saveFile()` only from trusted user actions; `saveFile()` accepts only `suggestedName`, `remove()` only deletes sandbox objects, and non-empty directories require `remove({ recursive: true })`.
53
+ 13. New PC enables the retained `files` and `network.download()` contract with persistent sandbox storage, single-file/directory pickers, exact File saving, and public-network streaming downloads. Mobile, Web, Browser Dev Host, and legacy PC return `METHOD_FORBIDDEN` and provide no memory/Blob fallback. Call `files.pickFiles()` / `pickDirectory()` / `saveFile()` only from trusted user actions; `saveFile()` accepts only `suggestedName`, `remove()` only deletes sandbox objects, and non-empty directories require `remove({ recursive: true })`.
54
54
  14. Use `network.download()` only with an SDK-created File/Directory target. It is GET-only, does not follow redirects, and exposes local `AbortSignal` / progress callbacks without sending functions over the bridge. Abort is a cancellation intent; a Host commit that already won still resolves successfully.
55
55
 
56
56
  ## Step 5: Use CLI workflows
@@ -300,7 +300,7 @@ Reference 由 `@heybox/hb-sdk` 的公开导出与源码注释自动生成,不
300
300
  | Miniapp Publish API | 0 | 5 | 2 | 0 | 0 |
301
301
  | Vite API | 0 | 1 | 5 | 1 | 1 |
302
302
 
303
- <!-- Generated by apps/docs/hb-sdk/scripts/generate-api-docs.ts; schemaVersion=3; fingerprint=95cbf9ad1d791cfa4133a35e9084252798450930135372e1467931e34226b8ea -->
303
+ <!-- Generated by apps/docs/hb-sdk/scripts/generate-api-docs.ts; schemaVersion=3; fingerprint=bf58059fc425a0c142ed1d3706d14a0a773f6fe623f99df08dc14e6f0e93461b -->
304
304
 
305
305
  ## SDK API
306
306
 
@@ -24,7 +24,7 @@
24
24
  ## Package metadata
25
25
 
26
26
  - Package: `@heybox/hb-sdk`
27
- - Version at generation time: `0.8.0-alpha.10`
27
+ - Version at generation time: `0.8.0-alpha.13`
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,
@@ -247,7 +248,7 @@ import { shouldSkipMiniappPlatformCspFromEnv } from './runtime-permission-env';
247
248
 
248
249
  export interface MiniappManifestPlugin {
249
250
  name: string;
250
- config: (config: MiniappManifestUserConfig) => MiniappManifestUserConfig | void;
251
+ config: (config: MiniappManifestUserConfig, env?: { command: 'build' | 'serve' }) => MiniappManifestUserConfig | void;
251
252
  configResolved: (resolved: MiniappManifestResolvedConfig) => void;
252
253
  /** Rollup 在构建失败后仍会跑 closeBundle;用 buildEnd 记录真实错误,避免二次校验掩盖原因。 */
253
254
  buildEnd: (error?: Error) => void;
@@ -289,12 +290,34 @@ export interface MiniappManifestResolvedConfig {
289
290
  export { MINIAPP_PLATFORM_VALUES };
290
291
  export type { MiniappPlatform };
291
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
+
292
314
  export interface MiniappManifestOptions {
293
315
  platforms: readonly MiniappPlatform[];
294
316
  }
295
317
 
296
318
  const sdkVersionPlaceholder = ['__HB_SDK', 'VERSION__'].join('_');
297
319
  const sdkVersionBuildConstant = ['__HB_SDK_BUILD', 'VERSION__'].join('_');
320
+ const miniDevLoggingConstant = ['__HB_SDK_DEV', 'LOGGING__'].join('_');
298
321
 
299
322
  export function miniappManifest(options: MiniappManifestOptions): MiniappManifestPlugin {
300
323
  const platforms = validateMiniappPlatforms(options?.platforms, 'miniappManifest().platforms');
@@ -308,12 +331,17 @@ export function miniappManifest(options: MiniappManifestOptions): MiniappManifes
308
331
 
309
332
  return {
310
333
  name: 'heybox-miniapp-manifest',
311
- config(config) {
334
+ config(config, env) {
312
335
  assertMiniappViteBase(config.base);
336
+ // command 在本钩子时序早于 configResolved,必须取自 env 命令而非闭包;
337
+ // 旧调用方(测试等)未传 env 时按 build 处理。
338
+ const isServe = env?.command === 'serve';
313
339
  return {
314
340
  ...(config.base === undefined ? { base: './' } : {}),
315
341
  define: {
316
342
  [sdkVersionBuildConstant]: JSON.stringify(resolveSdkVersion()),
343
+ // 仅 vite serve(hb-sdk dev)注入;vite build / hb-sdk build 永不注入,捕获模块被死代码消除。
344
+ ...(isServe ? { [miniDevLoggingConstant]: 'true' } : {}),
317
345
  },
318
346
  };
319
347
  },
@@ -335,12 +363,12 @@ export function miniappManifest(options: MiniappManifestOptions): MiniappManifes
335
363
  }
336
364
  },
337
365
  transformIndexHtml(html) {
338
- return enforceMiniappHtmlPolicy(html, {
366
+ const enforced = enforceMiniappHtmlPolicy(html, {
339
367
  ...(command === 'serve' ? { hmrWebSocketUrl } : {}),
340
368
  skipPlatformCsp,
341
369
  });
342
- },
343
- async closeBundle() {
370
+ return command === 'serve' ? injectMiniDevConsoleBootstrap(enforced) : enforced;
371
+ }, async closeBundle() {
344
372
  // Rollup 在 buildStart/transform 失败后仍会调用 closeBundle。
345
373
  // 若此时再抛「缺 index.html」等二次错误,会掩盖真实失败原因。
346
374
  if (priorBuildError) {
@@ -560,15 +588,14 @@ try {
560
588
 
561
589
  | Host | `files.sandbox` | 外部 picker | `network.download()` |
562
590
  | ---------------- | --------------- | ----------- | -------------------- |
563
- | 旧版 PC | 不支持 | 不支持 | 不支持 |
591
+ | PC | 支持 | 支持 | 支持 |
564
592
  | Mobile | 不支持 | 不支持 | 不支持 |
565
593
  | Web | 不支持 | 不支持 | 不支持 |
566
594
  | Browser Dev Host | 不支持 | 不支持 | 不支持 |
567
595
 
568
596
  当前 Runtime 认识但 Host 未实现时返回 `METHOD_FORBIDDEN`;旧 Runtime 收到新 method 时返回
569
- `METHOD_NOT_FOUND`。此前曾实现面向旧版小黑盒 PC Host 适配;由于新版 PC 即将启用,该适配
570
- 不再发布。文件/下载 API、协议和 Runtime 体系保持不变,后续直接按照新版 PC Host 架构接入。
571
- 当前任何 Host 都不提供 Blob 或内存假下载。
597
+ `METHOD_NOT_FOUND`。新 PC V1 注入真实文件与流式下载 primitive;其他当前 Host 未实现时仍不
598
+ 提供 throwing stub、Blob 或内存假下载。
572
599
 
573
600
  ### 路径与创建
574
601
 
@@ -594,9 +621,10 @@ async function saveFromUserAction(text: string) {
594
621
  }
595
622
  ```
596
623
 
597
- `saveFile()` 打开系统保存对话框并返回精确 File 授权,不会同时创建或保留 Directory
598
- 授权。V1 不接受 `accept`;扩展名过滤只属于 `pickFiles({ accept: ['.json'] })`。外部授权仅在当前
599
- Runtime session 有效。
624
+ `saveFile()` 请求 Host 返回精确 File 授权,不会同时创建或保留 Directory 授权。新 PC 当前先让
625
+ 用户选择保存目录,再以 `suggestedName` 独占创建空文件;同名文件抛出 `FILE_ALREADY_EXISTS`,
626
+ 不会静默覆盖。V1 不接受 `accept`;扩展名过滤只属于 `pickFiles({ accept: ['.json'] })`。外部授权
627
+ 仅在当前 Runtime session 有效。
600
628
 
601
629
  `pickFiles()` / `pickDirectory()` 默认返回 `mode: 'read'` 的授权;只有显式传入
602
630
  `multiple: true` 时,`pickFiles()` 才允许 Host 返回多个文件。需要修改文件、在所选目录中创建
@@ -105,7 +105,7 @@ Agent rules:
105
105
  hb-sdk dev
106
106
  ```
107
107
 
108
- CLI 会启动页面服务并自动打开 Vue 3 本地调试台。左侧集中放置调用日志、Storage 和问题三个诊断页签,右侧保持稳定的小程序内容与设备预览。
108
+ CLI 会启动页面服务并自动打开 Vue 3 本地调试台。左侧集中放置日志、Storage 和问题三个诊断页签,右侧保持稳定的小程序内容与设备预览。
109
109
 
110
110
  默认终端只显示启动结果、调试页地址、小程序地址和手机调试入口。排查启动问题时使用 `hb-sdk dev --verbose` 查看完整启动阶段;手机扫码调试凭证连续重试失败时,默认只在失败和恢复两次状态变化时提示。
111
111
 
@@ -125,7 +125,7 @@ Browser Mock 会自动在实时与兼容链路间切换。手机调试使用 `op
125
125
  - SDK 初始化与用户身份授权流程
126
126
  - 生命周期、Storage 和排行榜等能力
127
127
 
128
- 调试台提供紧凑的调用日志、当前小程序隔离作用域内的 Storage 只读快照和问题聚合。日志与网络记录只保留脱敏的诊断字段,不展示 payload、结果、查询参数、凭据或原始错误信息。工坊小程序默认不能进行网络请求,网络权限暂未开放申请,不要把本地结果当成线上能力。
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
 
@@ -105,7 +105,7 @@ try {
105
105
  }
106
106
  ```
107
107
 
108
- ### Sandbox download contract (Host pending)
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 after a supporting Host is available.
189
- - Do not treat any current Host, including legacy PC or Browser Dev Host, as evidence for files/download support. They return `METHOD_FORBIDDEN` and provide no memory fallback; the new PC Host will integrate the retained contract separately.
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.