@heybox/hb-sdk 0.8.0-alpha → 0.8.0-alpha.3

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 (64) hide show
  1. package/CHANGELOG.md +44 -1
  2. package/README.md +87 -14
  3. package/THIRD_PARTY_NOTICES.md +1755 -0
  4. package/dist/cli-chunks/{build-DJWFSM1B.cjs → build-qWzAbpS7.cjs} +2 -2
  5. package/dist/cli-chunks/{context-DV2UK1Nz.cjs → context-CtS2Thp0.cjs} +1 -26
  6. package/dist/cli-chunks/{create-2HfoB48V.cjs → create-PV5ua977.cjs} +1 -1
  7. package/dist/cli-chunks/{dev-Dgt2zS9k.cjs → dev-CwKbAm_H.cjs} +337 -522
  8. package/dist/cli-chunks/doctor-tJUGOYrm.cjs +65 -0
  9. package/dist/cli-chunks/{index-BjoSXl8C.cjs → index-DVuD75Hr.cjs} +1 -1
  10. package/dist/cli-chunks/{index-D62ANeBv.cjs → index-De687C6-.cjs} +33 -24
  11. package/dist/cli-chunks/{index.esm-CigcxJ2B.cjs → index.esm-B-4yrLNm.cjs} +6 -5
  12. package/dist/cli-chunks/{login-Cumknwdx.cjs → login-DolpqD8K.cjs} +2 -2
  13. package/dist/cli-chunks/{project-vite-CcE-HMmd.cjs → project-vite-1rvkK-M8.cjs} +1 -1
  14. package/dist/cli-chunks/{remote-DDdP3xcE.cjs → remote-rIAQE_G2.cjs} +4 -4
  15. package/dist/cli-chunks/{session-BDi_AZSv.cjs → session-CzaM2Cq3.cjs} +1 -1
  16. package/dist/cli-chunks/skill-CM40_9WH.cjs +83 -0
  17. package/dist/cli-chunks/version-Bz-AfXQU.cjs +8 -0
  18. package/dist/cli.cjs +1 -1
  19. package/dist/devtools/browser-dev-host/assets/browser-dev-host-uq-Wac6k.js +97 -0
  20. package/dist/devtools/browser-dev-host/assets/heybox-logo-CogNENsk.svg +6 -0
  21. package/dist/devtools/browser-dev-host/assets/index-CeP6SLB3.js +567 -0
  22. package/dist/devtools/browser-dev-host/assets/index-KD2f3Jdz.css +1 -0
  23. package/dist/devtools/browser-dev-host/assets/workbench-state-D-1U0JRq.js +5 -0
  24. package/dist/devtools/browser-dev-host/index.html +6 -435
  25. package/dist/index.cjs.js +924 -28
  26. package/dist/index.esm.js +924 -29
  27. package/dist/protocol.cjs.js +208 -6
  28. package/dist/protocol.esm.js +182 -7
  29. package/dist/vite.cjs.js +1 -1
  30. package/dist/vite.esm.js +1 -1
  31. package/package.json +29 -10
  32. package/skill/SKILL.md +16 -13
  33. package/skill/references/api-protocol.md +100 -4
  34. package/skill/references/api-root.md +142 -15
  35. package/skill/references/cli.md +27 -22
  36. package/skill/references/examples.md +30 -1
  37. package/skill/references/llms-index.md +1 -1
  38. package/skill/references/recipes.md +106 -2
  39. package/skill/references/safety-boundaries.md +12 -1
  40. package/skill/skill.json +10 -5
  41. package/types/core/client.d.ts +17 -1
  42. package/types/core/sdk.d.ts +3 -0
  43. package/types/core/singleton.d.ts +3 -0
  44. package/types/index.d.ts +4 -2
  45. package/types/modules/files/index.d.ts +5 -0
  46. package/types/modules/files/registry.d.ts +35 -0
  47. package/types/modules/files/types.d.ts +159 -0
  48. package/types/modules/network/index.d.ts +50 -3
  49. package/types/protocol/capabilities.d.ts +2 -2
  50. package/types/protocol/constants.d.ts +1 -1
  51. package/types/protocol/guards.d.ts +1 -1
  52. package/types/protocol/types.d.ts +1 -1
  53. package/types/protocol.d.ts +4 -3
  54. package/types/skill-metadata.d.ts +0 -4
  55. package/dist/cli-chunks/doctor-C95gIao_.cjs +0 -204
  56. package/dist/devtools/browser-dev-host/main.js +0 -12263
  57. package/skill/scripts/check-references.mjs +0 -14
  58. package/skill/scripts/markdown-sections.mjs +0 -36
  59. package/skill/scripts/package-skill.mjs +0 -60
  60. package/skill/scripts/package-skill.sh +0 -6
  61. package/skill/scripts/skill-metadata.mjs +0 -77
  62. package/skill/scripts/sync-agent-skills-payload.mjs +0 -359
  63. package/skill/scripts/sync-references.mjs +0 -794
  64. package/skill/scripts/validate-skill.mjs +0 -263
@@ -8,15 +8,16 @@ var node_crypto = require('node:crypto');
8
8
  var promises = require('node:dns/promises');
9
9
  var node_http = require('node:http');
10
10
  var node_module = require('node:module');
11
- var context = require('./context-DV2UK1Nz.cjs');
11
+ var context = require('./context-CtS2Thp0.cjs');
12
12
  var undici = require('undici');
13
13
  var fs$1 = require('node:fs/promises');
14
- var index = require('./index-D62ANeBv.cjs');
14
+ var index = require('./index-De687C6-.cjs');
15
15
  var require$$0$1 = require('crypto');
16
16
  var require$$0 = require('buffer');
17
- var session = require('./session-BDi_AZSv.cjs');
17
+ var session = require('./session-CzaM2Cq3.cjs');
18
18
  var browser = require('./browser-RAy8e8cV.cjs');
19
- var projectVite = require('./project-vite-CcE-HMmd.cjs');
19
+ var projectVite = require('./project-vite-1rvkK-M8.cjs');
20
+ var version = require('./version-Bz-AfXQU.cjs');
20
21
  var runtimePermissionEnv = require('./runtime-permission-env-CjsCe5bp.cjs');
21
22
 
22
23
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
@@ -429,6 +430,25 @@ class BrowserDevHostHttpError extends Error {
429
430
  this.name = 'BrowserDevHostHttpError';
430
431
  }
431
432
  }
