@heybox/hb-sdk 0.8.0 → 0.8.1-alpha.2

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 (39) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +19 -0
  3. package/dist/cli-chunks/{build-PYCNacya.cjs → build-FQoALfGC.cjs} +5 -5
  4. package/dist/cli-chunks/{context-m2W2XbL0.cjs → context-CA_Q1lyH.cjs} +2 -2
  5. package/dist/cli-chunks/{create-BdAg3WGA.cjs → create-BjIl4hy4.cjs} +1 -1
  6. package/dist/cli-chunks/{dev-CyZuw7Yn.cjs → dev-CiPQYsW_.cjs} +9 -9
  7. package/dist/cli-chunks/{doctor-DU8rCfUF.cjs → doctor-CS6c3n-W.cjs} +1 -1
  8. package/dist/cli-chunks/{index-MMW2ibQm.cjs → index-BEn7WaqA.cjs} +15 -15
  9. package/dist/cli-chunks/{index-DATObqzK.cjs → index-CsP_x6y6.cjs} +2 -2
  10. package/dist/cli-chunks/{index.esm-BiAaAUFC.cjs → index.esm-DeEc_-uV.cjs} +7 -7
  11. package/dist/cli-chunks/{login-B3TThMss.cjs → login-BENCVgaQ.cjs} +2 -2
  12. package/dist/cli-chunks/{project-vite-BQj8YLI4.cjs → project-vite-BO8oOfcs.cjs} +1 -1
  13. package/dist/cli-chunks/{remote-DNvI7tHH.cjs → remote-IiVCXcSq.cjs} +7 -7
  14. package/dist/cli-chunks/{runtime-gate-BEFp1w_s.cjs → runtime-gate-BMSY22AL.cjs} +1 -1
  15. package/dist/cli-chunks/{runtime-permission-env-CtL8rsjB.cjs → runtime-permission-env-BPRwn4Yc.cjs} +1 -1
  16. package/dist/cli-chunks/{session-DjBkjaF8.cjs → session-C0eIKZ6V.cjs} +1 -1
  17. package/dist/cli-chunks/{skill-cR_wnaw2.cjs → skill-DpInwbiA.cjs} +2 -2
  18. package/dist/cli-chunks/{version-yEn1E2Bg.cjs → version-BONZQWPR.cjs} +1 -1
  19. package/dist/cli.cjs +1 -1
  20. package/dist/devtools/browser-dev-host/assets/browser-dev-host-DzEst9n7.js +99 -0
  21. package/dist/devtools/browser-dev-host/assets/{index-C5MZZDa5.js → index-B-NHlLsr.js} +2 -2
  22. package/dist/devtools/browser-dev-host/index.html +1 -1
  23. package/dist/index.cjs.js +83 -2
  24. package/dist/index.esm.js +83 -3
  25. package/dist/vite.cjs.js +1 -1
  26. package/dist/vite.esm.js +1 -1
  27. package/package.json +8 -10
  28. package/skill/SKILL.md +3 -0
  29. package/skill/references/api-protocol.md +7 -3
  30. package/skill/references/api-root.md +104 -1
  31. package/skill/references/recipes.md +1 -0
  32. package/skill/skill.json +5 -5
  33. package/types/core/client.d.ts +7 -1
  34. package/types/core/sdk.d.ts +3 -0
  35. package/types/core/singleton.d.ts +3 -0
  36. package/types/index.d.ts +3 -1
  37. package/types/modules/environment/index.d.ts +70 -0
  38. package/types/protocol.d.ts +1 -1
  39. package/dist/devtools/browser-dev-host/assets/browser-dev-host-TzYf9L6C.js +0 -99
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <meta name="theme-color" content="#f4f5f7" />
7
7
  <title>小程序工坊调试台</title>
8
- <script type="module" crossorigin src="/assets/index-C5MZZDa5.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-B-NHlLsr.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/workbench-state-BwV7bm4n.js">
10
10
  <link rel="stylesheet" crossorigin href="/assets/index-P-ra4m1y.css">
11
11
  </head>
