@heybox/hb-sdk 0.7.5-alpha.0 → 0.8.0-alpha

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 (54) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +14 -14
  3. package/dist/cli-chunks/{build-V1YBdpzY.cjs → build-DJWFSM1B.cjs} +6 -5
  4. package/dist/cli-chunks/{context-Ba1Je-wT.cjs → context-DV2UK1Nz.cjs} +2 -2
  5. package/dist/cli-chunks/{create-CKGjqo9E.cjs → create-2HfoB48V.cjs} +1 -1
  6. package/dist/cli-chunks/{dev-XopYKLYZ.cjs → dev-Dgt2zS9k.cjs} +8 -8
  7. package/dist/cli-chunks/{doctor-BHbrYQqT.cjs → doctor-C95gIao_.cjs} +1 -1
  8. package/dist/cli-chunks/{index-DKWfX6Ut.cjs → index-BjoSXl8C.cjs} +2 -2
  9. package/dist/cli-chunks/{index-C9mpajVG.cjs → index-D62ANeBv.cjs} +14 -14
  10. package/dist/cli-chunks/{index.esm-SXAQ3WVR.cjs → index.esm-CigcxJ2B.cjs} +6 -6
  11. package/dist/cli-chunks/{login-BVWicWqe.cjs → login-Cumknwdx.cjs} +2 -2
  12. package/dist/cli-chunks/{project-vite-CBb38HJ3.cjs → project-vite-CcE-HMmd.cjs} +1 -1
  13. package/dist/cli-chunks/{remote-BG1u0NKT.cjs → remote-DDdP3xcE.cjs} +10 -8
  14. package/dist/cli-chunks/{runtime-gate-CtV7rWyX.cjs → runtime-gate-DFjw66kF.cjs} +20 -1
  15. package/dist/cli-chunks/{runtime-permission-env-D-8_jPG3.cjs → runtime-permission-env-CjsCe5bp.cjs} +13 -13
  16. package/dist/cli-chunks/{session-CJS_SEp9.cjs → session-BDi_AZSv.cjs} +1 -1
  17. package/dist/cli.cjs +1 -1
  18. package/dist/devtools/browser-dev-host/main.js +173 -68
  19. package/dist/index.cjs.js +113 -63
  20. package/dist/index.esm.js +113 -63
  21. package/dist/miniapp-publish.cjs.js +13 -13
  22. package/dist/miniapp-publish.esm.js +13 -13
  23. package/dist/templates/vue3-vite-ts/README.md.ejs +2 -0
  24. package/dist/templates/vue3-vite-ts/vite.config.ts +1 -1
  25. package/dist/vite.cjs.js +31 -4
  26. package/dist/vite.esm.js +31 -5
  27. package/package.json +10 -7
  28. package/skill/references/api-protocol.md +14 -2
  29. package/skill/references/api-root.md +42 -21
  30. package/skill/references/examples.md +1 -1
  31. package/skill/references/safety-boundaries.md +1 -1
  32. package/skill/scripts/sync-references.mjs +3 -1
  33. package/skill/skill.json +4 -4
  34. package/types/core/errors.d.ts +5 -5
  35. package/types/core/sdk.d.ts +5 -5
  36. package/types/core/singleton.d.ts +56 -6
  37. package/types/miniapp-manifest/schema.d.ts +5 -0
  38. package/types/miniapp-publish/index.d.ts +8 -8
  39. package/types/modules/auth/index.d.ts +15 -1
  40. package/types/modules/cloud/index.d.ts +75 -5
  41. package/types/modules/device/index.d.ts +31 -3
  42. package/types/modules/navigation/index.d.ts +46 -4
  43. package/types/modules/network/index.d.ts +22 -11
  44. package/types/modules/share/copy-link.d.ts +3 -3
  45. package/types/modules/share/index.d.ts +61 -5
  46. package/types/modules/share/screenshot.d.ts +3 -3
  47. package/types/modules/share/show-share-menu.d.ts +3 -3
  48. package/types/modules/storage/index.d.ts +38 -10
  49. package/types/modules/ui/index.d.ts +46 -4
  50. package/types/modules/user/get-info.d.ts +1 -1
  51. package/types/modules/user/index.d.ts +46 -4
  52. package/types/modules/user/steam-game-list.d.ts +2 -2
  53. package/types/modules/viewport/index.d.ts +36 -8
  54. package/types/vite/index.d.ts +15 -7