433
+ function createBrowserDevHostRequestAbortScope(request, response) {
434
+ const controller = new AbortController();
435
+ const abort = () => controller.abort();
436
+ const onResponseClose = () => {
437
+ if (!response.writableEnded)
438
+ abort();
439
+ };
440
+ request.once('aborted', abort);
441
+ response.once('close', onResponseClose);
442
+ if (request.aborted || (response.destroyed && !response.writableEnded))
443
+ abort();
444
+ return {
445
+ dispose() {
446
+ request.removeListener('aborted', abort);
447
+ response.removeListener('close', onResponseClose);
448
+ },
449
+ signal: controller.signal,
450
+ };
451
+ }
432
452
  function readJsonRequestBody(request, options = {}) {
433
453
  return new Promise((resolve, reject) => {
434
454
  const chunks = [];
@@ -498,7 +518,7 @@ function writeSerializedJsonResponse(response, status, body) {
498
518
  });
499
519
  response.end(body);
500
520
  }
501
- function isRecord$3(value) {
521
+ function isRecord$2(value) {
502
522
  return Object.prototype.toString.call(value) === '[object Object]';
503
523
  }
504
524
  function isObjectLike(value) {
@@ -594,7 +614,6 @@ function redactSensitivePairsInRawText(text) {
594
614
  });
595
615
  }
596
616
 
597
- const MAX_BROWSER_DEV_HOST_NETWORK_REDIRECTS = 5;
598
617
  const MAX_BROWSER_DEV_HOST_NETWORK_REQUEST_BODY = 2 * 1024 * 1024;
599
618
  const MAX_BROWSER_DEV_HOST_NETWORK_RESPONSE_BODY = 5 * 1024 * 1024;
600
619
  const DENIED_NETWORK_TARGETS = createDeniedNetworkTargets();
@@ -615,16 +634,17 @@ async function handleBrowserDevHostNetworkProxy(request, response, fetchImpl, lo
615
634
  let payload;
616
635
  try {
617
636
  payload = await readJsonRequestBody(request);
618
- const requestAbort = new AbortController();
619
- if (request.aborted)
620
- requestAbort.abort();
621
- else
622
- request.once('aborted', () => requestAbort.abort());
623
- const result = await requestBrowserDevHostNetwork(payload, fetchImpl, lookupHostname, options.allowedHttpOrigins, requestAbort.signal);
624
- if (typeof result.status === 'number' && (result.status < 200 || result.status >= 300)) {
625
- logBrowserDevHostNetworkProxyDiagnostic('http_status', payload, result);
637
+ const requestAbort = createBrowserDevHostRequestAbortScope(request, response);
638
+ try {
639
+ const result = await requestBrowserDevHostNetwork(payload, fetchImpl, lookupHostname, options.allowedHttpOrigins, requestAbort.signal);
640
+ if (typeof result.status === 'number' && (result.status < 200 || result.status >= 300)) {
641
+ logBrowserDevHostNetworkProxyDiagnostic('http_status', payload, result);
642
+ }
643
+ writeNetworkJsonResponse(response, 200, result, cors);
644
+ }
645
+ finally {
646
+ requestAbort.dispose();
626
647
  }
627
- writeNetworkJsonResponse(response, 200, result, cors);
628
648
  }
629
649
  catch (error) {
630
650
  logBrowserDevHostNetworkProxyDiagnostic('proxy_error', payload, undefined, error);
@@ -639,10 +659,10 @@ function logBrowserDevHostNetworkProxyDiagnostic(phase, payload, result, error)
639
659
  return;
640
660
  }
641
661
  const detail = { phase };
642
- if (isRecord$3(payload) && typeof payload.url === 'string') {
662
+ if (isRecord$2(payload) && typeof payload.url === 'string') {
643
663
  detail.url = sanitizeNetworkRequestUrl(payload.url);
644
664
  }
645
- if (isRecord$3(payload) && typeof payload.method === 'string') {
665
+ if (isRecord$2(payload) && typeof payload.method === 'string') {
646
666
  detail.method = payload.method;
647
667
  }
648
668
  if (typeof result?.status === 'number') {
@@ -673,14 +693,14 @@ function writeNetworkJsonResponse(response, status, body, cors) {
673
693
  }
674
694
  const BROWSER_DEV_HOST_NETWORK_MULTIPART_UNSUPPORTED_MESSAGE = 'network.request 不支持 multipart/form-data。App Host 客户端代发仅支持 application/x-www-form-urlencoded(form)与 application/json;请将 data 编码为 form 字符串(例如 new URLSearchParams({...}).toString())并设置 Content-Type: application/x-www-form-urlencoded。文件上传请使用专用上传能力,勿手写 multipart boundary。';
675
695
  async function requestBrowserDevHostNetwork(payload, fetchImpl, lookupHostname, allowedHttpOrigins, requestSignal) {
676
- if (!isRecord$3(payload) || typeof payload.url !== 'string' || !payload.url.trim()) {
696
+ if (!isRecord$2(payload) || typeof payload.url !== 'string' || !payload.url.trim()) {
677
697
  throw createBrowserDevHostError(400, 'INVALID_NETWORK_REQUEST', 'network.request url 必须是非空字符串');
678
698
  }
679
699
  const url = createBrowserDevHostNetworkUrl(payload.url, payload.params);
680
700
  const method = typeof payload.method === 'string' && payload.method.trim() ? payload.method.trim().toUpperCase() : 'GET';
681
701
  const headers = normalizeBrowserDevHostNetworkHeaders(payload.headers);
682
702
  assertSupportedBrowserDevHostNetworkRequestShape(headers, payload.data);
683
- const body = createBrowserDevHostNetworkBody(method, payload.data, headers);
703
+ const body = createBrowserDevHostNetworkBody(method, payload.data, headers, readBodyEncoding(payload.bodyEncoding, payload.data));
684
704
  const controller = new AbortController();
685
705
  const onRequestAbort = () => controller.abort(requestSignal.reason);
686
706
  requestSignal.addEventListener('abort', onRequestAbort, { once: true });
@@ -691,7 +711,7 @@ async function requestBrowserDevHostNetwork(payload, fetchImpl, lookupHostname,
691
711
  const pinnedTargets = new Map();
692
712
  const dispatcher = createPinnedNetworkDispatcher(pinnedTargets);
693
713
  try {
694
- const response = await fetchBrowserDevHostNetworkWithRedirects({
714
+ const response = await fetchBrowserDevHostNetworkNoRedirect({
695
715
  body,
696
716
  dispatcher,
697
717
  fetchImpl,
@@ -724,43 +744,17 @@ async function requestBrowserDevHostNetwork(payload, fetchImpl, lookupHostname,
724
744
  await dispatcher.close();
725
745
  }
726
746
  }
727
- async function fetchBrowserDevHostNetworkWithRedirects(options) {
728
- let url = options.url;
729
- let method = options.method;
730
- let body = options.body;
731
- for (let redirectCount = 0; redirectCount <= MAX_BROWSER_DEV_HOST_NETWORK_REDIRECTS; redirectCount += 1) {
732
- const pinnedTarget = await resolveBrowserDevHostNetworkTarget(url, options.lookupHostname, options.allowedHttpOrigins);
733
- options.pinnedTargets.set(createPinnedNetworkTargetKey(url), pinnedTarget);
734
- const response = await options.fetchImpl(url.toString(), {
735
- body,
736
- dispatcher: options.dispatcher,
737
- headers: options.headers,
738
- method,
739
- redirect: 'manual',
740
- signal: options.signal,
741
- });
742
- if (![301, 302, 303, 307, 308].includes(response.status)) {
743
- return response;
744
- }
745
- const location = response.headers.get('location');
746
- if (!location) {
747
- return response;
748
- }
749
- if (redirectCount === MAX_BROWSER_DEV_HOST_NETWORK_REDIRECTS) {
750
- throw createBrowserDevHostError(502, 'TOO_MANY_REDIRECTS', 'network.request redirect limit exceeded');
751
- }
752
- await response.body?.cancel();
753
- const redirectedUrl = new URL(location, url);
754
- if (redirectedUrl.origin !== url.origin) {
755
- throw createBrowserDevHostError(403, 'NETWORK_REDIRECT_DENIED', 'network.request 不允许跨 origin redirect');
756
- }
757
- url = redirectedUrl;
758
- if (response.status === 303 || ((response.status === 301 || response.status === 302) && method === 'POST')) {
759
- method = 'GET';
760
- body = undefined;
761
- }
762
- }
763
- throw createBrowserDevHostError(502, 'TOO_MANY_REDIRECTS', 'network.request redirect limit exceeded');
747
+ async function fetchBrowserDevHostNetworkNoRedirect(options) {
748
+ const pinnedTarget = await resolveBrowserDevHostNetworkTarget(options.url, options.lookupHostname, options.allowedHttpOrigins);
749
+ options.pinnedTargets.set(createPinnedNetworkTargetKey(options.url), pinnedTarget);
750
+ return options.fetchImpl(options.url.toString(), {
751
+ body: options.body,
752
+ dispatcher: options.dispatcher,
753
+ headers: options.headers,
754
+ method: options.method,
755
+ redirect: 'manual',
756
+ signal: options.signal,
757
+ });
764
758
  }
765
759
  async function resolveBrowserDevHostNetworkTarget(url, lookupHostname, allowedHttpOrigins) {
766
760
  if (!['http:', 'https:'].includes(url.protocol)) {
@@ -890,7 +884,7 @@ function createBrowserDevHostNetworkUrl(input, params) {
890
884
  if (!['http:', 'https:'].includes(url.protocol)) {
891
885
  throw createBrowserDevHostError(400, 'INVALID_NETWORK_REQUEST', 'network.request 仅支持 HTTP(S) URL');
892
886
  }
893
- if (isRecord$3(params)) {
887
+ if (isRecord$2(params)) {
894
888
  Object.entries(params).forEach(([key, value]) => {
895
889
  if (value !== undefined && value !== null) {
896
890
  url.searchParams.set(key, String(value));
@@ -901,7 +895,7 @@ function createBrowserDevHostNetworkUrl(input, params) {
901
895
  }
902
896
  function normalizeBrowserDevHostNetworkHeaders(headers) {
903
897
  const normalized = new Headers();
904
- if (!isRecord$3(headers)) {
898
+ if (!isRecord$2(headers)) {
905
899
  return normalized;
906
900
  }
907
901
  Object.entries(headers).forEach(([key, value]) => {
@@ -947,22 +941,60 @@ function looksLikeMultipartBody(data) {
947
941
  const trimmed = data.trimStart();
948
942
  return trimmed.startsWith('--') && /content-disposition\s*:\s*form-data/i.test(data);
949
943
  }
950
- function createBrowserDevHostNetworkBody(method, data, headers) {
944
+ function createBrowserDevHostNetworkBody(method, data, headers, bodyEncoding) {
951
945
  if (data === undefined || method === 'GET' || method === 'HEAD') {
952
946
  return undefined;
953
947
  }
954
- const body = typeof data === 'string' ? data : JSON.stringify(data);
948
+ const body = typeof data === 'string'
949
+ ? data
950
+ : bodyEncoding === 'form'
951
+ ? createLegacyFormBody$1(data)
952
+ : JSON.stringify(data);
955
953
  if (Buffer.byteLength(body) > MAX_BROWSER_DEV_HOST_NETWORK_REQUEST_BODY) {
956
954
  throw createBrowserDevHostError(413, 'REQUEST_ENTITY_TOO_LARGE', 'network.request data exceeds 2097152 bytes');
957
955
  }
958
- if (typeof data === 'string') {
959
- return body;
956
+ if (bodyEncoding === 'form' && !headers.has('content-type')) {
957
+ headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
960
958
  }
961
- if (!headers.has('content-type')) {
959
+ else if (bodyEncoding === 'json' && typeof data !== 'string' && !headers.has('content-type')) {
962
960
  headers.set('content-type', 'application/json');
963
961
  }
964
962
  return body;
965
963
  }
964
+ function readBodyEncoding(value, data) {
965
+ if (value === 'form' || value === 'json')
966
+ return value;
967
+ if (value === undefined && (data === undefined || typeof data === 'string'))
968
+ return undefined;
969
+ throw createBrowserDevHostError(400, 'INVALID_NETWORK_REQUEST', 'network.request bodyEncoding 必须明确为 form 或 json');
970
+ }
971
+ function encodeLegacyFormComponent$1(value) {
972
+ return encodeURIComponent(value).replace(/[!'()*]/g, (character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`);
973
+ }
974
+ function appendLegacyFormValue$1(pairs, key, value) {
975
+ if (value === undefined)
976
+ return;
977
+ if (value === null) {
978
+ pairs.push([key, '']);
979
+ return;
980
+ }
981
+ if (Array.isArray(value)) {
982
+ value.forEach((item) => appendLegacyFormValue$1(pairs, key, item));
983
+ return;
984
+ }
985
+ if (typeof value === 'object' && !(value instanceof Date)) {
986
+ Object.entries(value).forEach(([childKey, childValue]) => appendLegacyFormValue$1(pairs, `${key}[${childKey}]`, childValue));
987
+ return;
988
+ }
989
+ pairs.push([key, value instanceof Date ? value.toISOString() : String(value)]);
990
+ }
991
+ function createLegacyFormBody$1(data) {
992
+ const pairs = [];
993
+ if (data && typeof data === 'object') {
994
+ Object.entries(data).forEach(([key, value]) => appendLegacyFormValue$1(pairs, key, value));
995
+ }
996
+ return pairs.map(([key, value]) => `${encodeLegacyFormComponent$1(key)}=${encodeLegacyFormComponent$1(value)}`).join('&');
997
+ }
966
998
  function safeJsonParse(text) {
967
999
  try {
968
1000
  return JSON.parse(text);
@@ -1098,7 +1130,7 @@ function createDevSessionRoutes(options) {
1098
1130
  };
1099
1131
  }
1100
1132
  function validateDevSessionCreatePayload(payload, allowedMiniUrlOrigins) {
1101
- if (!isRecord$3(payload) || Object.keys(payload).some((key) => !['mini_url_origin', 'runtime_permissions'].includes(key))) {
1133
+ if (!isRecord$2(payload) || Object.keys(payload).some((key) => !['mini_url_origin', 'runtime_permissions'].includes(key))) {
1102
1134
  throw new TypeError('Dev Session body is invalid');
1103
1135
  }
1104
1136
  if (typeof payload.mini_url_origin !== 'string') {
@@ -1589,6 +1621,22 @@ const TOKEN_PATTERN = /^[A-Za-z0-9_-]{22}$/;
1589
1621
  const MAX_TOKEN_GENERATION_ATTEMPTS = 8;
1590
1622
  const CLOSE_WINDOW_DELAY_MS = 500;
1591
1623
  const CLOSE_WINDOW_PROTOCOL = `heybox://${encodeURIComponent(JSON.stringify({ protocol_type: 'closeWindow' }))}`;
1624
+ const MINI_PROGRAM_URL_QUERY_PARAM$1 = 'mini_url';
1625
+ const MINI_PROGRAM_SDK_VERSION_QUERY_PARAM = 'sdk_version';
1626
+ const MINI_PROGRAM_LOCAL_DEV_LAUNCH_TOKEN_QUERY_PARAM = 'local_dev_launch_token';
1627
+ const MINI_PROGRAM_DEV_SHELL_URL = 'heybox-mini-dev://sandbox';
1628
+ const OPEN_IN_APP_URL = 'https://api.xiaoheihe.cn/open_inapp/';
1629
+ function createMobileAppQrPayload(appUrl, options = {}) {
1630
+ const protocol = createHeyboxProtocol(createMiniProgramDevShellOpenWindowPayload(appUrl, options));
1631
+ return `${OPEN_IN_APP_URL}#${protocol}`;
1632
+ }
1633
+ function projectMiniProgramDevContextUrlToPrivateHost(value, host) {
1634
+ const url = parseDevContextUrl(value, 'loopback', 'devContextUrl must be a canonical loopback Dev Session URL');
1635
+ if (!isCanonicalPrivateLanIpv4(host))
1636
+ throw new TypeError('Mobile Dev Context host must be a canonical private IPv4 address');
1637
+ url.hostname = host;
1638
+ return url.href;
1639
+ }
1592
1640
  function createMobileLaunchRedirectRegistry(options = {}) {
1593
1641
  const capacity = options.capacity ?? DEFAULT_CAPACITY;
1594
1642
  const ttlMs = options.ttlMs ?? DEFAULT_TTL_MS;
@@ -1673,6 +1721,69 @@ function createMobileLaunchRedirectDocument(payload) {
1673
1721
  const closeUrl = JSON.stringify(CLOSE_WINDOW_PROTOCOL).replaceAll('<', '\\u003c');
1674
1722
  return `<!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>打开调试小程序</title></head><body><p>正在打开本地调试小程序…</p><p><a href="${href}" id="launch">如果没有自动跳转,请点这里</a></p><script>(function(){var launchUrl=${launchUrl};var closeUrl=${closeUrl};function go(){location.href=launchUrl;setTimeout(function(){location.href=closeUrl;},${CLOSE_WINDOW_DELAY_MS});}document.getElementById("launch").addEventListener("click",function(event){event.preventDefault();go();});go();})();</script></body></html>`;
1675
1723
  }
1724
+ function createMiniProgramDevShellOpenWindowPayload(appUrl, options) {
1725
+ const devShellUrl = `${MINI_PROGRAM_DEV_SHELL_URL}?${readDevShellQueryEntries(appUrl, options)
1726
+ .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
1727
+ .join('&')}`;
1728
+ const miniProgramId = options.miniProgramId?.trim();
1729
+ return {
1730
+ protocol_type: 'openWindow',
1731
+ full_screen: true,
1732
+ mini_program: '1',
1733
+ ...(miniProgramId ? { mini_program_id: miniProgramId } : {}),
1734
+ navigation_bar: { title: '' },
1735
+ webview: { url: devShellUrl, pull: false, refresh: false },
1736
+ };
1737
+ }
1738
+ function readDevShellQueryEntries(appUrl, options) {
1739
+ const entries = [[MINI_PROGRAM_URL_QUERY_PARAM$1, appUrl]];
1740
+ const miniProgramId = options.miniProgramId?.trim();
1741
+ if (miniProgramId)
1742
+ entries.push(['mini_program_id', miniProgramId]);
1743
+ const localDevLaunchToken = options.localDevLaunchToken?.trim();
1744
+ if (localDevLaunchToken)
1745
+ entries.push([MINI_PROGRAM_LOCAL_DEV_LAUNCH_TOKEN_QUERY_PARAM, localDevLaunchToken]);
1746
+ const devContextUrl = readDevContextUrl(options.devContextUrl);
1747
+ if (devContextUrl)
1748
+ entries.push([MINI_PROGRAM_DEV_CONTEXT_QUERY_PARAM, devContextUrl]);
1749
+ const sdkVersion = options.sdkVersion?.trim();
1750
+ if (sdkVersion)
1751
+ entries.push([MINI_PROGRAM_SDK_VERSION_QUERY_PARAM, sdkVersion]);
1752
+ return entries;
1753
+ }
1754
+ function readDevContextUrl(value) {
1755
+ if (value === undefined || value === '')
1756
+ return undefined;
1757
+ return parseDevContextUrl(value, 'loopback-or-private', 'devContextUrl must be a canonical Dev Session URL').href;
1758
+ }
1759
+ function parseDevContextUrl(value, hostPolicy, errorMessage) {
1760
+ if (value !== value.trim())
1761
+ throw new TypeError(errorMessage);
1762
+ let url;
1763
+ try {
1764
+ url = new URL(value);
1765
+ }
1766
+ catch {
1767
+ throw new TypeError(errorMessage);
1768
+ }
1769
+ const tokenPath = `${MINI_PROGRAM_DEV_CONTEXT_PATH}/`;
1770
+ const hostAllowed = isLoopbackHostname(url.hostname) || (hostPolicy === 'loopback-or-private' && isCanonicalPrivateLanIpv4(url.hostname));
1771
+ if (url.protocol !== 'http:' ||
1772
+ url.username !== '' ||
1773
+ url.password !== '' ||
1774
+ url.search !== '' ||
1775
+ url.hash !== '' ||
1776
+ !url.pathname.startsWith(tokenPath) ||
1777
+ !/^[a-f0-9]{64}$/.test(url.pathname.slice(tokenPath.length)) ||
1778
+ !hostAllowed ||
1779
+ url.href !== value) {
1780
+ throw new TypeError(errorMessage);
1781
+ }
1782
+ return url;
1783
+ }
1784
+ function createHeyboxProtocol(payload) {
1785
+ return `heybox://${encodeURIComponent(JSON.stringify(payload))}`;
1786
+ }
1676
1787
  function escapeHtml(value) {
1677
1788
  return value.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;').replaceAll('"', '&quot;').replaceAll("'", '&#039;');
1678
1789
  }
@@ -1713,13 +1824,12 @@ function assertAddressId(addressId) {
1713
1824
  }
1714
1825
  }
1715
1826
 
1716
- const MINI_PROGRAM_URL_QUERY_PARAM$1 = 'mini_url';
1827
+ const MINI_PROGRAM_URL_QUERY_PARAM = 'mini_url';
1717
1828
  const BROWSER_DEV_HOST_BOOTSTRAP_PATH = '/__hb_sdk_bootstrap__';
1718
1829
  const BROWSER_DEV_HOST_CHANNEL_PATH = '/__hb_sdk__/channel';
1719
1830
  const BROWSER_DEV_HOST_NETWORK_PATH = '/__hb_sdk__/network';
1720
1831
  const MOBILE_LAUNCH_REDIRECT_CONTROL_PATH = '/__hb_sdk__/mobile-launch-redirect';
1721
1832
  const MOBILE_LAUNCH_REDIRECT_CONTROL_BODY_LIMIT_BYTES = 66 * 1024;
1722
- const DEV_PERMISSIONS_PATH = '/__hb_sdk__/dev-permissions';
1723
1833
  const DEV_LISTEN_HOST$1 = '::';
1724
1834
  const DEV_PORT_PROBE_HOST = '0.0.0.0';
1725
1835
  const LOCAL_DEV_URL_HOST$1 = '127.0.0.1';
@@ -1741,7 +1851,8 @@ const DEFAULT_CHANNEL_TRANSPORT = {
1741
1851
  };
1742
1852
  const IPV4_LOOPBACK_ADDRESSES = new net.BlockList();
1743
1853
  IPV4_LOOPBACK_ADDRESSES.addSubnet('127.0.0.0', 8, 'ipv4');
1744
- const { WebSocket, WebSocketServer } = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/dev-Dgt2zS9k.cjs', document.baseURI).href)))('ws');
1854
+ const { WebSocket, WebSocketServer } = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/dev-CwKbAm_H.cjs', document.baseURI).href)))('ws');
1855
+ const { parse: parseHtml } = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/dev-CwKbAm_H.cjs', document.baseURI).href)))('parse5');
1745
1856
  const BROWSER_DEV_HOST_ROOT_CANDIDATES = [
1746
1857
  path.resolve(__dirname, 'devtools/browser-dev-host'),
1747
1858
  path.resolve(__dirname, '../devtools/browser-dev-host'),
@@ -1771,7 +1882,6 @@ async function startBrowserDevHostServer(options) {
1771
1882
  devContext: options.devContext,
1772
1883
  lanAddresses: options.lanAddresses ?? [],
1773
1884
  loginAvailable: options.loginService !== undefined,
1774
- macAppProtocol: options.macAppProtocol,
1775
1885
  miniProgram: options.miniProgram,
1776
1886
  mobileLaunchRedirect: initialMobileLaunchRedirect,
1777
1887
  nativeAppLaunchUnavailableReason: options.nativeAppLaunchUnavailableReason,
@@ -1787,7 +1897,6 @@ async function startBrowserDevHostServer(options) {
1787
1897
  isMobileLaunchRedirectPeerAllowed: options.isMobileLaunchRedirectPeerAllowed ?? isAllowedMobileLaunchRedirectPeer,
1788
1898
  lookupHostname: options.lookupHostname ?? (async (hostname) => promises.lookup(hostname, { all: true, verbatim: true })),
1789
1899
  now: options.now ?? Date.now,
1790
- permissionController: options.permissionController,
1791
1900
  channelHeartbeatIntervalMs: options.channelHeartbeatIntervalMs ?? DEFAULT_CHANNEL_HEARTBEAT_INTERVAL_MS,
1792
1901
  channelHelloTimeoutMs: options.channelHelloTimeoutMs ?? DEFAULT_CHANNEL_HELLO_TIMEOUT_MS,
1793
1902
  channelOutboundBufferLimitBytes: options.channelOutboundBufferLimitBytes ?? DEFAULT_CHANNEL_OUTBOUND_BUFFER_LIMIT_BYTES,
@@ -1855,10 +1964,6 @@ async function startBrowserDevHostServer(options) {
1855
1964
  delete bootstrap.mobileLaunchRedirect;
1856
1965
  }
1857
1966
  }
1858
- if (next.macAppProtocol === null)
1859
- delete bootstrap.macAppProtocol;
1860
- else if (next.macAppProtocol !== undefined)
1861
- bootstrap.macAppProtocol = next.macAppProtocol;
1862
1967
  if (next.miniProgram !== undefined)
1863
1968
  bootstrap.miniProgram = next.miniProgram;
1864
1969
  bootstrapJson = serializeBrowserDevHostBootstrap(bootstrap);
@@ -1891,7 +1996,36 @@ function assertCompleteMiniProgramBrowserDevHostRoot(root) {
1891
1996
  }
1892
1997
  }
1893
1998
  function isCompleteMiniProgramBrowserDevHostRoot(root) {
1894
- return fs.existsSync(path.join(root, 'index.html')) && fs.existsSync(path.join(root, 'main.js'));
1999
+ const entryPath = path.join(root, 'index.html');
2000
+ if (!fs.existsSync(entryPath))
2001
+ return false;
2002
+ // 测试夹具与旧发布产物仍使用固定入口;Vue 3 构建使用 HTML 中的哈希资源。
2003
+ if (fs.statSync(path.join(root, 'main.js'), { throwIfNoEntry: false })?.isFile())
2004
+ return true;
2005
+ try {
2006
+ const references = collectBrowserDevHostLocalReferences(parseHtml(fs.readFileSync(entryPath, 'utf8')));
2007
+ return (references.some((reference) => /\.m?js(?:$|\?)/.test(reference)) &&
2008
+ references.every((reference) => {
2009
+ const pathname = decodeURIComponent(reference.split(/[?#]/, 1)[0]);
2010
+ const resolved = path.resolve(root, pathname.replace(/^\/+/, ''));
2011
+ return resolved.startsWith(`${root}${path.sep}`) && fs.statSync(resolved, { throwIfNoEntry: false })?.isFile() === true;
2012
+ }));
2013
+ }
2014
+ catch {
2015
+ return false;
2016
+ }
2017
+ }
2018
+ function collectBrowserDevHostLocalReferences(node, references = []) {
2019
+ for (const attribute of node.attrs ?? []) {
2020
+ if (!['href', 'src'].includes(attribute.name))
2021
+ continue;
2022
+ if (attribute.value && !/^(?:[a-z][a-z\d+.-]*:|\/\/|#)/i.test(attribute.value))
2023
+ references.push(attribute.value);
2024
+ }
2025
+ for (const child of node.childNodes ?? []) {
2026
+ collectBrowserDevHostLocalReferences(child, references);
2027
+ }
2028
+ return [...new Set(references)];
1895
2029
  }
1896
2030
  function createMissingBrowserDevHostError() {
1897
2031
  return new Error('未找到完整的 hb-sdk browser dev host 静态产物。请先执行 @heybox/hb-sdk 的 build:browser-dev-host。');
@@ -1905,7 +2039,7 @@ function createBrowserDevHostNetworkUrls(options) {
1905
2039
  }
1906
2040
  function createBrowserDevHostUrlWithHost(options) {
1907
2041
  const url = new URL(`http://${options.host}:${options.port}/`);
1908
- url.searchParams.set(MINI_PROGRAM_URL_QUERY_PARAM$1, options.appUrl);
2042
+ url.searchParams.set(MINI_PROGRAM_URL_QUERY_PARAM, options.appUrl);
1909
2043
  return url.toString();
1910
2044
  }
1911
2045
  function serializeBrowserDevHostBootstrap(bootstrap) {
@@ -2015,10 +2149,10 @@ function createBrowserDevHostServer(root, runtime) {
2015
2149
  writeForbidden(response);
2016
2150
  return;
2017
2151
  }
2018
- if (isBrowserDevHostDocumentPath(pathname) && !requestUrl.searchParams.has(MINI_PROGRAM_URL_QUERY_PARAM$1)) {
2152
+ if (isBrowserDevHostDocumentPath(pathname) && !requestUrl.searchParams.has(MINI_PROGRAM_URL_QUERY_PARAM)) {
2019
2153
  const targetUrl = new URL(requestUrl);
2020
2154
  targetUrl.pathname = '/';
2021
- targetUrl.searchParams.set(MINI_PROGRAM_URL_QUERY_PARAM$1, runtime.appUrl);
2155
+ targetUrl.searchParams.set(MINI_PROGRAM_URL_QUERY_PARAM, runtime.appUrl);
2022
2156
  response.writeHead(302, {
2023
2157
  location: `${targetUrl.pathname}${targetUrl.search}`,
2024
2158
  'cache-control': 'no-store',
@@ -2129,28 +2263,6 @@ function createBrowserDevHostServer(root, runtime) {
2129
2263
  request.once('close', () => eventStreams.delete(response));
2130
2264
  return;
2131
2265
  }
2132
- if (pathname === DEV_PERMISSIONS_PATH && runtime.permissionController) {
2133
- if (!loopbackPeer || !hasNumericLoopbackHost(request)) {
2134
- writeForbidden(response);
2135
- return;
2136
- }
2137
- if (request.method === 'GET') {
2138
- writeJsonResponse(response, 200, await runtime.permissionController.get());
2139
- return;
2140
- }
2141
- if (request.method !== 'PUT' && request.method !== 'DELETE') {
2142
- writeMethodNotAllowed(response, 'GET, PUT, DELETE');
2143
- return;
2144
- }
2145
- if (!isValidSensitiveRequest(request, loopbackPeer, runtime.sessionController.csrfToken)) {
2146
- writeForbidden(response);
2147
- return;
2148
- }
2149
- if (await handleDevPermissionMutation(request, response, runtime.permissionController)) {
2150
- channelServer.publish('status.changed');
2151
- }
2152
- return;
2153
- }
2154
2266
  if (pathname === MINI_PROGRAM_DEV_CONTEXT_PATH) {
2155
2267
  if (request.method !== 'POST') {
2156
2268
  writeMethodNotAllowed(response, 'POST');
@@ -2531,7 +2643,7 @@ function createBrowserDevHostChannelServer(server, options) {
2531
2643
  }
2532
2644
  async function readBrowserDevHostChannelSnapshot(runtime, cookieHeader) {
2533
2645
  const status = await readAccountStatus(runtime, cookieHeader);
2534
- const permissions = await readBrowserDevPermissionState(runtime.permissionController, runtime.readDevContext());
2646
+ const permissions = context.createBrowserDevPermissionState(runtime.readDevContext());
2535
2647
  return {
2536
2648
  account: {
2537
2649
  revision: status.revision,
@@ -2549,13 +2661,6 @@ async function readAccountStatus(runtime, cookieHeader) {
2549
2661
  ...(status.authenticated ? { userId: status.userId } : {}),
2550
2662
  };
2551
2663
  }
2552
- async function readBrowserDevPermissionState(controller, fallbackContext) {
2553
- if (!controller)
2554
- return context.createBrowserDevPermissionState(fallbackContext);
2555
- const configuration = await controller.get();
2556
- const runtimePermissions = configuration.override_permissions ?? configuration.remote_permissions;
2557
- return context.createBrowserDevPermissionState(runtimePermissions === undefined ? { source: configuration.source } : { runtimePermissions });
2558
- }
2559
2664
  function createConnectionEpoch(random) {
2560
2665
  const value = random(16).toString('base64url');
2561
2666
  if (!/^[A-Za-z0-9_-]{22}$/.test(value))
@@ -2607,7 +2712,7 @@ function rejectWebSocketUpgrade(socket) {
2607
2712
  async function handleLoginIntent(request, response, controller) {
2608
2713
  try {
2609
2714
  const payload = await readJsonRequestBody(request);
2610
- if (!isRecord$3(payload) || Object.keys(payload).some((key) => key !== 'return_path') || typeof payload.return_path !== 'string') {
2715
+ if (!isRecord$2(payload) || Object.keys(payload).some((key) => key !== 'return_path') || typeof payload.return_path !== 'string') {
2611
2716
  throw new BrowserDevSessionError(400, 'INVALID_LOGIN_INTENT', 'Browser Dev Host login intent is invalid');
2612
2717
  }
2613
2718
  const result = await controller.createLoginIntent({
@@ -2654,8 +2759,7 @@ async function handleLoginCallback(request, response, requestUrl, controller) {
2654
2759
  }
2655
2760
  }
2656
2761
  async function handleAuthenticatedRequest(request, response, runtime) {
2657
- const abort = new AbortController();
2658
- request.once('aborted', () => abort.abort());
2762
+ const abort = createBrowserDevHostRequestAbortScope(request, response);
2659
2763
  try {
2660
2764
  const payload = await readJsonRequestBody(request);
2661
2765
  const result = runtime.cliAuth
@@ -2666,6 +2770,9 @@ async function handleAuthenticatedRequest(request, response, runtime) {
2666
2770
  catch (error) {
2667
2771
  writeSessionError(response, error);
2668
2772
  }
2773
+ finally {
2774
+ abort.dispose();
2775
+ }
2669
2776
  }
2670
2777
  async function handleMobileLaunchRedirectRotation(request, response, rotate) {
2671
2778
  try {
@@ -2676,7 +2783,7 @@ async function handleMobileLaunchRedirectRotation(request, response, rotate) {
2676
2783
  destroyOnLimit: false,
2677
2784
  maxBytes: MOBILE_LAUNCH_REDIRECT_CONTROL_BODY_LIMIT_BYTES,
2678
2785
  });
2679
- if (!isRecord$3(value) ||
2786
+ if (!isRecord$2(value) ||
2680
2787
  Object.keys(value).length !== 3 ||
2681
2788
  typeof value.address_id !== 'string' ||
2682
2789
  typeof value.payload !== 'string' ||
@@ -2730,49 +2837,6 @@ function hasValidCsrf(request, csrfToken) {
2730
2837
  const value = request.headers['x-hb-sdk-csrf'];
2731
2838
  return typeof value === 'string' && value === csrfToken;
2732
2839
  }
2733
- async function handleDevPermissionMutation(request, response, controller) {
2734
- try {
2735
- if (request.method === 'DELETE') {
2736
- if (hasRequestBody(request)) {
2737
- if (!request.headers['content-type']?.toLowerCase().startsWith('application/json')) {
2738
- throw createBrowserDevHostError(400, 'INVALID_DEV_PERMISSIONS', 'Dev permissions body must be JSON');
2739
- }
2740
- const payload = await readJsonRequestBody(request);
2741
- if (!isRecord$3(payload) || Object.keys(payload).length > 0) {
2742
- throw createBrowserDevHostError(400, 'INVALID_DEV_PERMISSIONS', 'Dev permissions reset body is invalid');
2743
- }
2744
- }
2745
- writeJsonResponse(response, 200, await controller.reset());
2746
- return true;
2747
- }
2748
- if (!request.headers['content-type']?.toLowerCase().startsWith('application/json')) {
2749
- throw createBrowserDevHostError(400, 'INVALID_DEV_PERMISSIONS', 'Dev permissions body must be JSON');
2750
- }
2751
- const payload = await readJsonRequestBody(request);
2752
- if (!isRecord$3(payload) || Object.keys(payload).length !== 1 || !Object.hasOwn(payload, 'runtime_permissions')) {
2753
- throw createBrowserDevHostError(400, 'INVALID_DEV_PERMISSIONS', 'Dev permissions update body is invalid');
2754
- }
2755
- const parsed = context.parseMiniProgramRuntimePermissions(payload.runtime_permissions);
2756
- if (!parsed.valid) {
2757
- throw createBrowserDevHostError(400, 'INVALID_DEV_PERMISSIONS', 'runtime_permissions is invalid');
2758
- }
2759
- const runtimePermissions = JSON.parse(JSON.stringify(payload.runtime_permissions));
2760
- writeJsonResponse(response, 200, await controller.save(runtimePermissions));
2761
- return true;
2762
- }
2763
- catch (error) {
2764
- const errorStatus = readBrowserDevHostErrorStatus(error);
2765
- const status = request.method === 'DELETE' && errorStatus === 500 ? 502 : errorStatus;
2766
- writeJsonResponse(response, status, {
2767
- code: request.method === 'DELETE' ? 'DEV_PERMISSIONS_RESET_FAILED' : 'DEV_PERMISSIONS_UPDATE_FAILED',
2768
- message: readErrorMessage(error),
2769
- });
2770
- return false;
2771
- }
2772
- }
2773
- function hasRequestBody(request) {
2774
- return request.headers['transfer-encoding'] !== undefined || Number(request.headers['content-length'] ?? 0) > 0;
2775
- }
2776
2840
  function writeMethodNotAllowed(response, allowedMethod) {
2777
2841
  response.writeHead(405, {
2778
2842
  allow: allowedMethod,
@@ -4819,7 +4883,7 @@ const DEFAULT_RUNTIME_SANITIZE_MAX_STRING_LENGTH = 2000;
4819
4883
  *
4820
4884
  * @param value - 待判断的值。
4821
4885
  */
4822
- function isRecord$2(value) {
4886
+ function isRecord$1(value) {
4823
4887
  return Boolean(value && typeof value === 'object');
4824
4888
  }
4825
4889
  /**
@@ -4939,14 +5003,14 @@ function normalizeRuntimeError(error, options = {}) {
4939
5003
  if (error instanceof RuntimeError) {
4940
5004
  return error;
4941
5005
  }
4942
- if (isRecord$2(error)) {
5006
+ if (isRecord$1(error)) {
4943
5007
  const code = readString(error, 'code') ?? options.code ?? 'runtime.error.unknown';
4944
5008
  const message = readString(error, 'message') ?? options.message ?? 'Unknown runtime error';
4945
5009
  const domain = readString(error, 'domain') ?? options.domain ?? inferRuntimeErrorDomain(code);
4946
5010
  const severity = readString(error, 'severity') ?? options.severity;
4947
5011
  const details = sanitizeRuntimeRecord({
4948
5012
  ...options.details,
4949
- ...((isRecord$2(error.details) ? error.details : undefined) ?? {}),
5013
+ ...((isRecord$1(error.details) ? error.details : undefined) ?? {}),
4950
5014
  });
4951
5015
  return createRuntimeError({
4952
5016
  cause: error instanceof Error ? error.cause : error.cause,
@@ -5016,7 +5080,7 @@ function serializeRuntimeError(error, options = {}, depth = 0) {
5016
5080
  const normalized = normalizeRuntimeError(error);
5017
5081
  const maxCauseDepth = options.maxCauseDepth ?? 4;
5018
5082
  const cause = depth < maxCauseDepth
5019
- ? (normalized.cause ?? (isRecord$2(error) && 'cause' in error ? error.cause : undefined))
5083
+ ? (normalized.cause ?? (isRecord$1(error) && 'cause' in error ? error.cause : undefined))
5020
5084
  : undefined;
5021
5085
  const details = sanitizeRuntimeRecord(normalized.details, options);
5022
5086
  const serialized = {
@@ -5686,6 +5750,7 @@ function createEndpointObservationConfig(endpoint, options = {}) {
5686
5750
  errorMode: options.errorMode ?? endpoint.errorMode,
5687
5751
  failurePresentation: options.failurePresentation ?? endpoint.failurePresentation,
5688
5752
  jsonParseMode: options.jsonParseMode ?? endpoint.jsonParseMode,
5753
+ maxResponseBytes: options.maxResponseBytes ?? endpoint.maxResponseBytes,
5689
5754
  metadata: {
5690
5755
  ...options.metadata,
5691
5756
  endpointId: endpoint.id,
@@ -5693,10 +5758,12 @@ function createEndpointObservationConfig(endpoint, options = {}) {
5693
5758
  method: endpoint.method,
5694
5759
  observability: options.observability ?? endpoint.observability,
5695
5760
  queryEncoding: options.queryEncoding ?? endpoint.queryEncoding,
5761
+ redirectPolicy: options.redirectPolicy ?? endpoint.redirectPolicy,
5696
5762
  responseType: options.responseType ?? endpoint.responseType,
5697
5763
  security: options.security ?? endpoint.security,
5698
5764
  timeout: options.timeout ?? endpoint.timeout,
5699
5765
  url: typeof endpoint.path === 'string' ? endpoint.path : `endpoint:${endpoint.id}`,
5766
+ withCredentials: options.withCredentials ?? endpoint.withCredentials,
5700
5767
  };
5701
5768
  }
5702
5769
  /**
@@ -5783,13 +5850,16 @@ async function createEndpointConfig(endpoint, input, options = {}) {
5783
5850
  },
5784
5851
  method: endpoint.method,
5785
5852
  jsonParseMode: options.jsonParseMode ?? endpoint.jsonParseMode,
5853
+ maxResponseBytes: options.maxResponseBytes ?? endpoint.maxResponseBytes,
5786
5854
  observability: options.observability ?? endpoint.observability,
5787
5855
  query: mergeRecord(await endpoint.query?.(input), options.params, options.query),
5788
5856
  queryEncoding: options.queryEncoding ?? endpoint.queryEncoding,
5857
+ redirectPolicy: options.redirectPolicy ?? endpoint.redirectPolicy,
5789
5858
  responseType: options.responseType ?? endpoint.responseType,
5790
5859
  security: options.security ?? endpoint.security,
5791
5860
  timeout: options.timeout ?? endpoint.timeout,
5792
5861
  url: getEndpointPath(endpoint, input),
5862
+ withCredentials: options.withCredentials ?? endpoint.withCredentials,
5793
5863
  };
5794
5864
  }
5795
5865
  /**
@@ -5993,15 +6063,18 @@ function createRuntimeRequest(options) {
5993
6063
  channel: transportConfig.channel,
5994
6064
  headers: transportConfig.headers,
5995
6065
  jsonParseMode: transportConfig.jsonParseMode,
6066
+ maxResponseBytes: transportConfig.maxResponseBytes,
5996
6067
  metadata: transportConfig.metadata,
5997
6068
  method: transportConfig.method,
5998
6069
  query: transportConfig.query,
5999
6070
  queryEncoding: transportConfig.queryEncoding,
6071
+ redirectPolicy: transportConfig.redirectPolicy,
6000
6072
  responseType: transportConfig.responseType,
6001
6073
  signal: transportConfig.signal,
6002
6074
  timeout: transportConfig.timeout,
6003
6075
  traceId: transportConfig.traceId,
6004
6076
  url: transportConfig.url,
6077
+ withCredentials: transportConfig.withCredentials,
6005
6078
  });
6006
6079
  return {
6007
6080
  fallbackUsed: transportIndex > 0,
@@ -7867,7 +7940,7 @@ const DEFAULT_NODE_RUNTIME_CONFIG_VALUE_PREFIX = 'RUNTIME_VALUE_';
7867
7940
  *
7868
7941
  * @param value - 待判断的值。
7869
7942
  */
7870
- function isRecord$1(value) {
7943
+ function isRecord(value) {
7871
7944
  return Boolean(value && typeof value === 'object' && !Array.isArray(value));
7872
7945
  }
7873
7946
  /**
@@ -7987,7 +8060,7 @@ function parseEnvValue(value) {
7987
8060
  * @param value - 原始值。
7988
8061
  */
7989
8062
  function normalizeFlags(value) {
7990
- if (!isRecord$1(value)) {
8063
+ if (!isRecord(value)) {
7991
8064
  return undefined;
7992
8065
  }
7993
8066
  const flags = {};
@@ -8004,11 +8077,11 @@ function normalizeFlags(value) {
8004
8077
  * @param value - 原始值。
8005
8078
  */
8006
8079
  function normalizeConfigInput(value) {
8007
- if (!isRecord$1(value)) {
8080
+ if (!isRecord(value)) {
8008
8081
  return undefined;
8009
8082
  }
8010
8083
  const input = {};
8011
- if (isRecord$1(value.build)) {
8084
+ if (isRecord(value.build)) {
8012
8085
  input.build = value.build;
8013
8086
  }
8014
8087
  if (typeof value.channel === 'string') {
@@ -8017,16 +8090,16 @@ function normalizeConfigInput(value) {
8017
8090
  if (typeof value.env === 'string') {
8018
8091
  input.env = value.env;
8019
8092
  }
8020
- if (isRecord$1(value.flags)) {
8093
+ if (isRecord(value.flags)) {
8021
8094
  input.flags = normalizeFlags(value.flags);
8022
8095
  }
8023
8096
  if (typeof value.isProd === 'boolean') {
8024
8097
  input.isProd = value.isProd;
8025
8098
  }
8026
- if (isRecord$1(value.tenant)) {
8099
+ if (isRecord(value.tenant)) {
8027
8100
  input.tenant = value.tenant;
8028
8101
  }
8029
- if (isRecord$1(value.values)) {
8102
+ if (isRecord(value.values)) {
8030
8103
  input.values = value.values;
8031
8104
  }
8032
8105
  return hasConfigInput(input) ? input : undefined;
@@ -8570,23 +8643,47 @@ function createFetchRequestControl(signal, timeout) {
8570
8643
  * @param response - transport 响应对象。
8571
8644
  * @param responseType - responseType 参数。
8572
8645
  */
8573
- async function parseFetchResponse(response, responseType, jsonParseMode) {
8646
+ async function parseFetchResponse(response, responseType, jsonParseMode, maxResponseBytes) {
8647
+ const limit = normalizeMaxResponseBytes(maxResponseBytes);
8574
8648
  if (responseType === 'raw') {
8649
+ if (limit !== undefined) {
8650
+ throw createRuntimeError({
8651
+ code: 'runtime.transport.raw_response_limit_unsupported',
8652
+ domain: 'transport',
8653
+ message: 'Raw fetch response cannot enforce maxResponseBytes',
8654
+ recoverable: false,
8655
+ severity: 'error',
8656
+ });
8657
+ }
8575
8658
  return response;
8576
8659
  }
8577
8660
  if (response.status === 204) {
8578
8661
  return undefined;
8579
8662
  }
8580
- if (responseType === 'text') {
8663
+ if (limit === undefined && responseType === 'text') {
8581
8664
  return response.text();
8582
8665
  }
8583
- if (responseType === 'blob') {
8666
+ if (limit === undefined && responseType === 'blob') {
8584
8667
  return response.blob();
8585
8668
  }
8586
- if (responseType === 'arrayBuffer') {
8669
+ if (limit === undefined && responseType === 'arrayBuffer') {
8587
8670
  return response.arrayBuffer();
8588
8671
  }
8589
- const text = await response.text();
8672
+ if (limit === undefined) {
8673
+ return parseFetchText(await response.text(), responseType, jsonParseMode);
8674
+ }
8675
+ const bytes = await readBoundedResponse(response, limit);
8676
+ if (responseType === 'arrayBuffer')
8677
+ return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
8678
+ if (responseType === 'blob') {
8679
+ const blobBytes = bytes.slice().buffer;
8680
+ return new Blob([blobBytes], { type: response.headers.get('content-type') ?? '' });
8681
+ }
8682
+ return parseFetchText(new TextDecoder().decode(bytes), responseType, jsonParseMode);
8683
+ }
8684
+ function parseFetchText(text, responseType, jsonParseMode) {
8685
+ if (responseType === 'text')
8686
+ return text;
8590
8687
  if (!text) {
8591
8688
  return undefined;
8592
8689
  }
@@ -8600,6 +8697,62 @@ async function parseFetchResponse(response, responseType, jsonParseMode) {
8600
8697
  throw error;
8601
8698
  }
8602
8699
  }
8700
+ function normalizeMaxResponseBytes(value) {
8701
+ if (value === undefined)
8702
+ return undefined;
8703
+ if (!Number.isSafeInteger(value) || value <= 0)
8704
+ throw new TypeError('maxResponseBytes must be a positive safe integer');
8705
+ return value;
8706
+ }
8707
+ function responseTooLarge(maxResponseBytes, receivedBytes) {
8708
+ return createRuntimeError({
8709
+ code: 'runtime.transport.response_too_large',
8710
+ details: {
8711
+ maxResponseBytes,
8712
+ ...(receivedBytes === undefined ? {} : { receivedBytes }),
8713
+ },
8714
+ domain: 'transport',
8715
+ message: `Fetch response exceeds ${maxResponseBytes} bytes`,
8716
+ recoverable: false,
8717
+ severity: 'error',
8718
+ });
8719
+ }
8720
+ async function readBoundedResponse(response, maxResponseBytes) {
8721
+ const declared = response.headers.get('content-length');
8722
+ if (declared && /^(?:0|[1-9]\d*)$/.test(declared)) {
8723
+ const declaredBytes = Number(declared);
8724
+ if (Number.isSafeInteger(declaredBytes) && declaredBytes > maxResponseBytes)
8725
+ throw responseTooLarge(maxResponseBytes, declaredBytes);
8726
+ }
8727
+ const reader = response.body?.getReader();
8728
+ if (!reader)
8729
+ return new Uint8Array();
8730
+ const chunks = [];
8731
+ let receivedBytes = 0;
8732
+ try {
8733
+ while (true) {
8734
+ const next = await reader.read();
8735
+ if (next.done)
8736
+ break;
8737
+ receivedBytes += next.value.byteLength;
8738
+ if (receivedBytes > maxResponseBytes) {
8739
+ await reader.cancel().catch(() => undefined);
8740
+ throw responseTooLarge(maxResponseBytes, receivedBytes);
8741
+ }
8742
+ chunks.push(next.value);
8743
+ }
8744
+ }
8745
+ finally {
8746
+ reader.releaseLock();
8747
+ }
8748
+ const result = new Uint8Array(receivedBytes);
8749
+ let offset = 0;
8750
+ for (const chunk of chunks) {
8751
+ result.set(chunk, offset);
8752
+ offset += chunk.byteLength;
8753
+ }
8754
+ return result;
8755
+ }
8603
8756
  /**
8604
8757
  * 创建基于 fetch 的 runtime transport。
8605
8758
  *
@@ -8638,13 +8791,14 @@ function createFetchRuntimeTransport(options = {}) {
8638
8791
  try {
8639
8792
  const response = await requestControl.wait(fetcher(url, {
8640
8793
  body: createRequestBody(request.body, headers, request.bodyEncoding),
8641
- credentials: options.credentials,
8794
+ credentials: request.withCredentials === undefined ? options.credentials : request.withCredentials ? 'include' : 'omit',
8642
8795
  headers,
8643
8796
  method: request.method ?? 'GET',
8797
+ ...(request.redirectPolicy === undefined ? {} : { redirect: request.redirectPolicy }),
8644
8798
  ...(requestControl.signal ? { signal: requestControl.signal } : undefined),
8645
8799
  }));
8646
8800
  return {
8647
- data: await parseFetchResponse(response, request.responseType ?? 'json', request.jsonParseMode ?? 'strict'),
8801
+ data: await parseFetchResponse(response, request.responseType ?? 'json', request.jsonParseMode ?? 'strict', request.maxResponseBytes),
8648
8802
  headers: Object.fromEntries(response.headers.entries()),
8649
8803
  raw: response,
8650
8804
  request: {
@@ -10741,7 +10895,7 @@ function assertNodeRuntimeCapabilities(ctx, settings) {
10741
10895
  function createNodeRealtimeDriverRegistry() {
10742
10896
  const registry = createRuntimeRealtimeDriverRegistry();
10743
10897
  registry.registerLazy('node-websocket', async () => {
10744
- const mod = await Promise.resolve().then(function () { return require('./index.esm-CigcxJ2B.cjs'); });
10898
+ const mod = await Promise.resolve().then(function () { return require('./index.esm-B-4yrLNm.cjs'); });
10745
10899
  return mod.createNodeWebSocketRuntimeDriver();
10746
10900
  });
10747
10901
  return registry;
@@ -14527,6 +14681,7 @@ const websitePolicy = {
14527
14681
  const CREDENTIAL_HEADER_RE = /^(?:authentication-info|authorization|cookie|cookie2|proxy-authenticate|proxy-authentication-info|proxy-authorization|set-cookie|set-cookie2|www-authenticate|pkey|x-pkey|x-access-token|x-auth-token|x-api-key)$/i;
14528
14682
  function createBrowserDevHostCliAuth(options = {}) {
14529
14683
  const fetchImpl = options.fetchImpl ?? fetch;
14684
+ const noRedirectFetch = (input, init) => fetchImpl(input, { ...init, redirect: 'manual' });
14530
14685
  const store = options.store ?? { env: options.env };
14531
14686
  const readSession = options.readSession ?? (() => session.readHeyboxAuthSession(store));
14532
14687
  let lastKey = '';
@@ -14538,7 +14693,7 @@ function createBrowserDevHostCliAuth(options = {}) {
14538
14693
  runtimePromise ??= createNodeProcessRuntime({
14539
14694
  appId: 'hb-sdk-browser-dev-host',
14540
14695
  environment: createNodeProcessRuntimeEnvironment({
14541
- transport: createFetchRuntimeTransport({ fetch: fetchImpl }),
14696
+ transport: createFetchRuntimeTransport({ fetch: noRedirectFetch }),
14542
14697
  }),
14543
14698
  identity: {
14544
14699
  container: 'browser',
@@ -14609,10 +14764,10 @@ async function readCliUserProfile(runtime, session) {
14609
14764
  }
14610
14765
  }
14611
14766
  function readCliUserProfileFields(value) {
14612
- if (!isRecord$3(value))
14767
+ if (!isRecord$2(value))
14613
14768
  return undefined;
14614
- const data = isRecord$3(value.data) ? value.data : value;
14615
- const result = isRecord$3(data.result) ? data.result : data;
14769
+ const data = isRecord$2(value.data) ? value.data : value;
14770
+ const result = isRecord$2(data.result) ? data.result : data;
14616
14771
  const nickname = typeof result.display_username === 'string' ? result.display_username.trim() : '';
14617
14772
  const avatar = typeof result.display_avatar === 'string' ? result.display_avatar.trim() : '';
14618
14773
  if (!nickname && !avatar)
@@ -14673,7 +14828,7 @@ async function executeCliHeyboxAuthenticatedRequest(runtime, session, request, s
14673
14828
  }
14674
14829
  function readQueryParams(params) {
14675
14830
  const query = {};
14676
- if (!isRecord$3(params))
14831
+ if (!isRecord$2(params))
14677
14832
  return query;
14678
14833
  for (const [key, value] of Object.entries(params)) {
14679
14834
  if (value === undefined || value === null || key === 'heybox_id')
@@ -14698,111 +14853,6 @@ function containsSecret(value, secret) {
14698
14853
  }
14699
14854
  }
14700
14855
 
14701
- const MINI_PROGRAM_URL_QUERY_PARAM = 'mini_url';
14702
- const MINI_PROGRAM_SDK_VERSION_QUERY_PARAM = 'sdk_version';
14703
- const MINI_PROGRAM_LOCAL_DEV_LAUNCH_TOKEN_QUERY_PARAM = 'local_dev_launch_token';
14704
- const MINI_PROGRAM_DEV_SHELL_URL = 'heybox-mini-dev://sandbox';
14705
- const OPEN_IN_APP_URL = 'https://api.xiaoheihe.cn/open_inapp/';
14706
- function createMacAppProtocol(appUrl, options = {}) {
14707
- return createHeyboxProtocol(createMiniProgramDevShellOpenWindowPayload(appUrl, options));
14708
- }
14709
- function createMobileAppQrPayload(appUrl, options = {}) {
14710
- const protocol = createHeyboxProtocol(createMiniProgramDevShellOpenWindowPayload(appUrl, { ...options, encodeMiniUrl: false }));
14711
- return `${OPEN_IN_APP_URL}#${protocol}`;
14712
- }
14713
- function createMiniProgramDevShellOpenWindowPayload(appUrl, options = {}) {
14714
- const devShellUrl = options.encodeMiniUrl === false
14715
- ? createPartiallyEncodedMiniProgramDevShellUrl(appUrl, options)
14716
- : createEncodedMiniProgramDevShellUrl(appUrl, options);
14717
- return createOpenWindowPayload(devShellUrl, options.miniProgramId);
14718
- }
14719
- function createOpenWindowPayload(webviewUrl, miniProgramIdValue) {
14720
- const miniProgramId = miniProgramIdValue?.trim();
14721
- return {
14722
- protocol_type: 'openWindow',
14723
- full_screen: true,
14724
- mini_program: '1',
14725
- ...(miniProgramId ? { mini_program_id: miniProgramId } : {}),
14726
- navigation_bar: {
14727
- title: '',
14728
- },
14729
- webview: {
14730
- url: webviewUrl,
14731
- pull: false,
14732
- refresh: false,
14733
- },
14734
- };
14735
- }
14736
- function readDevShellQueryEntries(appUrl, options) {
14737
- const entries = [[MINI_PROGRAM_URL_QUERY_PARAM, appUrl]];
14738
- const miniProgramId = options.miniProgramId?.trim();
14739
- if (miniProgramId)
14740
- entries.push(['mini_program_id', miniProgramId]);
14741
- const localDevLaunchToken = options.localDevLaunchToken?.trim();
14742
- if (localDevLaunchToken)
14743
- entries.push([MINI_PROGRAM_LOCAL_DEV_LAUNCH_TOKEN_QUERY_PARAM, localDevLaunchToken]);
14744
- const devContextUrl = readDevContextUrl(options.devContextUrl);
14745
- if (devContextUrl)
14746
- entries.push([MINI_PROGRAM_DEV_CONTEXT_QUERY_PARAM, devContextUrl]);
14747
- const sdkVersion = options.sdkVersion?.trim();
14748
- if (sdkVersion)
14749
- entries.push([MINI_PROGRAM_SDK_VERSION_QUERY_PARAM, sdkVersion]);
14750
- return entries;
14751
- }
14752
- function createPartiallyEncodedMiniProgramDevShellUrl(appUrl, options) {
14753
- return `${MINI_PROGRAM_DEV_SHELL_URL}?${readDevShellQueryEntries(appUrl, options)
14754
- .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
14755
- .join('&')}`;
14756
- }
14757
- function createEncodedMiniProgramDevShellUrl(appUrl, options) {
14758
- const devShellUrl = new URL(MINI_PROGRAM_DEV_SHELL_URL);
14759
- for (const [key, value] of readDevShellQueryEntries(appUrl, options)) {
14760
- devShellUrl.searchParams.set(key, value);
14761
- }
14762
- return devShellUrl.toString();
14763
- }
14764
- function readDevContextUrl(value) {
14765
- if (value === undefined || value === '')
14766
- return undefined;
14767
- return parseDevContextUrl(value, 'loopback-or-private', 'devContextUrl must be a canonical Dev Session URL').href;
14768
- }
14769
- function projectMiniProgramDevContextUrlToPrivateHost(value, host) {
14770
- const url = parseDevContextUrl(value, 'loopback', 'devContextUrl must be a canonical loopback Dev Session URL');
14771
- if (!isCanonicalPrivateLanIpv4(host)) {
14772
- throw new TypeError('Mobile Dev Context host must be a canonical private IPv4 address');
14773
- }
14774
- url.hostname = host;
14775
- return url.href;
14776
- }
14777
- function parseDevContextUrl(value, hostPolicy, errorMessage) {
14778
- if (value !== value.trim())
14779
- throw new TypeError(errorMessage);
14780
- let url;
14781
- try {
14782
- url = new URL(value);
14783
- }
14784
- catch {
14785
- throw new TypeError(errorMessage);
14786
- }
14787
- const tokenPath = `${MINI_PROGRAM_DEV_CONTEXT_PATH}/`;
14788
- const hostAllowed = isLoopbackHostname(url.hostname) || (hostPolicy === 'loopback-or-private' && isCanonicalPrivateLanIpv4(url.hostname));
14789
- if (url.protocol !== 'http:' ||
14790
- url.username !== '' ||
14791
- url.password !== '' ||
14792
- url.search !== '' ||
14793
- url.hash !== '' ||
14794
- !url.pathname.startsWith(tokenPath) ||
14795
- !/^[a-f0-9]{64}$/.test(url.pathname.slice(tokenPath.length)) ||
14796
- !hostAllowed ||
14797
- url.href !== value) {
14798
- throw new TypeError(errorMessage);
14799
- }
14800
- return url;
14801
- }
14802
- function createHeyboxProtocol(payload) {
14803
- return `heybox://${encodeURIComponent(JSON.stringify(payload))}`;
14804
- }
14805
-
14806
14856
  const LAUNCH_CORS_HEADERS = {
14807
14857
  'access-control-allow-methods': 'GET',
14808
14858
  'access-control-allow-origin': '*',
@@ -14905,127 +14955,6 @@ function writeLaunchResponse(response, status, body) {
14905
14955
  response.end(body ?? '');
14906
14956
  }
14907
14957
 
14908
- /** 构建时替换为当前发布包的实际版本。 */
14909
- const HB_SDK_VERSION = typeof undefined === 'string'
14910
- ? undefined
14911
- : '0.8.0-alpha';
14912
-
14913
- class DevPermissionOverrideStoreError extends Error {
14914
- code;
14915
- constructor(message, code, options = {}) {
14916
- super(message, { cause: options.cause });
14917
- this.code = code;
14918
- this.name = 'DevPermissionOverrideStoreError';
14919
- }
14920
- }
14921
- const CACHE_VERSION = 1;
14922
- const CACHE_DIRECTORY_NAME = 'dev-permission-overrides';
14923
- const defaultPaths = index.envPaths('hb-sdk', { suffix: '' });
14924
- function createDevPermissionOverrideStore(options = {}) {
14925
- const cacheDirectory = path.join(options.cacheRoot ?? defaultPaths.cache, CACHE_DIRECTORY_NAME);
14926
- return {
14927
- async read(scope) {
14928
- return readScopeFile(await getScopeFile(cacheDirectory, scope));
14929
- },
14930
- async remove(scope) {
14931
- const scopeFile = await getScopeFile(cacheDirectory, scope);
14932
- try {
14933
- await fs$1.unlink(scopeFile);
14934
- }
14935
- catch (error) {
14936
- if (isNodeError(error) && error.code === 'ENOENT') {
14937
- return;
14938
- }
14939
- throw createWriteError(error);
14940
- }
14941
- },
14942
- async set(scope, overrides) {
14943
- const scopeFile = await getScopeFile(cacheDirectory, scope);
14944
- try {
14945
- await fs$1.mkdir(cacheDirectory, { recursive: true, mode: 0o700 });
14946
- await fs$1.chmod(cacheDirectory, 0o700);
14947
- await readScopeFile(scopeFile);
14948
- await writeScopeFileAtomically(scopeFile, {
14949
- version: CACHE_VERSION,
14950
- overrides: cloneOverrides(overrides),
14951
- });
14952
- }
14953
- catch (error) {
14954
- if (error instanceof DevPermissionOverrideStoreError) {
14955
- throw error;
14956
- }
14957
- throw createWriteError(error);
14958
- }
14959
- },
14960
- };
14961
- }
14962
- async function getScopeFile(cacheDirectory, scope) {
14963
- const projectRoot = await fs$1.realpath(scope.projectRoot);
14964
- const miniProgramId = scope.miniProgramId ?? 'anonymous';
14965
- const scopeHash = node_crypto.createHash('sha256').update(`${projectRoot}\0${miniProgramId}`).digest('hex');
14966
- return path.join(cacheDirectory, `${scopeHash}.json`);
14967
- }
14968
- async function readScopeFile(scopeFile) {
14969
- let contents;
14970
- try {
14971
- contents = await fs$1.readFile(scopeFile, 'utf8');
14972
- }
14973
- catch (error) {
14974
- if (isNodeError(error) && error.code === 'ENOENT') {
14975
- return undefined;
14976
- }
14977
- throw error;
14978
- }
14979
- try {
14980
- const parsed = JSON.parse(contents);
14981
- const overrides = parsePersistedOverride(parsed);
14982
- if (!overrides) {
14983
- throw new TypeError('invalid cache schema');
14984
- }
14985
- return overrides;
14986
- }
14987
- catch (error) {
14988
- throw new DevPermissionOverrideStoreError('hb-sdk 本地权限覆盖缓存已损坏', 'DEV_PERMISSION_OVERRIDE_CACHE_CORRUPT', {
14989
- cause: error,
14990
- });
14991
- }
14992
- }
14993
- async function writeScopeFileAtomically(scopeFile, value) {
14994
- const tempFile = `${scopeFile}.${process.pid}.${node_crypto.randomBytes(8).toString('hex')}.tmp`;
14995
- let handle;
14996
- try {
14997
- handle = await fs$1.open(tempFile, 'wx', 0o600);
14998
- await handle.writeFile(`${JSON.stringify(value, null, 2)}\n`, 'utf8');
14999
- await handle.sync();
15000
- await handle.close();
15001
- handle = undefined;
15002
- await fs$1.rename(tempFile, scopeFile);
15003
- }
15004
- finally {
15005
- await handle?.close().catch(() => undefined);
15006
- await fs$1.unlink(tempFile).catch(() => undefined);
15007
- }
15008
- }
15009
- function createWriteError(cause) {
15010
- return new DevPermissionOverrideStoreError('无法写入 hb-sdk 本地权限覆盖缓存', 'DEV_PERMISSION_OVERRIDE_WRITE_FAILED', { cause });
15011
- }
15012
- function cloneOverrides(overrides) {
15013
- return {
15014
- networkRequest: { ...overrides.networkRequest },
15015
- };
15016
- }
15017
- function parsePersistedOverride(value) {
15018
- if (!isRecord(value) || value.version !== CACHE_VERSION || Object.keys(value).length !== 2)
15019
- return undefined;
15020
- return context.parseBrowserDevPermissionState(value.overrides);
15021
- }
15022
- function isRecord(value) {
15023
- return typeof value === 'object' && value !== null && !Array.isArray(value);
15024
- }
15025
- function isNodeError(error) {
15026
- return error instanceof Error && 'code' in error;
15027
- }
15028
-
15029
14958
  const DEFAULT_APP_PORT = 5173;
15030
14959
  const DEFAULT_BROWSER_DEV_HOST_PORT = 5174;
15031
14960
  const DEFAULT_DEV_CONTEXT_TIMEOUT_MS = 3000;
@@ -15062,44 +14991,7 @@ async function runDevCommand(options, runtime = {}) {
15062
14991
  projectRoot,
15063
14992
  timeoutMs: runtime.devContextTimeoutMs ?? DEFAULT_DEV_CONTEXT_TIMEOUT_MS,
15064
14993
  });
15065
- const innerPermissionController = createDevPermissionController({
15066
- boundMiniProgramId: await context.readBoundMiniProgramId(projectRoot),
15067
- cacheRoot: runtime.devPermissionCacheRoot,
15068
- devContext: devLaunchContext,
15069
- loadRemoteContext: async () => (await loadDevLaunchContext({
15070
- env: runtime.env,
15071
- fetchImpl,
15072
- logger,
15073
- projectRoot,
15074
- timeoutMs: runtime.devContextTimeoutMs ?? DEFAULT_DEV_CONTEXT_TIMEOUT_MS,
15075
- })).context,
15076
- projectRoot,
15077
- });
15078
- let launchRuntimePermissions = context.createBrowserDevRuntimePermissions(context.createBrowserDevPermissionState(devLaunchContext));
15079
- const rememberLaunchRuntimePermissions = (configuration) => {
15080
- const snapshot = configuration.override_permissions ?? configuration.remote_permissions;
15081
- launchRuntimePermissions = context.parseMiniProgramRuntimePermissions(snapshot).valid
15082
- ? JSON.parse(JSON.stringify(snapshot))
15083
- : context.createBrowserDevRuntimePermissions({ networkRequest: { status: 'disabled', useOfficialDomain: false } });
15084
- };
15085
- rememberLaunchRuntimePermissions(await innerPermissionController.get());
15086
- const permissionController = {
15087
- get: async () => {
15088
- const configuration = await innerPermissionController.get();
15089
- rememberLaunchRuntimePermissions(configuration);
15090
- return configuration;
15091
- },
15092
- reset: async () => {
15093
- const configuration = await innerPermissionController.reset();
15094
- rememberLaunchRuntimePermissions(configuration);
15095
- return configuration;
15096
- },
15097
- save: async (runtimePermissions) => {
15098
- const configuration = await innerPermissionController.save(runtimePermissions);
15099
- rememberLaunchRuntimePermissions(configuration);
15100
- return configuration;
15101
- },
15102
- };
14994
+ const launchRuntimePermissions = context.createBrowserDevRuntimePermissions(context.createBrowserDevPermissionState(devLaunchContext));
15103
14995
  const vite = await logger.task('正在加载项目 Vite', () => projectVite.loadProjectVite(projectRoot), { successText: '已加载项目 Vite' });
15104
14996
  const appServer = await logger.task('正在创建 Vite dev server', () => runtimePermissionEnv.withMiniappPlatformCspEnv(context.shouldSkipMiniappPlatformCsp(devLaunchContext.runtimePermissions), () => withManagedDevOutputEnv(() => vite.createServer(createViteServerOptions(projectRoot, resolvedOptions)), runtime.env), runtime.env), { successText: '已创建 Vite dev server' });
15105
14997
  const mobileDevContextUrlsByOrigin = new Map();
@@ -15110,7 +15002,7 @@ async function runDevCommand(options, runtime = {}) {
15110
15002
  localDevLaunchToken: currentLocalDevLaunchToken,
15111
15003
  miniProgramId: devLaunchContext.miniProgramId,
15112
15004
  runtimePermissions: launchRuntimePermissions,
15113
- sdkVersion: HB_SDK_VERSION,
15005
+ sdkVersion: version.HB_SDK_VERSION,
15114
15006
  }));
15115
15007
  if (!handled)
15116
15008
  next();
@@ -15128,7 +15020,7 @@ async function runDevCommand(options, runtime = {}) {
15128
15020
  interfaces: networkInterfaceSnapshot,
15129
15021
  localDevLaunchToken: currentLocalDevLaunchToken,
15130
15022
  miniProgramId: devLaunchContext.miniProgramId,
15131
- sdkVersion: HB_SDK_VERSION,
15023
+ sdkVersion: version.HB_SDK_VERSION,
15132
15024
  viteNetworkUrls: appServer.resolvedUrls?.network ?? [],
15133
15025
  });
15134
15026
  const lanAddresses = buildLanAddresses();
@@ -15146,18 +15038,12 @@ async function runDevCommand(options, runtime = {}) {
15146
15038
  loginService: runtime.loginService,
15147
15039
  miniProgram,
15148
15040
  cliAuth: runtime.cliAuth ?? createBrowserDevHostCliAuth({ env: runtime.env, fetchImpl }),
15149
- macAppProtocol: createMacAppProtocol(appUrl, {
15150
- miniProgramId: devLaunchContext.miniProgramId,
15151
- localDevLaunchToken: devLaunchContext.localDevLaunchToken,
15152
- sdkVersion: HB_SDK_VERSION,
15153
- }),
15154
15041
  onMobileDevSessionCreated: ({ devContextUrl, miniUrlOrigin }) => {
15155
15042
  mobileDevContextUrlsByOrigin.set(miniUrlOrigin, devContextUrl);
15156
15043
  browserDevHost.updateBootstrap({
15157
15044
  lanAddresses: buildLanAddresses(),
15158
15045
  });
15159
15046
  },
15160
- permissionController,
15161
15047
  port: options.browserDevHostPort ?? DEFAULT_BROWSER_DEV_HOST_PORT,
15162
15048
  root: runtime.browserDevHostRoot,
15163
15049
  rootCandidates: runtime.browserDevHostRootCandidates,
@@ -15186,11 +15072,6 @@ async function runDevCommand(options, runtime = {}) {
15186
15072
  browserDevHost.updateBootstrap({
15187
15073
  devContext: tokenContext,
15188
15074
  lanAddresses: buildLanAddresses(),
15189
- macAppProtocol: createMacAppProtocol(appUrl, {
15190
- miniProgramId: devLaunchContext.miniProgramId,
15191
- localDevLaunchToken,
15192
- sdkVersion: HB_SDK_VERSION,
15193
- }),
15194
15075
  });
15195
15076
  },
15196
15077
  projectRoot,
@@ -15250,72 +15131,6 @@ function createMiniProgramSummary(miniProgramId, detail) {
15250
15131
  ...(typeof detail.developer_name === 'string' && detail.developer_name.trim() ? { developerName: detail.developer_name.trim() } : {}),
15251
15132
  };
15252
15133
  }
15253
- function createDevPermissionController(options) {
15254
- const store = createDevPermissionOverrideStore({ cacheRoot: options.cacheRoot });
15255
- let devContext = options.devContext;
15256
- let ephemeralOverride;
15257
- let persistenceError;
15258
- const readScope = () => ({
15259
- projectRoot: options.projectRoot,
15260
- ...(options.boundMiniProgramId ? { miniProgramId: options.boundMiniProgramId } : {}),
15261
- });
15262
- const createConfiguration = (overrides, error = persistenceError) => {
15263
- const miniProgramId = options.boundMiniProgramId ?? devContext.miniProgramId;
15264
- return {
15265
- source: devContext.source,
15266
- ...(miniProgramId ? { mini_program_id: miniProgramId } : {}),
15267
- ...(isRuntimePermissionsSnapshot(devContext.runtimePermissions) ? { remote_permissions: devContext.runtimePermissions } : {}),
15268
- ...(overrides ? { override_permissions: context.createBrowserDevRuntimePermissions(overrides) } : {}),
15269
- ...(error ? { persistence_error: error } : {}),
15270
- };
15271
- };
15272
- const get = async () => {
15273
- try {
15274
- const persistedOverride = await store.read(readScope());
15275
- return createConfiguration(ephemeralOverride ?? persistedOverride);
15276
- }
15277
- catch (error) {
15278
- persistenceError = index.readErrorMessage(error);
15279
- return createConfiguration(ephemeralOverride, persistenceError);
15280
- }
15281
- };
15282
- return {
15283
- get,
15284
- async reset() {
15285
- let refreshedContext;
15286
- try {
15287
- refreshedContext = await options.loadRemoteContext();
15288
- }
15289
- catch (error) {
15290
- throw new Error('远端权限读取失败,请检查 CLI 登录状态和网络后重试。', { cause: error });
15291
- }
15292
- await store.remove(readScope());
15293
- devContext = refreshedContext;
15294
- ephemeralOverride = undefined;
15295
- persistenceError = undefined;
15296
- return createConfiguration(undefined);
15297
- },
15298
- async save(runtimePermissions) {
15299
- const overrides = context.createBrowserDevPermissionState({
15300
- runtimePermissions,
15301
- });
15302
- try {
15303
- await store.set(readScope(), overrides);
15304
- ephemeralOverride = undefined;
15305
- persistenceError = undefined;
15306
- return createConfiguration(overrides);
15307
- }
15308
- catch {
15309
- ephemeralOverride = overrides;
15310
- persistenceError = '保存失败,当前页面仍会应用该权限,但刷新或重启后会丢失。';
15311
- return createConfiguration(overrides, persistenceError);
15312
- }
15313
- },
15314
- };
15315
- }
15316
- function isRuntimePermissionsSnapshot(value) {
15317
- return context.parseMiniProgramRuntimePermissions(value).valid;
15318
- }
15319
15134
  async function loadRemoteDevContextWithTimeout(options) {
15320
15135
  const controller = new AbortController();
15321
15136
  const fetchImpl = ((input, init) => options.fetchImpl(input, { ...init, signal: controller.signal }));