package/dist/index.cjs.js CHANGED
@@ -799,7 +799,50 @@ function createMessageId() {
799
799
  /** 构建时替换为当前发布包的实际版本。 */
800
800
  const HB_SDK_VERSION = typeof undefined === 'string'
801
801
  ? undefined
802
- : '0.8.0';
802
+ : '0.8.1-alpha.2';
803
+
804
+ const RUNTIME_MODES = new Set(['production', 'preview', 'development', 'unknown']);
805
+ const OPERATING_SYSTEM_NAMES = new Set(['android', 'ios', 'ohos', 'windows', 'macos', 'linux', 'unknown']);
806
+ /** 创建环境信息模块。 */
807
+ function createEnvironmentModule(reader) {
808
+ return {
809
+ getInfo: () => reader.getEnvironmentInfo(),
810
+ getInfoSync: () => reader.getEnvironmentInfoSync(),
811
+ };
812
+ }
813
+ /** 将不可信 wire 值逐字段降级为固定、深度冻结的公开快照。 */
814
+ function normalizeMiniProgramEnvironmentInfo(value) {
815
+ const root = readRecord$1(value);
816
+ const runtime = readRecord$1(root?.runtime);
817
+ const host = readRecord$1(root?.host);
818
+ const miniProgram = readRecord$1(root?.miniProgram);
819
+ const operatingSystem = readRecord$1(root?.operatingSystem);
820
+ return Object.freeze({
821
+ runtime: Object.freeze({
822
+ mode: RUNTIME_MODES.has(runtime?.mode) ? runtime?.mode : 'unknown',
823
+ }),
824
+ host: Object.freeze({
825
+ appVersion: readOptionalString(host?.appVersion),
826
+ }),
827
+ miniProgram: Object.freeze({
828
+ id: readOptionalString(miniProgram?.id),
829
+ version: readOptionalString(miniProgram?.version),
830
+ }),
831
+ operatingSystem: Object.freeze({
832
+ name: OPERATING_SYSTEM_NAMES.has(operatingSystem?.name)
833
+ ? operatingSystem?.name
834
+ : 'unknown',
835
+ version: readOptionalString(operatingSystem?.version),
836
+ }),
837
+ sdk: Object.freeze({ version: HB_SDK_VERSION }),
838
+ });
839
+ }
840
+ function readOptionalString(value) {
841
+ return typeof value === 'string' && value.trim() ? value.trim() : null;
842
+ }
843
+ function readRecord$1(value) {
844
+ return typeof value === 'object' && value !== null && !Array.isArray(value) ? value : undefined;
845
+ }
803
846
 
804
847
  const DEFAULT_TIMEOUT = 10000;
805
848
  const HANDSHAKE_RETRY_INTERVAL = 250;
@@ -831,6 +874,7 @@ class MiniProgramBridgeClient {
831
874
  destroyed = false;
832
875
  runtimeUnavailable = false;
833
876
  runtimeUnavailableError;
877
+ environmentInfo;
834
878
  constructor(options = {}) {
835
879
  this.timeout = options.timeout || DEFAULT_TIMEOUT;
836
880
  this.selfWindow = options.selfWindow || getGlobalWindow();
@@ -857,6 +901,21 @@ class MiniProgramBridgeClient {
857
901
  onHandshakeStateChange(handler) {
858
902
  return this.handshakeState.subscribe(handler);
859
903
  }
904
+ /** 等待握手后读取当前实例的环境快照。 */
905
+ async getEnvironmentInfo() {
906
+ await this.waitForHandshake();
907
+ return this.getEnvironmentInfoSync();
908
+ }
909
+ /** 同步读取握手期间缓存的环境快照。 */
910
+ getEnvironmentInfoSync() {
911
+ const state = this.handshakeState.getState();
912
+ if (state.status === 'failed')
913
+ throw state.error;
914
+ if (state.status !== 'ready' || !this.environmentInfo) {
915
+ throw createSDKError('ENVIRONMENT_NOT_READY', '环境信息将在 SDK ready 后可用');
916
+ }
917
+ return this.environmentInfo;
918
+ }
860
919
  /** 注册小程序事件监听。 */
861
920
  on(eventName, handler) {
862
921
  return this.eventBus.on(eventName, handler);
@@ -1109,7 +1168,10 @@ class MiniProgramBridgeClient {
1109
1168
  if (eventName === 'unload') {
1110
1169
  this.markRuntimeUnavailable();
1111
1170
  }
1112
- else if (eventName === 'ready' && !this.runtimeUnavailable) {
1171
+ else if (eventName === 'ready' && !this.runtimeUnavailable && this.handshakeState.getState().status !== 'failed') {
1172
+ if (!this.environmentInfo) {
1173
+ this.environmentInfo = normalizeMiniProgramEnvironmentInfo(undefined);
1174
+ }
1113
1175
  this.resolveHandshakeOnce();
1114
1176
  }
1115
1177
  else if (eventName === 'show' && !this.runtimeUnavailable) {
@@ -1118,6 +1180,12 @@ class MiniProgramBridgeClient {
1118
1180
  this.eventBus.emit(eventName, message.payload);
1119
1181
  }
1120
1182
  handleResponse(message) {
1183
+ if (message.method === SDK_HANDSHAKE_METHOD && message.error === undefined) {
1184
+ if (!this.environmentInfo) {
1185
+ this.environmentInfo = normalizeMiniProgramEnvironmentInfo(readRecord(message.payload)?.environment);
1186
+ }
1187
+ return;
1188
+ }
1121
1189
  if (!message.id) {
1122
1190
  return;
1123
1191
  }
@@ -1237,6 +1305,9 @@ class MiniProgramBridgeClient {
1237
1305
  this.pendingRequests.clear();
1238
1306
  }
1239
1307
  }
1308
+ function readRecord(value) {
1309
+ return typeof value === 'object' && value !== null && !Array.isArray(value) ? value : undefined;
1310
+ }
1240
1311
  function waitForHandshakeOrAbort(handshake, signal, createAbortError, getTerminalError) {
1241
1312
  if (!signal)
1242
1313
  return handshake;
@@ -3691,6 +3762,8 @@ class MiniProgramSDK {
3691
3762
  navigation;
3692
3763
  /** 云端数据相关开放能力。 */
3693
3764
  cloud;
3765
+ /** 当前实例的环境信息。 */
3766
+ environment;
3694
3767
  constructor(options) {
3695
3768
  const launchHref = (options?.selfWindow ?? getGlobalWindow())?.location.href;
3696
3769
  this.client = new MiniProgramBridgeClient(options);
@@ -3705,6 +3778,7 @@ class MiniProgramSDK {
3705
3778
  this.device = createDeviceModule(this.client);
3706
3779
  this.navigation = createNavigationModule(this.client);
3707
3780
  this.cloud = createCloudModule(this.client);
3781
+ this.environment = createEnvironmentModule(this.client);
3708
3782
  }
3709
3783
  /** 获取当前握手状态。 */
3710
3784
  getHandshakeState() {
@@ -4003,6 +4077,11 @@ const cloud = {
4003
4077
  getInfo: (options) => getDefaultSDK().cloud.leaderboard.getInfo(options),
4004
4078
  },
4005
4079
  };
4080
+ /** 默认 SDK 实例的 environment 模块。 */
4081
+ const environment = {
4082
+ getInfo: () => getDefaultSDK().environment.getInfo(),
4083
+ getInfoSync: () => getDefaultSDK().environment.getInfoSync(),
4084
+ };
4006
4085
 
4007
4086
  const hbSDK = {
4008
4087
  getHandshakeState,
@@ -4018,6 +4097,7 @@ const hbSDK = {
4018
4097
  network,
4019
4098
  ui,
4020
4099
  device,
4100
+ environment,
4021
4101
  navigation,
4022
4102
  cloud,
4023
4103
  };
@@ -4029,6 +4109,7 @@ exports.auth = auth;
4029
4109
  exports.cloud = cloud;
4030
4110
  exports.default = hbSDK;
4031
4111
  exports.device = device;
4112
+ exports.environment = environment;
4032
4113
  exports.files = files;
4033
4114
  exports.getHandshakeState = getHandshakeState;
4034
4115
  exports.navigation = navigation;
package/dist/index.esm.js CHANGED
@@ -795,7 +795,50 @@ function createMessageId() {
795
795
  /** 构建时替换为当前发布包的实际版本。 */
796
796
  const HB_SDK_VERSION = typeof undefined === 'string'
797
797
  ? undefined
798
- : '0.8.0';
798
+ : '0.8.1-alpha.2';
799
+
800
+ const RUNTIME_MODES = new Set(['production', 'preview', 'development', 'unknown']);
801
+ const OPERATING_SYSTEM_NAMES = new Set(['android', 'ios', 'ohos', 'windows', 'macos', 'linux', 'unknown']);
802
+ /** 创建环境信息模块。 */
803
+ function createEnvironmentModule(reader) {
804
+ return {
805
+ getInfo: () => reader.getEnvironmentInfo(),
806
+ getInfoSync: () => reader.getEnvironmentInfoSync(),
807
+ };
808
+ }
809
+ /** 将不可信 wire 值逐字段降级为固定、深度冻结的公开快照。 */
810
+ function normalizeMiniProgramEnvironmentInfo(value) {
811
+ const root = readRecord$1(value);
812
+ const runtime = readRecord$1(root?.runtime);
813
+ const host = readRecord$1(root?.host);
814
+ const miniProgram = readRecord$1(root?.miniProgram);
815
+ const operatingSystem = readRecord$1(root?.operatingSystem);
816
+ return Object.freeze({
817
+ runtime: Object.freeze({
818
+ mode: RUNTIME_MODES.has(runtime?.mode) ? runtime?.mode : 'unknown',
819
+ }),
820
+ host: Object.freeze({
821
+ appVersion: readOptionalString(host?.appVersion),
822
+ }),
823
+ miniProgram: Object.freeze({
824
+ id: readOptionalString(miniProgram?.id),
825
+ version: readOptionalString(miniProgram?.version),
826
+ }),
827
+ operatingSystem: Object.freeze({
828
+ name: OPERATING_SYSTEM_NAMES.has(operatingSystem?.name)
829
+ ? operatingSystem?.name
830
+ : 'unknown',
831
+ version: readOptionalString(operatingSystem?.version),
832
+ }),
833
+ sdk: Object.freeze({ version: HB_SDK_VERSION }),
834
+ });
835
+ }
836
+ function readOptionalString(value) {
837
+ return typeof value === 'string' && value.trim() ? value.trim() : null;
838
+ }
839
+ function readRecord$1(value) {
840
+ return typeof value === 'object' && value !== null && !Array.isArray(value) ? value : undefined;
841
+ }
799
842
 
800
843
  const DEFAULT_TIMEOUT = 10000;
801
844
  const HANDSHAKE_RETRY_INTERVAL = 250;
@@ -827,6 +870,7 @@ class MiniProgramBridgeClient {
827
870
  destroyed = false;
828
871
  runtimeUnavailable = false;
829
872
  runtimeUnavailableError;
873
+ environmentInfo;
830
874
  constructor(options = {}) {
831
875
  this.timeout = options.timeout || DEFAULT_TIMEOUT;
832
876
  this.selfWindow = options.selfWindow || getGlobalWindow();
@@ -853,6 +897,21 @@ class MiniProgramBridgeClient {
853
897
  onHandshakeStateChange(handler) {
854
898
  return this.handshakeState.subscribe(handler);
855
899
  }
900
+ /** 等待握手后读取当前实例的环境快照。 */
901
+ async getEnvironmentInfo() {
902
+ await this.waitForHandshake();
903
+ return this.getEnvironmentInfoSync();
904
+ }
905
+ /** 同步读取握手期间缓存的环境快照。 */
906
+ getEnvironmentInfoSync() {
907
+ const state = this.handshakeState.getState();
908
+ if (state.status === 'failed')
909
+ throw state.error;
910
+ if (state.status !== 'ready' || !this.environmentInfo) {
911
+ throw createSDKError('ENVIRONMENT_NOT_READY', '环境信息将在 SDK ready 后可用');
912
+ }
913
+ return this.environmentInfo;
914
+ }
856
915
  /** 注册小程序事件监听。 */
857
916
  on(eventName, handler) {
858
917
  return this.eventBus.on(eventName, handler);
@@ -1105,7 +1164,10 @@ class MiniProgramBridgeClient {
1105
1164
  if (eventName === 'unload') {
1106
1165
  this.markRuntimeUnavailable();
1107
1166
  }
1108
- else if (eventName === 'ready' && !this.runtimeUnavailable) {
1167
+ else if (eventName === 'ready' && !this.runtimeUnavailable && this.handshakeState.getState().status !== 'failed') {
1168
+ if (!this.environmentInfo) {
1169
+ this.environmentInfo = normalizeMiniProgramEnvironmentInfo(undefined);
1170
+ }
1109
1171
  this.resolveHandshakeOnce();
1110
1172
  }
1111
1173
  else if (eventName === 'show' && !this.runtimeUnavailable) {
@@ -1114,6 +1176,12 @@ class MiniProgramBridgeClient {
1114
1176
  this.eventBus.emit(eventName, message.payload);
1115
1177
  }
1116
1178
  handleResponse(message) {
1179
+ if (message.method === SDK_HANDSHAKE_METHOD && message.error === undefined) {
1180
+ if (!this.environmentInfo) {
1181
+ this.environmentInfo = normalizeMiniProgramEnvironmentInfo(readRecord(message.payload)?.environment);
1182
+ }
1183
+ return;
1184
+ }
1117
1185
  if (!message.id) {
1118
1186
  return;
1119
1187
  }
@@ -1233,6 +1301,9 @@ class MiniProgramBridgeClient {
1233
1301
  this.pendingRequests.clear();
1234
1302
  }
1235
1303
  }
1304
+ function readRecord(value) {
1305
+ return typeof value === 'object' && value !== null && !Array.isArray(value) ? value : undefined;
1306
+ }
1236
1307
  function waitForHandshakeOrAbort(handshake, signal, createAbortError, getTerminalError) {
1237
1308
  if (!signal)
1238
1309
  return handshake;
@@ -3687,6 +3758,8 @@ class MiniProgramSDK {
3687
3758
  navigation;
3688
3759
  /** 云端数据相关开放能力。 */
3689
3760
  cloud;
3761
+ /** 当前实例的环境信息。 */
3762
+ environment;
3690
3763
  constructor(options) {
3691
3764
  const launchHref = (options?.selfWindow ?? getGlobalWindow())?.location.href;
3692
3765
  this.client = new MiniProgramBridgeClient(options);
@@ -3701,6 +3774,7 @@ class MiniProgramSDK {
3701
3774
  this.device = createDeviceModule(this.client);
3702
3775
  this.navigation = createNavigationModule(this.client);
3703
3776
  this.cloud = createCloudModule(this.client);
3777
+ this.environment = createEnvironmentModule(this.client);
3704
3778
  }
3705
3779
  /** 获取当前握手状态。 */
3706
3780
  getHandshakeState() {
@@ -3999,6 +4073,11 @@ const cloud = {
3999
4073
  getInfo: (options) => getDefaultSDK().cloud.leaderboard.getInfo(options),
4000
4074
  },
4001
4075
  };
4076
+ /** 默认 SDK 实例的 environment 模块。 */
4077
+ const environment = {
4078
+ getInfo: () => getDefaultSDK().environment.getInfo(),
4079
+ getInfoSync: () => getDefaultSDK().environment.getInfoSync(),
4080
+ };
4002
4081
 
4003
4082
  const hbSDK = {
4004
4083
  getHandshakeState,
@@ -4014,8 +4093,9 @@ const hbSDK = {
4014
4093
  network,
4015
4094
  ui,
4016
4095
  device,
4096
+ environment,
4017
4097
  navigation,
4018
4098
  cloud,
4019
4099
  };
4020
4100
 
4021
- export { HbMiniProgramNetworkError, HbMiniProgramSDKError, USER_INFO_AUTHORIZATION_SCOPES, auth, cloud, hbSDK as default, device, files, getHandshakeState, navigation, network, off, on, onHandshakeStateChange, share, storage, ui, user, viewport };
4101
+ export { HbMiniProgramNetworkError, HbMiniProgramSDKError, USER_INFO_AUTHORIZATION_SCOPES, auth, cloud, hbSDK as default, device, environment, files, getHandshakeState, navigation, network, off, on, onHandshakeStateChange, share, storage, ui, user, viewport };
package/dist/vite.cjs.js CHANGED
@@ -8,7 +8,7 @@ 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';
11
+ : '0.8.1-alpha.2';
12
12
 
13
13
  /**
14
14
  * iframe 与调试台页面的开发期 console 捕获转发。
package/dist/vite.esm.js CHANGED
@@ -5,7 +5,7 @@ import { AsyncLocalStorage } from 'node:async_hooks';
5
5
  /** 构建时替换为当前发布包的实际版本。 */
6
6
  const HB_SDK_VERSION = typeof undefined === 'string'
7
7
  ? undefined
8
- : '0.8.0';
8
+ : '0.8.1-alpha.2';
9
9
 
10
10
  /**
11
11
  * iframe 与调试台页面的开发期 console 捕获转发。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heybox/hb-sdk",
3
- "version": "0.8.0",
3
+ "version": "0.8.1-alpha.2",
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"
65
+ "@heybox/hb-sdk-protocol": "0.8.1-alpha.2"
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",
116
117
  "@heybox-domain/heybox-theme": "~0.1.0",
117
118
  "@heybox/hb-api": "~1.28.2",
118
- "@heybox/hb-sdk-runtime": "~0.8.0",
119
- "@heybox/runtime": "~0.2.0",
119
+ "@heybox/hb-sdk-runtime": "~0.8.1-alpha.2",
120
120
  "@heybox/runtime-policy": "~0.2.0",
121
- "@heybox-domain/heybox-vue3-ui": "~0.1.0",
122
- "@heybox/runtime-transport-fetch": "~0.2.0"
121
+ "@heybox/runtime-transport-fetch": "~0.2.0",
122
+ "@heybox/runtime": "~0.2.0"
123
123
  },
124
124
  "publishConfig": {
125
125
  "registry": "https://registry.npmjs.org/",
@@ -183,14 +183,12 @@
183
183
  "changelog:draft": "node scripts/changelog-draft.cjs",
184
184
  "check:changelog": "node scripts/check-changelog.cjs",
185
185
  "release:verify-tarball": "node scripts/skill/verify-tarball-install.mjs",
186
- "test:release": "node --test scripts/public-changelog.test.mjs scripts/public-changelog-workflow.test.cjs scripts/release-family.test.cjs ../../ops/jobs/publish-changed-packages/publish.test.cjs ../../ops/jobs/release-hb-sdk/docs-release-contract.test.cjs ../../ops/jobs/release-hb-sdk/stable-promote-coordinator.test.cjs",
186
+ "test:release": "node --test scripts/public-changelog.test.mjs scripts/public-changelog-workflow.test.cjs scripts/release-family.test.cjs ../../ops/jobs/publish-changed-packages/publish.test.cjs",
187
187
  "test:compatibility-evidence": "node --test scripts/validate-compatibility-evidence.test.mjs",
188
188
  "release:prepare": "node scripts/release-prepare.cjs",
189
189
  "release:tag": "node scripts/release-tag.cjs",
190
190
  "release:family:dry-run": "node ../../ops/jobs/publish-changed-packages/publish.cjs --dry-run",
191
191
  "release:family:promote": "node ../../ops/jobs/publish-changed-packages/publish.cjs --family-action promote",
192
- "release:family:rollback": "node ../../ops/jobs/publish-changed-packages/publish.cjs --family-action rollback",
193
- "release:stable:promote": "node ../../ops/jobs/release-hb-sdk/stable-promote-coordinator.cjs --action promote",
194
- "release:stable:rollback": "node ../../ops/jobs/release-hb-sdk/stable-promote-coordinator.cjs --action rollback"
192
+ "release:family:rollback": "node ../../ops/jobs/publish-changed-packages/publish.cjs --family-action rollback"
195
193
  }
196
194
  }
package/skill/SKILL.md CHANGED
@@ -52,6 +52,8 @@ Apply these instructions when writing, reviewing, or debugging code that consume
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
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
+ 15. Use `environment.getInfo()` for the immutable runtime, Host App, canonical Mini-program, operating-system, and SDK version snapshot. It waits for the handshake automatically. Use `environment.getInfoSync()` only after `getHandshakeState().status === 'ready'` or inside a ready-state subscription; before that it throws `ENVIRONMENT_NOT_READY`.
56
+ 16. Treat missing environment strings as `null` and unknown enum values as `unknown`. Only `sdk.version` is SemVer; do not compare the other opaque version strings or use any environment field for authentication, authorization, or risk control.
55
57
 
56
58
  ## Step 5: Use CLI workflows
57
59
 
@@ -88,6 +90,7 @@ For workshop mini-program business code:
88
90
  7. Do not use `network.request()` to reach platform-reserved runtime auth or OpenAPI internal paths.
89
91
  8. Do not expose credentials or describe internal Host authorization state machines and routes in app-facing guidance.
90
92
  9. Do not invent string paths, File System Access API handles, Blob downloads, uploads, Range/resume, external deletion, move, append, or persistent external grants. Public file operations use only SDK-created handles; deletion is limited to SDK sandbox handles.
93
+ 10. Do not treat `environment.*` as a device-fingerprint or trusted backend signal. It intentionally excludes account data, device identifiers, model, UA, CPU, and memory; use `viewport.getWindowInfo()` for screen geometry.
91
94
 
92
95
  For CLI and local development:
93
96
 
@@ -176,7 +176,10 @@ export type {
176
176
  MiniProgramNetworkMethod,
177
177
  MiniProgramNetworkParams,
178
178
  MiniProgramNetworkRequestMethod,
179
+ MiniProgramOperatingSystemName,
179
180
  MiniProgramRuntimePermissionEntry,
181
+ MiniProgramRuntimeEnvironmentInfo,
182
+ MiniProgramRuntimeMode,
180
183
  MiniProgramRuntimePermissionsSnapshot,
181
184
  MiniProgramRuntimePermissionStatus,
182
185
  MiniProgramSafeArea,
@@ -215,6 +218,7 @@ export type {
215
218
  SaveFilePayload,
216
219
  SaveFileResult,
217
220
  SDKHandshakePayload,
221
+ SDKHandshakeResult,
218
222
  SetClipboardPayload,
219
223
  SetClipboardResult,
220
224
  SetNavigationBarStylePayload,
@@ -295,12 +299,12 @@ Reference 由 `@heybox/hb-sdk` 的公开导出与源码注释自动生成,不
295
299
 
296
300
  | 导出面 | Classes | Functions | Interfaces | Types | Constants |
297
301
  | --- | ---: | ---: | ---: | ---: | ---: |
298
- | Root API | 2 | 4 | 65 | 60 | 1 |
299
- | Protocol API | 0 | 13 | 56 | 90 | 47 |
302
+ | Root API | 2 | 4 | 67 | 62 | 2 |
303
+ | Protocol API | 0 | 13 | 58 | 90 | 47 |
300
304
  | Miniapp Publish API | 0 | 5 | 2 | 0 | 0 |
301
305
  | Vite API | 0 | 1 | 5 | 1 | 1 |
302
306
 
303
- <!-- Generated by apps/docs/hb-sdk/scripts/generate-api-docs.ts; schemaVersion=3; fingerprint=660a21ad77c32f30dbc7ebb02b053ebce2a7c6e7301cc805a5cdd1a75572fbb2 -->
307
+ <!-- Generated by apps/docs/hb-sdk/scripts/generate-api-docs.ts; schemaVersion=4; fingerprint=1b6c6a8f921122d588700ac1323b6c46a2ee6d331c585078527612b218546757 -->
304
308
 
305
309
  ## SDK API
306
310
 
@@ -9,6 +9,7 @@
9
9
  - packages/hb-sdk/src/vite/index.ts
10
10
  - packages/hb-sdk/README.md
11
11
  - apps/docs/hb-sdk/guide/quick-start.md
12
+ - apps/docs/hb-sdk/guide/environment.md
12
13
  - apps/docs/hb-sdk/guide/error-handling.md
13
14
  - apps/docs/hb-sdk/guide/lifecycle.md
14
15
  - apps/docs/hb-sdk/guide/cli.md
@@ -19,12 +20,13 @@
19
20
  - [Public root entrypoint](#public-root-entrypoint)
20
21
  - [Vite plugin export](#vite-plugin-export)
21
22
  - [App-facing concepts](#app-facing-concepts)
23
+ - [Environment info](#environment-info)
22
24
  - [Public modules](#public-modules)
23
25
  - [Cloud leaderboard](#cloud-leaderboard)
24
26
  ## Package metadata
25
27
 
26
28
  - Package: `@heybox/hb-sdk`
27
- - Version at generation time: `0.8.0`
29
+ - Version at generation time: `0.8.1-alpha.2`
28
30
  - Public root export: `@heybox/hb-sdk`
29
31
  - Protocol export: `@heybox/hb-sdk/protocol`
30
32
  - Vite plugin export: `@heybox/hb-sdk/vite`
@@ -47,6 +49,7 @@ export {
47
49
  network,
48
50
  ui,
49
51
  device,
52
+ environment,
50
53
  navigation,
51
54
  cloud,
52
55
  } from './core/singleton';
@@ -165,6 +168,12 @@ export type {
165
168
  VibratePayload,
166
169
  VibrateResult,
167
170
  } from './modules/device';
171
+ export type {
172
+ MiniProgramEnvironmentInfo,
173
+ MiniProgramEnvironmentModule,
174
+ MiniProgramOperatingSystemName,
175
+ MiniProgramRuntimeMode,
176
+ } from './modules/environment';
168
177
  export type {
169
178
  ClosePayload,
170
179
  CloseResult,
@@ -189,6 +198,7 @@ import {
189
198
  auth,
190
199
  cloud,
191
200
  device,
201
+ environment,
192
202
  getHandshakeState,
193
203
  navigation,
194
204
  network,
@@ -217,6 +227,7 @@ const hbSDK = {
217
227
  network,
218
228
  ui,
219
229
  device,
230
+ environment,
220
231
  navigation,
221
232
  cloud,
222
233
  };
@@ -648,6 +659,96 @@ async function saveFromUserAction(text: string) {
648
659
 
649
660
  大多数小程序页面都应该使用默认实例。0.6 起不再对业务代码提供独立实例工厂。
650
661
 
662
+ ## Environment info
663
+
664
+
665
+ # 环境信息
666
+
667
+ `environment` 模块提供当前小程序实例的静态环境快照,包括运行模式、小黑盒 App 版本、canonical 小程序身份、操作系统和 SDK 版本。该能力无需在 `heybox.permissions` 中声明,也不会触发用户授权。
668
+
669
+ ## 推荐用法
670
+
671
+ 优先使用异步方法。SDK 尚未完成握手时,`getInfo()` 会自动等待:
672
+
673
+ ```ts
674
+ import { environment } from '@heybox/hb-sdk'
675
+
676
+ const info = await environment.getInfo()
677
+
678
+ console.log(info.runtime.mode)
679
+ console.log(info.host.appVersion)
680
+ console.log(info.miniProgram.id, info.miniProgram.version)
681
+ console.log(info.operatingSystem.name, info.operatingSystem.version)
682
+ console.log(info.sdk.version)
683
+ ```
684
+
685
+ 返回对象采用固定结构并深度冻结:
686
+
687
+ ```ts
688
+ interface MiniProgramEnvironmentInfo {
689
+ readonly runtime: {
690
+ readonly mode: 'production' | 'preview' | 'development' | 'unknown'
691
+ }
692
+ readonly host: {
693
+ readonly appVersion: string | null
694
+ }
695
+ readonly miniProgram: {
696
+ readonly id: string | null
697
+ readonly version: string | null
698
+ }
699
+ readonly operatingSystem: {
700
+ readonly name: 'android' | 'ios' | 'ohos' | 'windows' | 'macos' | 'linux' | 'unknown'
701
+ readonly version: string | null
702
+ }
703
+ readonly sdk: {
704
+ readonly version: string
705
+ }
706
+ }
707
+ ```
708
+
709
+ ## 同步读取
710
+
711
+ 只有已经确认 SDK 为 `ready` 时才能调用 `getInfoSync()`。SDK 会在派发 `ready` 状态前缓存环境快照,因此可以在握手状态订阅中同步读取:
712
+
713
+ ```ts
714
+ import { environment, onHandshakeStateChange } from '@heybox/hb-sdk'
715
+
716
+ const unsubscribe = onHandshakeStateChange(state => {
717
+ if (state.status !== 'ready') return
718
+
719
+ const info = environment.getInfoSync()
720
+ console.log(info.operatingSystem.name)
721
+ })
722
+ ```
723
+
724
+ 握手完成前调用会抛出 `HbMiniProgramSDKError`,错误码为 `ENVIRONMENT_NOT_READY`。通常不需要自行等待握手;不要求同步执行的代码直接使用 `await environment.getInfo()`。
725
+
726
+ ## 字段语义
727
+
728
+ | 字段 | 语义 |
729
+ | ------------------------- | -------------------------------------------------------------------------------------------------------------- |
730
+ | `runtime.mode` | 当前实例的粗粒度运行模式。正式发布为 `production`,版本预览为 `preview`,本地或 Dev Session 为 `development`。 |
731
+ | `host.appVersion` | 当前小黑盒 App 版本。它是 Host 提供的不透明字符串。 |
732
+ | `miniProgram.id` | 平台确认的 canonical `mini_program_id`,不返回数字 ID、用户 ID 或其他旧 ID。 |
733
+ | `miniProgram.version` | 当前加载的小程序版本,是不透明字符串。 |
734
+ | `operatingSystem.name` | Host 明确提供的标准系统枚举,不从小程序 iframe 的 UA 推断。 |
735
+ | `operatingSystem.version` | Host 明确提供的系统版本;当前 Host 未提供时为 `null`。 |
736
+ | `sdk.version` | 当前页面实际运行的 `@heybox/hb-sdk` 版本,遵循 npm SemVer。 |
737
+
738
+ 除 `sdk.version` 外,其他版本字段均不承诺 SemVer 或大小比较语义。需要判断某项能力是否可用时,应依据能力调用结果进行降级,不要仅比较 App 或系统版本。
739
+
740
+ ## 缺失与兼容
741
+
742
+ 旧 Host、匿名本地调试或未提供某个字段的 Host 仍会返回完整结构:缺失字符串为 `null`,未知枚举为 `'unknown'`。非法 Host 字段只会被逐项降级,不会阻断 SDK 握手。
743
+
744
+ Browser Mock 在 Runtime 启动时使用当前设备预设作为操作系统名称,不读取开发者电脑的 UA。切换设备预设会保留当前 Runtime 和页面状态;需要重新生成环境快照时,使用调试台的重启操作。
745
+
746
+ ## 信任边界
747
+
748
+ 环境信息仅用于界面适配、兼容降级、埋点和诊断,不能用于鉴权、权限控制或风控。小程序提交给服务端的任何环境字段都可能被修改;服务端安全判断必须使用自身认证上下文或平台受信数据。
749
+
750
+ 该 API 不提供设备型号、品牌、UA、CPU、内存、设备唯一标识、账号信息或凭据。屏幕和安全区域继续通过 [`viewport.getWindowInfo()`](https://docs.xiaoheihe.cn/hb_sdk/reference/sdk/viewport/getWindowInfo/) 获取。
751
+
651
752
 
652
753
  # 错误处理
653
754
 
@@ -686,6 +787,7 @@ try {
686
787
  - `AUTHORIZATION_CANCELLED` 表示用户取消、拒绝或关闭授权页面,应正常结束当前操作。
687
788
  - `SERVER_API_REQUIRED` 表示当前用户数据必须经开发者服务端 OpenAPI 获取,不应在页面重试对应 Host API。
688
789
  - `METHOD_FORBIDDEN` 表示当前 Host 未实现或关闭对应能力。V1 files/download 在 Mobile、Web 和 Browser Dev Host 都会得到该错误。
790
+ - `ENVIRONMENT_NOT_READY` 表示在 SDK 完成握手前调用了 `environment.getInfoSync()`;一般改用会自动等待的 `environment.getInfo()`。
689
791
  - `FILE_PICKER_CANCELLED` 表示用户取消了外部文件或目录选择,应正常结束当前操作。
690
792
  - `DOWNLOAD_CANCELLED` 表示取消意图先于 Host 提交生效;Host 已完成提交时仍返回成功。`DOWNLOAD_TIMEOUT` 表示网络空闲超时,失败不会改动原目标。
691
793
  - `DOWNLOAD_HTTP_STATUS` 的 `data` 只包含脱敏后的 `status`、可选 `statusText` 和安全响应头。
@@ -750,6 +852,7 @@ SDK 还提供 `getHandshakeState()` / `onHandshakeStateChange()` 管理持久握
750
852
  | 模块 | 用途 |
751
853
  | ------------ | ----------------------------------------------- |
752
854
  | `auth` | 获取交给开发者服务端交换的短期授权码 |
855
+ | `environment` | 读取当前实例的冻结环境快照 |
753
856
  | `user` | 读取 Host 当前用户资料、隔离身份或撤销授权 |
754
857
  | `share` | 打开分享、复制链接或截图分享流程 |
755
858
  | `ui` | 展示 Toast 和 Loading |
@@ -413,6 +413,7 @@ try {
413
413
  - `AUTHORIZATION_CANCELLED` 表示用户取消、拒绝或关闭授权页面,应正常结束当前操作。
414
414
  - `SERVER_API_REQUIRED` 表示当前用户数据必须经开发者服务端 OpenAPI 获取,不应在页面重试对应 Host API。
415
415
  - `METHOD_FORBIDDEN` 表示当前 Host 未实现或关闭对应能力。V1 files/download 在 Mobile、Web 和 Browser Dev Host 都会得到该错误。
416
+ - `ENVIRONMENT_NOT_READY` 表示在 SDK 完成握手前调用了 `environment.getInfoSync()`;一般改用会自动等待的 `environment.getInfo()`。
416
417
  - `FILE_PICKER_CANCELLED` 表示用户取消了外部文件或目录选择,应正常结束当前操作。
417
418
  - `DOWNLOAD_CANCELLED` 表示取消意图先于 Host 提交生效;Host 已完成提交时仍返回成功。`DOWNLOAD_TIMEOUT` 表示网络空闲超时,失败不会改动原目标。
418
419
  - `DOWNLOAD_HTTP_STATUS` 的 `data` 只包含脱敏后的 `status`、可选 `statusText` 和安全响应头。
package/skill/skill.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "hb-sdk",
3
- "skillVersion": "0.8.0+skill.7bb8515ab71e",
3
+ "skillVersion": "0.8.1-alpha.2+skill.99494863257b",
4
4
  "sdk": {
5
5
  "package": "@heybox/hb-sdk",
6
- "version": "0.8.0",
7
- "compatibility": "0.8.0"
6
+ "version": "0.8.1-alpha.2",
7
+ "compatibility": "0.8.1-alpha.2"
8
8
  },
9
9
  "distribution": {
10
10
  "type": "npm",
11
11
  "package": "@heybox/hb-sdk",
12
- "version": "0.8.0",
12
+ "version": "0.8.1-alpha.2",
13
13
  "path": "skill"
14
14
  },
15
- "integrity": "sha256-7bb8515ab71e004724601d7e09d0e5058888b53a7486b7ed15535ba9a8cdb93c"
15
+ "integrity": "sha256-99494863257b8e51843a42bb94c2e40555a1cc28f11ca0f7da37473e19424bdf"
16
16
  }