@heybox/hb-sdk 0.6.5 → 0.6.6-alpha.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.
@@ -4,7 +4,7 @@ var fs$1 = require('node:fs');
4
4
  var fs = require('node:fs/promises');
5
5
  var os = require('node:os');
6
6
  var path = require('node:path');
7
- var index = require('./index-CKat0ExC.cjs');
7
+ var index = require('./index-Ck6a9STO.cjs');
8
8
  require('node:module');
9
9
  require('path');
10
10
  require('os');
@@ -234,19 +234,19 @@ function requireArgument () {
234
234
 
235
235
  var command = {};
236
236
 
237
- const require$5 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-CKat0ExC.cjs', document.baseURI).href)));
237
+ const require$5 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-Ck6a9STO.cjs', document.baseURI).href)));
238
238
  function __require$4() { return require$5("node:events"); }
239
239
 
240
- const require$4 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-CKat0ExC.cjs', document.baseURI).href)));
240
+ const require$4 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-Ck6a9STO.cjs', document.baseURI).href)));
241
241
  function __require$3() { return require$4("node:child_process"); }
242
242
 
243
- const require$3 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-CKat0ExC.cjs', document.baseURI).href)));
243
+ const require$3 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-Ck6a9STO.cjs', document.baseURI).href)));
244
244
  function __require$2() { return require$3("node:path"); }
245
245
 
246
- const require$2 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-CKat0ExC.cjs', document.baseURI).href)));
246
+ const require$2 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-Ck6a9STO.cjs', document.baseURI).href)));
247
247
  function __require$1() { return require$2("node:fs"); }
248
248
 
249
- const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-CKat0ExC.cjs', document.baseURI).href)));
249
+ const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-Ck6a9STO.cjs', document.baseURI).href)));
250
250
  function __require() { return require$1("node:process"); }
251
251
 
252
252
  var help = {};
@@ -13347,7 +13347,7 @@ function getPathname(pathWithQuery) {
13347
13347
  }
13348
13348
 
13349
13349
  const CLI_VERSION_PLACEHOLDER = ['__HB', 'SDK', 'CLI', 'VERSION__'].join('_');
13350
- const BUILT_CLI_VERSION = '0.6.5';
13350
+ const BUILT_CLI_VERSION = '0.6.6-alpha.0';
13351
13351
  const PACKAGE_JSON_CANDIDATES = [
13352
13352
  path.resolve(__dirname, '..', '..', 'package.json'),
13353
13353
  path.resolve(__dirname, '..', 'package.json'),
@@ -13668,31 +13668,31 @@ function createCommandLoggerResolver(options) {
13668
13668
  };
13669
13669
  }
13670
13670
  const defaultClearLoginStatus = async (...args) => {
13671
- const { clearLoginStatus } = await Promise.resolve().then(function () { return require('./login-B6gERpSX.cjs'); });
13671
+ const { clearLoginStatus } = await Promise.resolve().then(function () { return require('./login-CqXRKZgq.cjs'); });
13672
13672
  return clearLoginStatus(...args);
13673
13673
  };
13674
13674
  const defaultLoginToHeybox = async (...args) => {
13675
- const { loginToHeybox } = await Promise.resolve().then(function () { return require('./login-B6gERpSX.cjs'); });
13675
+ const { loginToHeybox } = await Promise.resolve().then(function () { return require('./login-CqXRKZgq.cjs'); });
13676
13676
  return loginToHeybox(...args);
13677
13677
  };
13678
13678
  const defaultPrintLoginStatus = async (...args) => {
13679
- const { printLoginStatus } = await Promise.resolve().then(function () { return require('./login-B6gERpSX.cjs'); });
13679
+ const { printLoginStatus } = await Promise.resolve().then(function () { return require('./login-CqXRKZgq.cjs'); });
13680
13680
  return printLoginStatus(...args);
13681
13681
  };
13682
13682
  const defaultRunCreateCommand = async (...args) => {
13683
- const { runCreateCommand } = await Promise.resolve().then(function () { return require('./create-D3BBKay9.cjs'); });
13683
+ const { runCreateCommand } = await Promise.resolve().then(function () { return require('./create-CG36zW_8.cjs'); });
13684
13684
  return runCreateCommand(...args);
13685
13685
  };
13686
13686
  const defaultRunDevCommand = async (...args) => {
13687
- const { runDevCommand } = await Promise.resolve().then(function () { return require('./dev-C3u5FXIy.cjs'); });
13687
+ const { runDevCommand } = await Promise.resolve().then(function () { return require('./dev-BjlyFzNU.cjs'); });
13688
13688
  return runDevCommand(...args);
13689
13689
  };
13690
13690
  const defaultRunDoctorCommand = async (...args) => {
13691
- const { runDoctorCommand } = await Promise.resolve().then(function () { return require('./doctor-DEgZa2qC.cjs'); });
13691
+ const { runDoctorCommand } = await Promise.resolve().then(function () { return require('./doctor-OIjeEwrd.cjs'); });
13692
13692
  return runDoctorCommand(...args);
13693
13693
  };
13694
13694
  const defaultRunRemoteCommand = async (...args) => {
13695
- const { runRemoteCommand } = await Promise.resolve().then(function () { return require('./remote-BfQiZzeJ.cjs'); });
13695
+ const { runRemoteCommand } = await Promise.resolve().then(function () { return require('./remote-vquOa1cT.cjs'); });
13696
13696
  return runRemoteCommand(...args);
13697
13697
  };
13698
13698
  function resolveStandaloneLogger(options, verbose) {
@@ -1,13 +1,13 @@
1
1
  'use strict';
2
2
 
3
- var index$2 = require('./index-CKat0ExC.cjs');
3
+ var index$2 = require('./index-Ck6a9STO.cjs');
4
4
  var require$$0$2 = require('fs');
5
5
  var require$$2$1 = require('crypto');
6
6
  var require$$1$2 = require('path');
7
7
  var require$$0$3 = require('assert');
8
8
  var require$$4$2 = require('events');
9
9
  var require$$1$1 = require('util');
10
- var context$1 = require('./context-DjepdCaa.cjs');
10
+ var context$1 = require('./context-Do5YcZPw.cjs');
11
11
  var require$$0$5 = require('net');
12
12
  var require$$0$4 = require('url');
13
13
  var require$$2$2 = require('http');
@@ -3,9 +3,9 @@
3
3
  var promises = require('node:readline/promises');
4
4
  var node_crypto = require('node:crypto');
5
5
  var node_http = require('node:http');
6
- var session = require('./session-DPEq__gB.cjs');
6
+ var session = require('./session-DUM4KQHQ.cjs');
7
7
  var browser = require('./browser-RAy8e8cV.cjs');
8
- var index = require('./index-CKat0ExC.cjs');
8
+ var index = require('./index-Ck6a9STO.cjs');
9
9
  require('node:path');
10
10
  require('fs');
11
11
  require('constants');
@@ -1,13 +1,13 @@
1
1
  'use strict';
2
2
 
3
3
  var promises = require('node:readline/promises');
4
- var index = require('./index-CKat0ExC.cjs');
5
- var session = require('./session-DPEq__gB.cjs');
4
+ var index = require('./index-Ck6a9STO.cjs');
5
+ var session = require('./session-DUM4KQHQ.cjs');
6
6
  var childProcess = require('node:child_process');
7
7
  var fs = require('node:fs');
8
8
  var fs$1 = require('node:fs/promises');
9
9
  var path = require('node:path');
10
- var context = require('./context-DjepdCaa.cjs');
10
+ var context = require('./context-Do5YcZPw.cjs');
11
11
  require('node:module');
12
12
  require('path');
13
13
  require('os');
@@ -264,7 +264,7 @@ async function createDefaultCosClient(uploadToken) {
264
264
  };
265
265
  }
266
266
  async function loadCosConstructor() {
267
- const cosModule = await Promise.resolve().then(function () { return require('./index-B5gEl9ow.cjs'); }).then(function (n) { return n.index; });
267
+ const cosModule = await Promise.resolve().then(function () { return require('./index-NrjOOQMK.cjs'); }).then(function (n) { return n.index; });
268
268
  return cosModule.default;
269
269
  }
270
270
  function formatSize(bytes) {
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-CKat0ExC.cjs');
3
+ var index = require('./index-Ck6a9STO.cjs');
4
4
  var node_crypto = require('node:crypto');
5
5
  var path = require('node:path');
6
6
  var require$$0$2 = require('fs');
package/dist/cli.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./cli-chunks/index-CKat0ExC.cjs');
3
+ var index = require('./cli-chunks/index-Ck6a9STO.cjs');
4
4
  require('node:module');
5
5
  require('node:fs');
6
6
  require('node:fs/promises');
@@ -384,6 +384,7 @@
384
384
  <div class="actions" style="margin-top: 10px">
385
385
  <button id="reset-permissions-button" type="button">恢复初始权限</button>
386
386
  </div>
387
+ <div class="mac-app-status" id="permission-persistence-status"></div>
387
388
  <ul class="release-diagnostics" id="release-diagnostics"></ul>
388
389
  </section>
389
390
 
@@ -3427,6 +3427,11 @@ function requireBrowser () {
3427
3427
 
3428
3428
  var browserExports = requireBrowser();
3429
3429
 
3430
+ /** Dev Shell 读取局域网 Dev Session endpoint 的 query 参数。 */
3431
+ const MINI_PROGRAM_DEV_CONTEXT_QUERY_PARAM = 'dev_context_url';
3432
+ /** Mock Host 创建和读取 Dev Session 的固定路径。 */
3433
+ const MINI_PROGRAM_DEV_CONTEXT_PATH = '/__hb_sdk__/dev-context';
3434
+
3430
3435
  function createCSPViolationPanel(container) {
3431
3436
  const seen = new Set();
3432
3437
  const list = document.createElement('ol');
@@ -6385,6 +6390,7 @@ function isPlainRecord(value) {
6385
6390
 
6386
6391
  const NETWORK_PROXY_PATH = '/__hb_sdk_mock_network__';
6387
6392
  const MOCK_HOST_BOOTSTRAP_PATH = '/__hb_sdk_bootstrap__';
6393
+ const DEV_PERMISSIONS_PATH = '/__hb_sdk__/dev-permissions';
6388
6394
  const RUNTIME_GATE_PROBE_METHOD = 'runtime.gate.probe';
6389
6395
  const params = new URL(location.href).searchParams;
6390
6396
  const miniUrl = params.get('mini_url');
@@ -6397,6 +6403,9 @@ const storage = new Map();
6397
6403
  const logs = [];
6398
6404
  let handshaken = false;
6399
6405
  let navigationBarStyle = 'dark';
6406
+ let mobileQrGeneration = 0;
6407
+ let mobileQrRefreshTimer;
6408
+ let mobileDevSessionCreation = Promise.resolve();
6400
6409
  let currentUser = {
6401
6410
  heybox_id: 'debug_user',
6402
6411
  nickname: 'PC Debug User',
@@ -6419,6 +6428,7 @@ const elements = {
6419
6428
  mobileQrStatus: queryElement('#mobile-qr-status'),
6420
6429
  nicknameInput: queryElement('#nickname-input'),
6421
6430
  networkPermissionSelect: queryElement('#network-permission-select'),
6431
+ permissionPersistenceStatus: queryElement('#permission-persistence-status'),
6422
6432
  releaseDiagnostics: queryElement('#release-diagnostics'),
6423
6433
  resetPermissionsButton: queryElement('#reset-permissions-button'),
6424
6434
  storageSnapshot: queryElement('#storage-snapshot'),
@@ -6431,9 +6441,12 @@ if (!miniUrl) {
6431
6441
  }
6432
6442
  const miniProgramUrl = miniUrl;
6433
6443
  const bootstrap = await loadMockHostBootstrap();
6434
- const devContext = bootstrap.devContext;
6435
- const initialPermissionState = createMiniProgramMockPermissionState(devContext);
6436
- let permissionState = clonePermissionState(initialPermissionState);
6444
+ let devContext = bootstrap.devContext;
6445
+ let remotePermissionState = createMiniProgramMockPermissionState(devContext);
6446
+ let permissionState = clonePermissionState(remotePermissionState);
6447
+ let hasPermissionOverride = false;
6448
+ let permissionActionMessage = '';
6449
+ await loadPersistedPermissionConfiguration();
6437
6450
  const iframe = document.createElement('iframe');
6438
6451
  iframe.src = appendNonce(miniProgramUrl, nonce);
6439
6452
  iframe.allow = 'clipboard-read; clipboard-write';
@@ -6468,6 +6481,7 @@ updateStorageSnapshot();
6468
6481
  updatePermissionControls();
6469
6482
  window.addEventListener('message', handleMessage);
6470
6483
  window.addEventListener('beforeunload', () => {
6484
+ clearMobileQrRefreshTimer();
6471
6485
  postEvent('unload', { timestamp: Date.now() });
6472
6486
  });
6473
6487
  queryElement('#login-button').addEventListener('click', () => {
@@ -6494,13 +6508,10 @@ elements.mobileLanSelect.addEventListener('change', () => {
6494
6508
  void updateMobileQrCode();
6495
6509
  });
6496
6510
  elements.networkPermissionSelect.addEventListener('change', () => {
6497
- permissionState.networkRequest.status =
6498
- elements.networkPermissionSelect.value === 'enabled' ? 'enabled' : 'disabled';
6499
- rebuildRuntimeWithPermissions();
6511
+ void savePermissionOverride(elements.networkPermissionSelect.value === 'enabled' ? 'enabled' : 'disabled');
6500
6512
  });
6501
6513
  elements.resetPermissionsButton.addEventListener('click', () => {
6502
- permissionState = clonePermissionState(initialPermissionState);
6503
- rebuildRuntimeWithPermissions();
6514
+ void resetPermissionOverride();
6504
6515
  });
6505
6516
  const mobileAppQrReady = setupMobileAppQr();
6506
6517
  function createRuntime() {
@@ -6515,14 +6526,149 @@ function rebuildRuntimeWithPermissions() {
6515
6526
  }
6516
6527
  function updatePermissionControls() {
6517
6528
  elements.devContextStatus.textContent =
6518
- devContext.source === 'remote'
6519
- ? `已连接线上配置${devContext.miniProgramId ? ` · ${devContext.miniProgramId}` : ''}`
6520
- : '匿名本地沙箱';
6529
+ devContext.source === 'remote' ? `已连接线上配置${devContext.miniProgramId ? ` · ${devContext.miniProgramId}` : ''}` : '匿名本地沙箱';
6521
6530
  elements.networkPermissionSelect.value = permissionState.networkRequest.status;
6531
+ const remoteLabel = readPermissionStatusLabel(remotePermissionState.networkRequest.status);
6532
+ const localLabel = readPermissionStatusLabel(permissionState.networkRequest.status);
6533
+ const sourceDescription = hasPermissionOverride
6534
+ ? `远端基线:${remoteLabel} · 本地覆盖:${localLabel}`
6535
+ : `${devContext.source === 'remote' ? '当前使用远端权限' : '当前使用匿名默认权限'}:${remoteLabel}`;
6536
+ elements.permissionPersistenceStatus.textContent = permissionActionMessage
6537
+ ? `${sourceDescription} · ${permissionActionMessage}`
6538
+ : sourceDescription;
6522
6539
  const diagnostics = createMiniProgramDevReleaseDiagnostics(devContext, permissionState);
6523
- elements.releaseDiagnostics.innerHTML = diagnostics
6524
- .map((diagnostic) => `<li>${escapeHtml(diagnostic.message)}</li>`)
6525
- .join('');
6540
+ elements.releaseDiagnostics.innerHTML = diagnostics.map((diagnostic) => `<li>${escapeHtml(diagnostic.message)}</li>`).join('');
6541
+ }
6542
+ async function loadPersistedPermissionConfiguration() {
6543
+ try {
6544
+ const response = await fetch(DEV_PERMISSIONS_PATH, { cache: 'no-store' });
6545
+ const payload = await response.json();
6546
+ const configuration = readPermissionConfiguration(payload);
6547
+ if (!response.ok || !configuration) {
6548
+ throw new Error('权限持久化配置加载失败');
6549
+ }
6550
+ applyPermissionConfiguration(configuration);
6551
+ }
6552
+ catch {
6553
+ permissionActionMessage = '权限持久化暂不可用,刷新或重启后可能丢失本页修改。';
6554
+ }
6555
+ }
6556
+ async function savePermissionOverride(status) {
6557
+ elements.networkPermissionSelect.disabled = true;
6558
+ elements.resetPermissionsButton.disabled = true;
6559
+ permissionState = {
6560
+ networkRequest: {
6561
+ ...permissionState.networkRequest,
6562
+ status,
6563
+ },
6564
+ };
6565
+ hasPermissionOverride = true;
6566
+ permissionActionMessage = '正在保存本地权限覆盖...';
6567
+ rebuildRuntimeWithPermissions();
6568
+ void updateMobileQrCode();
6569
+ try {
6570
+ const response = await fetch(DEV_PERMISSIONS_PATH, {
6571
+ body: JSON.stringify({
6572
+ runtime_permissions: createMiniProgramMockRuntimePermissions(permissionState),
6573
+ }),
6574
+ headers: { 'content-type': 'application/json' },
6575
+ method: 'PUT',
6576
+ });
6577
+ const payload = await response.json();
6578
+ const configuration = readPermissionConfiguration(payload);
6579
+ if (!response.ok || !configuration) {
6580
+ throw new Error(readResponseMessage(payload) ?? '保存失败');
6581
+ }
6582
+ applyPermissionConfiguration(configuration, configuration.persistenceError || '本地权限覆盖已保存。');
6583
+ rebuildRuntimeWithPermissions();
6584
+ }
6585
+ catch (error) {
6586
+ permissionActionMessage = `${readErrorText(error)},当前页面仍会应用该权限,但刷新或重启后会丢失。`;
6587
+ updatePermissionControls();
6588
+ }
6589
+ finally {
6590
+ elements.networkPermissionSelect.disabled = false;
6591
+ elements.resetPermissionsButton.disabled = false;
6592
+ }
6593
+ }
6594
+ async function resetPermissionOverride() {
6595
+ elements.networkPermissionSelect.disabled = true;
6596
+ elements.resetPermissionsButton.disabled = true;
6597
+ try {
6598
+ const response = await fetch(DEV_PERMISSIONS_PATH, {
6599
+ method: 'DELETE',
6600
+ });
6601
+ const payload = await response.json();
6602
+ const configuration = readPermissionConfiguration(payload);
6603
+ if (!response.ok || !configuration) {
6604
+ throw new Error(readResponseMessage(payload) ?? '重置失败');
6605
+ }
6606
+ else {
6607
+ applyPermissionConfiguration(configuration, configuration.source === 'remote' ? '已重新读取远端权限并清除本地覆盖。' : '已清除本地权限覆盖。');
6608
+ }
6609
+ rebuildRuntimeWithPermissions();
6610
+ void updateMobileQrCode();
6611
+ }
6612
+ catch (error) {
6613
+ permissionActionMessage = `重置失败:${readErrorText(error)}`;
6614
+ updatePermissionControls();
6615
+ }
6616
+ finally {
6617
+ elements.networkPermissionSelect.disabled = false;
6618
+ elements.resetPermissionsButton.disabled = false;
6619
+ }
6620
+ }
6621
+ function readPermissionConfiguration(value) {
6622
+ if (!isRecord(value) || (value.source !== 'anonymous' && value.source !== 'remote')) {
6623
+ return undefined;
6624
+ }
6625
+ const remotePermissions = value.remote_permissions;
6626
+ const remoteParsed = parseMiniProgramRuntimePermissions(remotePermissions);
6627
+ const overridePermissions = value.override_permissions;
6628
+ const overrideParsed = parseMiniProgramRuntimePermissions(overridePermissions);
6629
+ if (remotePermissions !== undefined && !remoteParsed.valid) {
6630
+ return undefined;
6631
+ }
6632
+ if (overridePermissions !== undefined && !overrideParsed.valid) {
6633
+ return undefined;
6634
+ }
6635
+ const source = value.source;
6636
+ const fallbackContext = { };
6637
+ return {
6638
+ source,
6639
+ miniProgramId: typeof value.mini_program_id === 'string' ? value.mini_program_id : undefined,
6640
+ remotePermissions,
6641
+ remoteState: createMiniProgramMockPermissionState(remotePermissions === undefined ? fallbackContext : { runtimePermissions: remotePermissions }),
6642
+ ...(overridePermissions === undefined
6643
+ ? {}
6644
+ : {
6645
+ overrideState: createMiniProgramMockPermissionState({ runtimePermissions: overridePermissions }),
6646
+ }),
6647
+ persistenceError: typeof value.persistence_error === 'string' ? value.persistence_error : undefined,
6648
+ };
6649
+ }
6650
+ function applyPermissionConfiguration(configuration, message) {
6651
+ devContext =
6652
+ configuration.source === 'remote'
6653
+ ? {
6654
+ source: 'remote',
6655
+ miniProgramId: configuration.miniProgramId,
6656
+ runtimePermissions: configuration.remotePermissions,
6657
+ }
6658
+ : { source: 'anonymous', warning: devContext.warning };
6659
+ remotePermissionState = clonePermissionState(configuration.remoteState);
6660
+ permissionState = clonePermissionState(configuration.overrideState ?? configuration.remoteState);
6661
+ hasPermissionOverride = Boolean(configuration.overrideState);
6662
+ permissionActionMessage = message ?? configuration.persistenceError ?? '';
6663
+ }
6664
+ function readPermissionStatusLabel(status) {
6665
+ return status === 'enabled' ? '允许' : '拒绝';
6666
+ }
6667
+ function readResponseMessage(value) {
6668
+ return isRecord(value) && typeof value.message === 'string' ? value.message : undefined;
6669
+ }
6670
+ function readErrorText(error) {
6671
+ return error instanceof Error && error.message ? error.message : '操作失败';
6526
6672
  }
6527
6673
  function clonePermissionState(state) {
6528
6674
  return {
@@ -6754,9 +6900,7 @@ async function loadMockHostBootstrap() {
6754
6900
  devContext: readDevContext(payload.devContext, payload.runtimePermissions),
6755
6901
  lanAddresses: Array.isArray(payload.lanAddresses) ? payload.lanAddresses.filter(isLanAddress) : [],
6756
6902
  macAppProtocol: typeof payload.macAppProtocol === 'string' ? payload.macAppProtocol : undefined,
6757
- nativeAppLaunchUnavailableReason: typeof payload.nativeAppLaunchUnavailableReason === 'string'
6758
- ? payload.nativeAppLaunchUnavailableReason
6759
- : undefined,
6903
+ nativeAppLaunchUnavailableReason: typeof payload.nativeAppLaunchUnavailableReason === 'string' ? payload.nativeAppLaunchUnavailableReason : undefined,
6760
6904
  runtimePermissions: payload.runtimePermissions,
6761
6905
  };
6762
6906
  }
@@ -6805,6 +6949,8 @@ function setupMobileLanSelect() {
6805
6949
  elements.mobileLanSelect.disabled = !hasLanAddress;
6806
6950
  }
6807
6951
  async function updateMobileQrCode() {
6952
+ const generation = ++mobileQrGeneration;
6953
+ clearMobileQrRefreshTimer();
6808
6954
  if (nativeAppLaunchUnavailableReason) {
6809
6955
  elements.mobileQrImage.removeAttribute('src');
6810
6956
  elements.mobileQrImage.hidden = true;
@@ -6818,8 +6964,8 @@ async function updateMobileQrCode() {
6818
6964
  elements.mobileQrStatus.textContent = '';
6819
6965
  return;
6820
6966
  }
6821
- const payload = selected.mobileAppQrPayload;
6822
- if (!payload) {
6967
+ const basePayload = selected.mobileAppQrPayload;
6968
+ if (!basePayload) {
6823
6969
  elements.mobileQrImage.removeAttribute('src');
6824
6970
  elements.mobileQrImage.hidden = true;
6825
6971
  elements.mobileQrStatus.textContent = '真机调试配置不可用,请重启 hb-sdk dev 后重试。';
@@ -6827,20 +6973,112 @@ async function updateMobileQrCode() {
6827
6973
  }
6828
6974
  elements.mobileQrStatus.textContent = '正在生成二维码...';
6829
6975
  try {
6830
- elements.mobileQrImage.src = await browserExports.toDataURL(payload, {
6976
+ const devSession = await createMobileDevSession(selected);
6977
+ if (generation !== mobileQrGeneration) {
6978
+ return;
6979
+ }
6980
+ const payload = applyDevContextToMobileQrPayload(basePayload, devSession.url);
6981
+ const imageUrl = await browserExports.toDataURL(payload, {
6831
6982
  errorCorrectionLevel: 'M',
6832
6983
  margin: 1,
6833
6984
  width: 176,
6834
6985
  });
6986
+ if (generation !== mobileQrGeneration) {
6987
+ return;
6988
+ }
6989
+ elements.mobileQrImage.src = imageUrl;
6835
6990
  elements.mobileQrImage.hidden = false;
6836
6991
  elements.mobileQrStatus.textContent = '';
6992
+ scheduleMobileQrRefresh(devSession.expiresAt, generation);
6837
6993
  }
6838
6994
  catch {
6995
+ if (generation !== mobileQrGeneration) {
6996
+ return;
6997
+ }
6839
6998
  elements.mobileQrImage.removeAttribute('src');
6840
6999
  elements.mobileQrImage.hidden = true;
6841
7000
  elements.mobileQrStatus.textContent = '二维码生成失败';
6842
7001
  }
6843
7002
  }
7003
+ async function createMobileDevSession(selected) {
7004
+ const creation = mobileDevSessionCreation.then(() => requestMobileDevSession(selected));
7005
+ mobileDevSessionCreation = creation.then(() => undefined, () => undefined);
7006
+ return creation;
7007
+ }
7008
+ async function requestMobileDevSession(selected) {
7009
+ const miniUrl = new URL(selected.appUrl);
7010
+ const response = await fetch(MINI_PROGRAM_DEV_CONTEXT_PATH, {
7011
+ body: JSON.stringify({
7012
+ mini_url_origin: miniUrl.origin,
7013
+ runtime_permissions: createMiniProgramMockRuntimePermissions({
7014
+ ...permissionState,
7015
+ networkRequest: {
7016
+ ...permissionState.networkRequest,
7017
+ useOfficialDomain: false,
7018
+ },
7019
+ }),
7020
+ }),
7021
+ headers: { 'content-type': 'application/json' },
7022
+ method: 'POST',
7023
+ });
7024
+ if (!response.ok) {
7025
+ throw new Error('Failed to create mobile Dev Session');
7026
+ }
7027
+ const result = await response.json();
7028
+ if (!isRecord(result) ||
7029
+ typeof result.token !== 'string' ||
7030
+ !/^[a-f0-9]{64}$/.test(result.token) ||
7031
+ typeof result.expires_at !== 'number' ||
7032
+ !Number.isFinite(result.expires_at) ||
7033
+ result.expires_at <= Date.now()) {
7034
+ throw new Error('Invalid mobile Dev Session response');
7035
+ }
7036
+ const devContextUrl = new URL(`${MINI_PROGRAM_DEV_CONTEXT_PATH}/${result.token}`, location.origin);
7037
+ devContextUrl.hostname = miniUrl.hostname;
7038
+ return {
7039
+ expiresAt: result.expires_at,
7040
+ url: devContextUrl.toString(),
7041
+ };
7042
+ }
7043
+ function scheduleMobileQrRefresh(expiresAt, generation) {
7044
+ mobileQrRefreshTimer = window.setTimeout(() => {
7045
+ if (generation !== mobileQrGeneration) {
7046
+ return;
7047
+ }
7048
+ elements.mobileQrImage.removeAttribute('src');
7049
+ elements.mobileQrImage.hidden = true;
7050
+ elements.mobileQrStatus.textContent = '二维码已过期,正在重新生成...';
7051
+ void updateMobileQrCode();
7052
+ }, Math.max(0, expiresAt - Date.now()));
7053
+ }
7054
+ function clearMobileQrRefreshTimer() {
7055
+ if (mobileQrRefreshTimer === undefined) {
7056
+ return;
7057
+ }
7058
+ window.clearTimeout(mobileQrRefreshTimer);
7059
+ mobileQrRefreshTimer = undefined;
7060
+ }
7061
+ function applyDevContextToMobileQrPayload(payload, devContextUrl) {
7062
+ const protocolMarker = '#heybox://';
7063
+ const protocolIndex = payload.indexOf(protocolMarker);
7064
+ if (protocolIndex < 0) {
7065
+ throw new Error('Invalid mobile App QR payload');
7066
+ }
7067
+ const encodedPayload = payload.slice(protocolIndex + protocolMarker.length);
7068
+ const openWindowPayload = JSON.parse(decodeURIComponent(encodedPayload));
7069
+ if (!isRecord(openWindowPayload) || !isRecord(openWindowPayload.webview)) {
7070
+ throw new Error('Invalid mobile App openWindow payload');
7071
+ }
7072
+ const devShellUrlValue = openWindowPayload.webview.url;
7073
+ if (typeof devShellUrlValue !== 'string') {
7074
+ throw new Error('Missing mobile App dev shell URL');
7075
+ }
7076
+ const devShellUrl = new URL(devShellUrlValue);
7077
+ devShellUrl.searchParams.delete('dev_network_request');
7078
+ devShellUrl.searchParams.set(MINI_PROGRAM_DEV_CONTEXT_QUERY_PARAM, devContextUrl);
7079
+ openWindowPayload.webview.url = devShellUrl.toString();
7080
+ return `${payload.slice(0, protocolIndex)}${protocolMarker}${encodeURIComponent(JSON.stringify(openWindowPayload))}`;
7081
+ }
6844
7082
  function updateNativeAppLaunchAvailability() {
6845
7083
  const isUnavailable = Boolean(nativeAppLaunchUnavailableReason);
6846
7084
  elements.macAppButton.disabled = isUnavailable;
package/dist/index.cjs.js CHANGED
@@ -325,7 +325,7 @@ function createMessageId() {
325
325
  /** 构建时替换为当前发布包的实际版本。 */
326
326
  const HB_SDK_VERSION = typeof undefined === 'string'
327
327
  ? undefined
328
- : '0.6.5';
328
+ : '0.6.6-alpha.0';
329
329
 
330
330
  /**
331
331
  * 判断未知数据是否符合小程序 bridge 消息信封。
package/dist/index.esm.js CHANGED
@@ -321,7 +321,7 @@ function createMessageId() {
321
321
  /** 构建时替换为当前发布包的实际版本。 */
322
322
  const HB_SDK_VERSION = typeof undefined === 'string'
323
323
  ? undefined
324
- : '0.6.5';
324
+ : '0.6.6-alpha.0';
325
325
 
326
326
  /**
327
327
  * 判断未知数据是否符合小程序 bridge 消息信封。
package/dist/vite.cjs.js CHANGED
@@ -7,7 +7,7 @@ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentS
7
7
  /** 构建时替换为当前发布包的实际版本。 */
8
8
  const HB_SDK_VERSION = typeof undefined === 'string'
9
9
  ? undefined
10
- : '0.6.5';
10
+ : '0.6.6-alpha.0';
11
11
 
12
12
  var re = {exports: {}};
13
13
 
package/dist/vite.esm.js CHANGED
@@ -4,7 +4,7 @@ import path from 'node:path';
4
4
  /** 构建时替换为当前发布包的实际版本。 */
5
5
  const HB_SDK_VERSION = typeof undefined === 'string'
6
6
  ? undefined
7
- : '0.6.5';
7
+ : '0.6.6-alpha.0';
8
8
 
9
9
  var re = {exports: {}};
10
10
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heybox/hb-sdk",
3
- "version": "0.6.5",
3
+ "version": "0.6.6-alpha.0",
4
4
  "sideEffects": [
5
5
  "./src/index.ts",
6
6
  "./src/core/singleton.ts",
@@ -51,7 +51,8 @@
51
51
  "author": "",
52
52
  "license": "ISC",
53
53
  "dependencies": {
54
- "parse5": "^7.3.0"
54
+ "parse5": "^7.3.0",
55
+ "undici": "^7.28.0"
55
56
  },
56
57
  "peerDependencies": {
57
58
  "vite": ">=5"
@@ -92,7 +93,7 @@
92
93
  "vue": "^2.7.16",
93
94
  "vite": "^8.0.12",
94
95
  "vitest": "^3.2.4",
95
- "@heybox/hb-api": "~1.25.3"
96
+ "@heybox/hb-api": "~1.25.4"
96
97
  },
97
98
  "publishConfig": {
98
99
  "registry": "https://registry.npmjs.org/",
package/skill/SKILL.md CHANGED
@@ -80,7 +80,9 @@ For CLI and local development:
80
80
  2. Do not use `hb-sdk login` as a workaround for mini-program user authentication.
81
81
  3. Use the built-in local debugging page instead of creating another browser Mock.
82
82
  4. Keep the Vite `miniappManifest()` plugin enabled.
83
- 5. Treat browser Mock settings as local-only; they must not be presented as online permissions.
83
+ 5. Treat Dev Context permission changes as persistent local overrides, not online configuration changes. `hb-sdk` scopes them by real project path and `miniProgramId`, restores them after page refresh or `hb-sdk dev` restart, and clears them only after an explicit reset successfully refetches remote permissions. A regenerated Mobile App QR code may carry only a `dev_context_url` backed by a 256-bit token that expires after 5 minutes; it must not embed a permission snapshot.
84
+ 6. Require the Runtime Host to fetch the immutable Dev Session snapshot before startup. Dev Session `network.request` must use the token-bound local proxy, never a native credential adapter, and must force `useOfficialDomain: false`.
85
+ 7. Do not treat the legacy `dev_network_request` query as authorization or as a fallback. This Web-only flow must preserve existing Android/iOS URL pass-through behavior without requiring client changes.
84
86
 
85
87
  For host/runtime/protocol-maintenance code:
86
88