@@ -251,6 +251,10 @@ class MiniProgramBridgeServer {
251
251
  this.dispatcher = options.dispatcher;
252
252
  this.targetOrigin = options.targetOrigin || '*';
253
253
  }
254
+ /** 返回当前已完成握手的协议版本。 */
255
+ get protocolVersion() {
256
+ return this.handshaken ? this.bridgeVersion : undefined;
257
+ }
254
258
  /** 开始监听 iframe 内 SDK 消息。 */
255
259
  start() {
256
260
  if (this.started) {
@@ -342,9 +346,10 @@ class MiniProgramBridgeServer {
342
346
  isTrustedMiniProgramMessage(event) {
343
347
  return (event.source === this.iframe.contentWindow &&
344
348
  isMiniProgramBridgeMessage(event.data) &&
349
+ (!this.handshaken || event.data.version === this.bridgeVersion) &&
345
350
  // 历史 v1 小程序可能在启动后跳转到不同的合法文档 origin;source 与 nonce
346
351
  // 仍然绑定到当前 iframe 实例,v2 继续执行严格 origin 校验。
347
- (event.data.version === 1 || this.targetOrigin === '*' || event.origin === this.targetOrigin) &&
352
+ ((this.handshaken ? this.bridgeVersion : event.data.version) === 1 || this.targetOrigin === '*' || event.origin === this.targetOrigin) &&
348
353
  event.data.nonce === this.nonce);
349
354
  }
350
355
  handleHandshake(payload, version, origin) {
@@ -747,20 +752,6 @@ function parseLoginResponse(response) {
747
752
  }
748
753
  return { ...envelope, result: mapped };
749
754
  }
750
- function parseLocalIdentityBeginResponse(response) {
751
- const envelope = parseAPIResponse(response, '小程序本地身份接口响应异常');
752
- const result = envelope.result;
753
- const mapped = {};
754
- if (result.local_identity && typeof result.local_identity === 'object') {
755
- mapped.localIdentity = {
756
- appUserId: result.local_identity.app_user_id,
757
- };
758
- }
759
- if (result.consent_challenge && typeof result.consent_challenge === 'object') {
760
- mapped.consentChallenge = mapChallenge(result.consent_challenge);
761
- }
762
- return { ...envelope, result: mapped };
763
- }
764
755
 
765
756
  const userMiniprogramAuthorizationCancelEndpoint = {
766
757
  auth: 'none',
@@ -786,29 +777,17 @@ const userMiniprogramAuthorizationRevokeEndpoint = {
786
777
  parse: (response) => parseAPIResponse(response, '小程序授权撤销接口响应异常'),
787
778
  };
788
779
 
789
- const userMiniprogramLocalIdentityBeginEndpoint = {
780
+ const userMiniprogramLocalIdentityEndpoint = {
790
781
  auth: 'none',
791
782
  bodyEncoding: 'form',
792
783
  channel: 'api',
793
784
  failurePresentation: 'none',
794
- id: 'heybox.user_miniprogram.runtime.auth.local_identity.begin.post',
785
+ id: 'heybox.user_miniprogram.runtime.local_identity.post',
795
786
  method: 'POST',
796
- path: '/user_miniprogram/runtime/auth/local_identity/begin',
787
+ path: '/user_miniprogram/runtime/local_identity',
797
788
  body: (input) => runtimeContextBody(input.runtimeContext),
798
- parse: (response) => parseLocalIdentityBeginResponse(response),
799
- };
800
-
801
- const userMiniprogramLocalIdentityConfirmEndpoint = {
802
- auth: 'none',
803
- bodyEncoding: 'form',
804
- channel: 'api',
805
- failurePresentation: 'none',
806
- id: 'heybox.user_miniprogram.runtime.auth.local_identity.confirm.post',
807
- method: 'POST',
808
- path: '/user_miniprogram/runtime/auth/local_identity/confirm',
809
- body: (input) => ({ ...runtimeContextBody(input.runtimeContext), challenge: input.challenge }),
810
789
  parse(response) {
811
- const envelope = parseAPIResponse(response, '小程序本地身份确认接口响应异常');
790
+ const envelope = parseAPIResponse(response, '小程序隔离身份接口响应异常');
812
791
  return { ...envelope, result: { appUserId: envelope.result.app_user_id } };
813
792
  },
814
793
  };
@@ -1323,35 +1302,11 @@ function createAuthorizationCoordinator(options) {
1323
1302
  }
1324
1303
  async function requestLocalIdentity(userId, miniProgramId) {
1325
1304
  const expectedGeneration = generation;
1326
- const beginEnvelope = await request(userMiniprogramLocalIdentityBeginEndpoint, {
1305
+ const envelope = await request(userMiniprogramLocalIdentityEndpoint, {
1327
1306
  runtimeContext: { miniProgramId },
1328
1307
  });
1329
1308
  await assertAuthorizationContext(userId, expectedGeneration);
1330
- const begin = readSuccessfulResult$3(beginEnvelope, '用户本地身份');
1331
- const hasIdentity = hasOwn(begin, 'localIdentity');
1332
- const hasChallenge = hasOwn(begin, 'consentChallenge');
1333
- if (hasIdentity === hasChallenge) {
1334
- throw createCapabilityBridgeError('INVALID_RESPONSE', '用户本地身份 begin 必须返回 exact oneof');
1335
- }
1336
- let localIdentity;
1337
- if (hasIdentity) {
1338
- localIdentity = validateLocalIdentity(begin.localIdentity);
1339
- }
1340
- else {
1341
- const identityChallenge = validateConsentChallenge(begin.consentChallenge);
1342
- if (identityChallenge.requestedScopes.length !== 1 ||
1343
- identityChallenge.requestedScopes[0] !== 'identity' ||
1344
- identityChallenge.displayedScopes.length !== 1 ||
1345
- identityChallenge.displayedScopes[0] !== 'identity') {
1346
- throw createCapabilityBridgeError('INVALID_RESPONSE', '用户本地身份 challenge 必须仅包含 identity scope');
1347
- }
1348
- const confirmEnvelope = await request(userMiniprogramLocalIdentityConfirmEndpoint, {
1349
- runtimeContext: { miniProgramId },
1350
- challenge: identityChallenge.challenge,
1351
- });
1352
- await assertAuthorizationContext(userId, expectedGeneration);
1353
- localIdentity = validateLocalIdentity(readSuccessfulResult$3(confirmEnvelope, '用户本地身份确认'));
1354
- }
1309
+ const localIdentity = validateLocalIdentity(readSuccessfulResult$3(envelope, '用户本地身份'));
1355
1310
  for (const scope of USER_INFO_AUTHORIZATION_SCOPES)
1356
1311
  grantedScopes.add(scope);
1357
1312
  emit('user_info_authorization_change', authorizationFromScopes(grantedScopes));
@@ -5747,6 +5702,9 @@ class MiniProgramRuntimeImpl {
5747
5702
  this.probeSequence = 0;
5748
5703
  this.hostVisible = true;
5749
5704
  this.awaitingControlledDocumentLoad = false;
5705
+ this.documentRevalidationPending = false;
5706
+ this.documentRevalidationGeneration = 0;
5707
+ this.iframeHiddenForRevalidation = false;
5750
5708
  this.runtimePermissions = undefined;
5751
5709
  this.options = options;
5752
5710
  this.iframe = options.iframe;
@@ -5776,13 +5734,22 @@ class MiniProgramRuntimeImpl {
5776
5734
  this.iframeLoadListener = () => {
5777
5735
  if (this.awaitingControlledDocumentLoad) {
5778
5736
  this.awaitingControlledDocumentLoad = false;
5737
+ if (this.stateValue === 'ready' && this.bridgeServer?.protocolVersion === 2 && this.sdkVersionDecision?.heartbeatEnabled) {
5738
+ this.beginDocumentRevalidation();
5739
+ return;
5740
+ }
5779
5741
  if (this.compatibilityWithoutSdk && !this.readyContext) {
5780
5742
  this.completeCompatibilityLaunch();
5781
5743
  }
5782
5744
  return;
5783
5745
  }
5784
5746
  if (this.stateValue === 'ready') {
5785
- this.scheduleUnexpectedDocumentLoadFailure();
5747
+ if (this.bridgeServer?.protocolVersion === 2 && this.sdkVersionDecision?.heartbeatEnabled) {
5748
+ this.beginDocumentRevalidation();
5749
+ }
5750
+ else {
5751
+ this.scheduleUnexpectedDocumentLoadFailure();
5752
+ }
5786
5753
  }
5787
5754
  };
5788
5755
  this.iframe.addEventListener('error', this.iframeErrorListener);
@@ -5830,14 +5797,34 @@ class MiniProgramRuntimeImpl {
5830
5797
  this.hostVisible = true;
5831
5798
  this.emitLifecycleEvent('show');
5832
5799
  if (!wasVisible && this.stateValue === 'ready' && this.sdkVersionDecision?.heartbeatEnabled) {
5833
- this.sendLocationProbe();
5800
+ if (this.documentRevalidationPending) {
5801
+ this.armDocumentRevalidationTimer(this.documentRevalidationGeneration);
5802
+ this.resendDocumentRevalidationProbe();
5803
+ }
5804
+ else {
5805
+ this.sendLocationProbe();
5806
+ }
5834
5807
  }
5835
5808
  }
5836
5809
  hide() {
5837
5810
  this.hostVisible = false;
5838
5811
  this.clearHeartbeat();
5812
+ this.clearDocumentRevalidationTimer();
5839
5813
  this.emitLifecycleEvent('hide');
5840
5814
  }
5815
+ prepareForHistoryTraversal() {
5816
+ if (this.stateValue !== 'ready' || this.bridgeServer?.protocolVersion !== 2 || !this.sdkVersionDecision?.heartbeatEnabled) {
5817
+ return () => undefined;
5818
+ }
5819
+ const generation = this.beginDocumentRevalidation({ deferProbe: true });
5820
+ this.preparedHistoryTraversalGeneration = generation;
5821
+ return () => {
5822
+ if (this.preparedHistoryTraversalGeneration !== generation) {
5823
+ return;
5824
+ }
5825
+ this.cancelPreparedHistoryTraversal();
5826
+ };
5827
+ }
5841
5828
  createReadyPromise() {
5842
5829
  return new Promise((resolve, reject) => {
5843
5830
  this.resolveReady = resolve;
@@ -5934,11 +5921,7 @@ class MiniProgramRuntimeImpl {
5934
5921
  this.handleBridgeReady();
5935
5922
  },
5936
5923
  onDuplicateHandshake: () => {
5937
- this.trace({
5938
- runtimeId: this.nonce,
5939
- timestamp: Date.now(),
5940
- type: 'duplicate_handshake',
5941
- });
5924
+ this.handleDuplicateBridgeHandshake();
5942
5925
  },
5943
5926
  onInternalEvent: (message) => {
5944
5927
  this.handleInternalBridgeEvent(message);
@@ -6179,7 +6162,7 @@ class MiniProgramRuntimeImpl {
6179
6162
  }
6180
6163
  }
6181
6164
  sendLocationProbe() {
6182
- if (this.isInactive() || !this.hostVisible || !this.sdkVersionDecision?.heartbeatEnabled) {
6165
+ if (this.isInactive() || !this.hostVisible || !this.sdkVersionDecision?.heartbeatEnabled || this.documentRevalidationPending) {
6183
6166
  return;
6184
6167
  }
6185
6168
  if (this.pendingProbeId) {
@@ -6214,6 +6197,123 @@ class MiniProgramRuntimeImpl {
6214
6197
  this.pendingProbeId = undefined;
6215
6198
  this.consecutiveHeartbeatMisses = 0;
6216
6199
  }
6200
+ beginDocumentRevalidation(options = {}) {
6201
+ this.clearUnexpectedDocumentLoadFailure();
6202
+ this.clearHeartbeat();
6203
+ this.clearDocumentRevalidationTimer();
6204
+ this.preparedHistoryTraversalGeneration = undefined;
6205
+ this.documentRevalidationPending = true;
6206
+ const generation = ++this.documentRevalidationGeneration;
6207
+ if (!this.iframeHiddenForRevalidation) {
6208
+ this.iframeVisibilityBeforeRevalidation = this.iframe.style.visibility;
6209
+ this.iframe.style.visibility = 'hidden';
6210
+ this.iframeHiddenForRevalidation = true;
6211
+ }
6212
+ this.armDocumentRevalidationTimer(generation);
6213
+ if (!options.deferProbe) {
6214
+ this.sendDocumentRevalidationProbe();
6215
+ }
6216
+ return generation;
6217
+ }
6218
+ sendDocumentRevalidationProbe() {
6219
+ if (this.isInactive() || !this.hostVisible || !this.documentRevalidationPending || !this.sdkVersionDecision?.heartbeatEnabled) {
6220
+ return;
6221
+ }
6222
+ const probeId = `${Date.now().toString(36)}_${++this.probeSequence}`;
6223
+ this.pendingProbeId = probeId;
6224
+ this.postLocationProbe(probeId);
6225
+ }
6226
+ resendDocumentRevalidationProbe() {
6227
+ if (this.isInactive() || !this.hostVisible || !this.documentRevalidationPending || !this.sdkVersionDecision?.heartbeatEnabled) {
6228
+ return;
6229
+ }
6230
+ if (!this.pendingProbeId) {
6231
+ this.sendDocumentRevalidationProbe();
6232
+ return;
6233
+ }
6234
+ this.postLocationProbe(this.pendingProbeId);
6235
+ }
6236
+ postLocationProbe(probeId) {
6237
+ this.bridgeServer?.postInternalRequest(RUNTIME_LOCATION_PROBE_METHOD, probeId, {
6238
+ probeId,
6239
+ timestamp: Date.now(),
6240
+ });
6241
+ this.trace({
6242
+ runtimeId: this.nonce,
6243
+ timestamp: Date.now(),
6244
+ type: 'location_probe',
6245
+ method: RUNTIME_LOCATION_PROBE_METHOD,
6246
+ });
6247
+ }
6248
+ armDocumentRevalidationTimer(generation) {
6249
+ if (!this.hostVisible) {
6250
+ return;
6251
+ }
6252
+ this.documentRevalidationTimer = setTimeout(() => {
6253
+ this.documentRevalidationTimer = undefined;
6254
+ if (this.isInactive() || !this.documentRevalidationPending || generation !== this.documentRevalidationGeneration) {
6255
+ return;
6256
+ }
6257
+ this.emitUrlSecurityViolation('UNEXPECTED_DOCUMENT_LOAD', this.launchUrl);
6258
+ this.failRuntime(createBridgeError('UNEXPECTED_DOCUMENT_LOAD', '小程序 iframe 文档再验证超时'));
6259
+ }, HEARTBEAT_INTERVAL);
6260
+ }
6261
+ clearDocumentRevalidationTimer() {
6262
+ if (this.documentRevalidationTimer) {
6263
+ clearTimeout(this.documentRevalidationTimer);
6264
+ this.documentRevalidationTimer = undefined;
6265
+ }
6266
+ }
6267
+ completeDocumentRevalidation() {
6268
+ this.clearDocumentRevalidationTimer();
6269
+ this.documentRevalidationPending = false;
6270
+ this.preparedHistoryTraversalGeneration = undefined;
6271
+ this.pendingProbeId = undefined;
6272
+ this.consecutiveHeartbeatMisses = 0;
6273
+ if (this.iframeHiddenForRevalidation && this.iframe.style.visibility === 'hidden') {
6274
+ this.iframe.style.visibility = this.iframeVisibilityBeforeRevalidation ?? '';
6275
+ }
6276
+ this.iframeVisibilityBeforeRevalidation = undefined;
6277
+ this.iframeHiddenForRevalidation = false;
6278
+ if (this.hostVisible && this.sdkVersionDecision?.heartbeatEnabled) {
6279
+ this.heartbeatTimer = setTimeout(() => {
6280
+ this.heartbeatTimer = undefined;
6281
+ this.sendLocationProbe();
6282
+ }, HEARTBEAT_INTERVAL);
6283
+ }
6284
+ }
6285
+ clearDocumentRevalidation() {
6286
+ this.clearDocumentRevalidationTimer();
6287
+ this.documentRevalidationPending = false;
6288
+ this.preparedHistoryTraversalGeneration = undefined;
6289
+ this.iframeVisibilityBeforeRevalidation = undefined;
6290
+ this.iframeHiddenForRevalidation = false;
6291
+ }
6292
+ cancelPreparedHistoryTraversal() {
6293
+ this.clearDocumentRevalidationTimer();
6294
+ this.documentRevalidationPending = false;
6295
+ this.preparedHistoryTraversalGeneration = undefined;
6296
+ this.pendingProbeId = undefined;
6297
+ this.consecutiveHeartbeatMisses = 0;
6298
+ if (this.iframeHiddenForRevalidation && this.iframe.style.visibility === 'hidden') {
6299
+ this.iframe.style.visibility = this.iframeVisibilityBeforeRevalidation ?? '';
6300
+ }
6301
+ this.iframeVisibilityBeforeRevalidation = undefined;
6302
+ this.iframeHiddenForRevalidation = false;
6303
+ if (this.hostVisible && this.sdkVersionDecision?.heartbeatEnabled) {
6304
+ this.sendLocationProbe();
6305
+ }
6306
+ }
6307
+ handleDuplicateBridgeHandshake() {
6308
+ this.trace({
6309
+ runtimeId: this.nonce,
6310
+ timestamp: Date.now(),
6311
+ type: 'duplicate_handshake',
6312
+ });
6313
+ if (this.documentRevalidationPending) {
6314
+ this.resendDocumentRevalidationProbe();
6315
+ }
6316
+ }
6217
6317
  handleInternalBridgeEvent(message) {
6218
6318
  if (message.method === SDK_CSP_VIOLATION_METHOD) {
6219
6319
  this.handleCspViolation(message.payload);
@@ -6245,12 +6345,16 @@ class MiniProgramRuntimeImpl {
6245
6345
  this.failRuntime(createBridgeError('URL_OUT_OF_SCOPE', '小程序页面地址超出允许范围'));
6246
6346
  return;
6247
6347
  }
6248
- if (report.trigger === 'hashchange') {
6249
- this.clearUnexpectedDocumentLoadFailure();
6250
- }
6251
6348
  if (report.probeId !== undefined) {
6252
6349
  this.pendingProbeId = undefined;
6253
6350
  this.consecutiveHeartbeatMisses = 0;
6351
+ if (this.documentRevalidationPending) {
6352
+ this.completeDocumentRevalidation();
6353
+ }
6354
+ }
6355
+ else if (this.documentRevalidationPending && !this.pendingProbeId) {
6356
+ this.preparedHistoryTraversalGeneration = undefined;
6357
+ this.sendDocumentRevalidationProbe();
6254
6358
  }
6255
6359
  }
6256
6360
  handleCspViolation(payload) {
@@ -6360,6 +6464,7 @@ class MiniProgramRuntimeImpl {
6360
6464
  this.clearHandshakeTimeout();
6361
6465
  this.clearHeartbeat();
6362
6466
  this.clearUnexpectedDocumentLoadFailure();
6467
+ this.clearDocumentRevalidation();
6363
6468
  this.destroyBridgeServer();
6364
6469
  this.capabilityGraph?.dispose();
6365
6470
  this.capabilityGraph = undefined;