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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/README.md +69 -16
  3. package/THIRD_PARTY_NOTICES.md +1755 -0
  4. package/dist/cli-chunks/{build-V1YBdpzY.cjs → build-CCLWgXyA.cjs} +6 -5
  5. package/dist/cli-chunks/{context-Ba1Je-wT.cjs → context-Brh56h56.cjs} +2 -27
  6. package/dist/cli-chunks/{create-CKGjqo9E.cjs → create-BZ-hi2s1.cjs} +1 -1
  7. package/dist/cli-chunks/{dev-XopYKLYZ.cjs → dev-CoSXtEYa.cjs} +336 -517
  8. package/dist/cli-chunks/{doctor-BHbrYQqT.cjs → doctor-EsCYJGhV.cjs} +1 -1
  9. package/dist/cli-chunks/{index-C9mpajVG.cjs → index-BL5eEPap.cjs} +14 -14
  10. package/dist/cli-chunks/{index-DKWfX6Ut.cjs → index-CS6Q0o5C.cjs} +2 -2
  11. package/dist/cli-chunks/{index.esm-SXAQ3WVR.cjs → index.esm-BoBHPfpq.cjs} +6 -6
  12. package/dist/cli-chunks/{login-BVWicWqe.cjs → login-CILLxGuf.cjs} +2 -2
  13. package/dist/cli-chunks/{project-vite-CBb38HJ3.cjs → project-vite-Qu6Xe9Dn.cjs} +1 -1
  14. package/dist/cli-chunks/{remote-BG1u0NKT.cjs → remote-DRuTQ51u.cjs} +10 -8
  15. package/dist/cli-chunks/{runtime-gate-CtV7rWyX.cjs → runtime-gate-DFjw66kF.cjs} +20 -1
  16. package/dist/cli-chunks/{runtime-permission-env-D-8_jPG3.cjs → runtime-permission-env-CjsCe5bp.cjs} +13 -13
  17. package/dist/cli-chunks/{session-CJS_SEp9.cjs → session-D-_N3WVL.cjs} +1 -1
  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 +1036 -90
  26. package/dist/index.esm.js +1036 -91
  27. package/dist/miniapp-publish.cjs.js +13 -13
  28. package/dist/miniapp-publish.esm.js +13 -13
  29. package/dist/protocol.cjs.js +208 -6
  30. package/dist/protocol.esm.js +182 -7
  31. package/dist/templates/vue3-vite-ts/README.md.ejs +2 -0
  32. package/dist/templates/vue3-vite-ts/vite.config.ts +1 -1
  33. package/dist/vite.cjs.js +31 -4
  34. package/dist/vite.esm.js +31 -5
  35. package/package.json +28 -11
  36. package/skill/SKILL.md +9 -5
  37. package/skill/references/api-protocol.md +111 -3
  38. package/skill/references/api-root.md +170 -22
  39. package/skill/references/cli.md +21 -17
  40. package/skill/references/examples.md +30 -1
  41. package/skill/references/recipes.md +105 -1
  42. package/skill/references/safety-boundaries.md +12 -1
  43. package/skill/scripts/sync-references.mjs +37 -3
  44. package/skill/skill.json +4 -4
  45. package/types/core/client.d.ts +17 -1
  46. package/types/core/errors.d.ts +5 -5
  47. package/types/core/sdk.d.ts +8 -5
  48. package/types/core/singleton.d.ts +59 -6
  49. package/types/index.d.ts +4 -2
  50. package/types/miniapp-manifest/schema.d.ts +5 -0
  51. package/types/miniapp-publish/index.d.ts +8 -8
  52. package/types/modules/auth/index.d.ts +15 -1
  53. package/types/modules/cloud/index.d.ts +75 -5
  54. package/types/modules/device/index.d.ts +31 -3
  55. package/types/modules/files/index.d.ts +5 -0
  56. package/types/modules/files/registry.d.ts +35 -0
  57. package/types/modules/files/types.d.ts +159 -0
  58. package/types/modules/navigation/index.d.ts +46 -4
  59. package/types/modules/network/index.d.ts +72 -14
  60. package/types/modules/share/copy-link.d.ts +3 -3
  61. package/types/modules/share/index.d.ts +61 -5
  62. package/types/modules/share/screenshot.d.ts +3 -3
  63. package/types/modules/share/show-share-menu.d.ts +3 -3
  64. package/types/modules/storage/index.d.ts +38 -10
  65. package/types/modules/ui/index.d.ts +46 -4
  66. package/types/modules/user/get-info.d.ts +1 -1
  67. package/types/modules/user/index.d.ts +46 -4
  68. package/types/modules/user/steam-game-list.d.ts +2 -2
  69. package/types/modules/viewport/index.d.ts +36 -8
  70. package/types/protocol/capabilities.d.ts +2 -2
  71. package/types/protocol/constants.d.ts +1 -1
  72. package/types/protocol/guards.d.ts +1 -1
  73. package/types/protocol/types.d.ts +1 -1
  74. package/types/protocol.d.ts +4 -3
  75. package/types/vite/index.d.ts +15 -7
  76. package/dist/devtools/browser-dev-host/main.js +0 -12158
@@ -8,16 +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-Ba1Je-wT.cjs');
11
+ var context = require('./context-Brh56h56.cjs');
12
12
  var undici = require('undici');
13
13
  var fs$1 = require('node:fs/promises');
14
- var index = require('./index-C9mpajVG.cjs');
14
+ var index = require('./index-BL5eEPap.cjs');
15
15
  var require$$0$1 = require('crypto');
16
16
  var require$$0 = require('buffer');
17
- var session = require('./session-CJS_SEp9.cjs');
17
+ var session = require('./session-D-_N3WVL.cjs');
18
18
  var browser = require('./browser-RAy8e8cV.cjs');
19
- var projectVite = require('./project-vite-CBb38HJ3.cjs');
20
- var runtimePermissionEnv = require('./runtime-permission-env-D-8_jPG3.cjs');
19
+ var projectVite = require('./project-vite-Qu6Xe9Dn.cjs');
20
+ var runtimePermissionEnv = require('./runtime-permission-env-CjsCe5bp.cjs');
21
21
 
22
22
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
23
23
  class Locked extends Error {
@@ -429,6 +429,25 @@ class BrowserDevHostHttpError extends Error {
429
429
  this.name = 'BrowserDevHostHttpError';
430
430
  }
431
431
  }
432
+ function createBrowserDevHostRequestAbortScope(request, response) {
433
+ const controller = new AbortController();
434
+ const abort = () => controller.abort();
435
+ const onResponseClose = () => {
436
+ if (!response.writableEnded)
437
+ abort();
438
+ };
439
+ request.once('aborted', abort);
440
+ response.once('close', onResponseClose);
441
+ if (request.aborted || (response.destroyed && !response.writableEnded))
442
+ abort();
443
+ return {
444
+ dispose() {
445
+ request.removeListener('aborted', abort);
446
+ response.removeListener('close', onResponseClose);
447
+ },
448
+ signal: controller.signal,
449
+ };
450
+ }
432
451
  function readJsonRequestBody(request, options = {}) {
433
452
  return new Promise((resolve, reject) => {
434
453
  const chunks = [];
@@ -498,7 +517,7 @@ function writeSerializedJsonResponse(response, status, body) {
498
517
  });
499
518
  response.end(body);
500
519
  }
501
- function isRecord$3(value) {
520
+ function isRecord$2(value) {
502
521
  return Object.prototype.toString.call(value) === '[object Object]';
503
522
  }
504
523
  function isObjectLike(value) {
@@ -594,7 +613,6 @@ function redactSensitivePairsInRawText(text) {
594
613
  });
595
614
  }
596
615
 
597
- const MAX_BROWSER_DEV_HOST_NETWORK_REDIRECTS = 5;
598
616
  const MAX_BROWSER_DEV_HOST_NETWORK_REQUEST_BODY = 2 * 1024 * 1024;
599
617
  const MAX_BROWSER_DEV_HOST_NETWORK_RESPONSE_BODY = 5 * 1024 * 1024;
600
618
  const DENIED_NETWORK_TARGETS = createDeniedNetworkTargets();
@@ -615,16 +633,17 @@ async function handleBrowserDevHostNetworkProxy(request, response, fetchImpl, lo
615
633
  let payload;
616
634
  try {
617
635
  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);
636
+ const requestAbort = createBrowserDevHostRequestAbortScope(request, response);
637
+ try {
638
+ const result = await requestBrowserDevHostNetwork(payload, fetchImpl, lookupHostname, options.allowedHttpOrigins, requestAbort.signal);
639
+ if (typeof result.status === 'number' && (result.status < 200 || result.status >= 300)) {
640
+ logBrowserDevHostNetworkProxyDiagnostic('http_status', payload, result);
641
+ }
642
+ writeNetworkJsonResponse(response, 200, result, cors);
643
+ }
644
+ finally {
645
+ requestAbort.dispose();
626
646
  }
627
- writeNetworkJsonResponse(response, 200, result, cors);
628
647
  }
629
648
  catch (error) {
630
649
  logBrowserDevHostNetworkProxyDiagnostic('proxy_error', payload, undefined, error);
@@ -639,10 +658,10 @@ function logBrowserDevHostNetworkProxyDiagnostic(phase, payload, result, error)
639
658
  return;
640
659
  }
641
660
  const detail = { phase };
642
- if (isRecord$3(payload) && typeof payload.url === 'string') {
661
+ if (isRecord$2(payload) && typeof payload.url === 'string') {
643
662
  detail.url = sanitizeNetworkRequestUrl(payload.url);
644
663
  }
645
- if (isRecord$3(payload) && typeof payload.method === 'string') {
664
+ if (isRecord$2(payload) && typeof payload.method === 'string') {
646
665
  detail.method = payload.method;
647
666
  }
648
667
  if (typeof result?.status === 'number') {
@@ -673,14 +692,14 @@ function writeNetworkJsonResponse(response, status, body, cors) {
673
692
  }
674
693
  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
694
  async function requestBrowserDevHostNetwork(payload, fetchImpl, lookupHostname, allowedHttpOrigins, requestSignal) {
676
- if (!isRecord$3(payload) || typeof payload.url !== 'string' || !payload.url.trim()) {
695
+ if (!isRecord$2(payload) || typeof payload.url !== 'string' || !payload.url.trim()) {
677
696
  throw createBrowserDevHostError(400, 'INVALID_NETWORK_REQUEST', 'network.request url 必须是非空字符串');
678
697
  }
679
698
  const url = createBrowserDevHostNetworkUrl(payload.url, payload.params);
680
699
  const method = typeof payload.method === 'string' && payload.method.trim() ? payload.method.trim().toUpperCase() : 'GET';
681
700
  const headers = normalizeBrowserDevHostNetworkHeaders(payload.headers);
682
701
  assertSupportedBrowserDevHostNetworkRequestShape(headers, payload.data);
683
- const body = createBrowserDevHostNetworkBody(method, payload.data, headers);
702
+ const body = createBrowserDevHostNetworkBody(method, payload.data, headers, readBodyEncoding(payload.bodyEncoding, payload.data));
684
703
  const controller = new AbortController();
685
704
  const onRequestAbort = () => controller.abort(requestSignal.reason);
686
705
  requestSignal.addEventListener('abort', onRequestAbort, { once: true });
@@ -691,7 +710,7 @@ async function requestBrowserDevHostNetwork(payload, fetchImpl, lookupHostname,
691
710
  const pinnedTargets = new Map();
692
711
  const dispatcher = createPinnedNetworkDispatcher(pinnedTargets);
693
712
  try {
694
- const response = await fetchBrowserDevHostNetworkWithRedirects({
713
+ const response = await fetchBrowserDevHostNetworkNoRedirect({
695
714
  body,
696
715
  dispatcher,
697
716
  fetchImpl,
@@ -724,43 +743,17 @@ async function requestBrowserDevHostNetwork(payload, fetchImpl, lookupHostname,
724
743
  await dispatcher.close();
725
744
  }
726
745
  }
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');
746
+ async function fetchBrowserDevHostNetworkNoRedirect(options) {
747
+ const pinnedTarget = await resolveBrowserDevHostNetworkTarget(options.url, options.lookupHostname, options.allowedHttpOrigins);
748
+ options.pinnedTargets.set(createPinnedNetworkTargetKey(options.url), pinnedTarget);
749
+ return options.fetchImpl(options.url.toString(), {
750
+ body: options.body,
751
+ dispatcher: options.dispatcher,
752
+ headers: options.headers,
753
+ method: options.method,
754
+ redirect: 'manual',
755
+ signal: options.signal,
756
+ });
764
757
  }
765
758
  async function resolveBrowserDevHostNetworkTarget(url, lookupHostname, allowedHttpOrigins) {
766
759
  if (!['http:', 'https:'].includes(url.protocol)) {
@@ -890,7 +883,7 @@ function createBrowserDevHostNetworkUrl(input, params) {
890
883
  if (!['http:', 'https:'].includes(url.protocol)) {
891
884
  throw createBrowserDevHostError(400, 'INVALID_NETWORK_REQUEST', 'network.request 仅支持 HTTP(S) URL');
892
885
  }
893
- if (isRecord$3(params)) {
886
+ if (isRecord$2(params)) {
894
887
  Object.entries(params).forEach(([key, value]) => {
895
888
  if (value !== undefined && value !== null) {
896
889
  url.searchParams.set(key, String(value));
@@ -901,7 +894,7 @@ function createBrowserDevHostNetworkUrl(input, params) {
901
894
  }
902
895
  function normalizeBrowserDevHostNetworkHeaders(headers) {
903
896
  const normalized = new Headers();
904
- if (!isRecord$3(headers)) {
897
+ if (!isRecord$2(headers)) {
905
898
  return normalized;
906
899
  }
907
900
  Object.entries(headers).forEach(([key, value]) => {
@@ -947,22 +940,60 @@ function looksLikeMultipartBody(data) {
947
940
  const trimmed = data.trimStart();
948
941
  return trimmed.startsWith('--') && /content-disposition\s*:\s*form-data/i.test(data);
949
942
  }
950
- function createBrowserDevHostNetworkBody(method, data, headers) {
943
+ function createBrowserDevHostNetworkBody(method, data, headers, bodyEncoding) {
951
944
  if (data === undefined || method === 'GET' || method === 'HEAD') {
952
945
  return undefined;
953
946
  }
954
- const body = typeof data === 'string' ? data : JSON.stringify(data);
947
+ const body = typeof data === 'string'
948
+ ? data
949
+ : bodyEncoding === 'form'
950
+ ? createLegacyFormBody$1(data)
951
+ : JSON.stringify(data);
955
952
  if (Buffer.byteLength(body) > MAX_BROWSER_DEV_HOST_NETWORK_REQUEST_BODY) {
956
953
  throw createBrowserDevHostError(413, 'REQUEST_ENTITY_TOO_LARGE', 'network.request data exceeds 2097152 bytes');
957
954
  }
958
- if (typeof data === 'string') {
959
- return body;
955
+ if (bodyEncoding === 'form' && !headers.has('content-type')) {
956
+ headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
960
957
  }
961
- if (!headers.has('content-type')) {
958
+ else if (bodyEncoding === 'json' && typeof data !== 'string' && !headers.has('content-type')) {
962
959
  headers.set('content-type', 'application/json');
963
960
  }
964
961
  return body;
965
962
  }
963
+ function readBodyEncoding(value, data) {
964
+ if (value === 'form' || value === 'json')
965
+ return value;
966
+ if (value === undefined && (data === undefined || typeof data === 'string'))
967
+ return undefined;
968
+ throw createBrowserDevHostError(400, 'INVALID_NETWORK_REQUEST', 'network.request bodyEncoding 必须明确为 form 或 json');
969
+ }
970
+ function encodeLegacyFormComponent$1(value) {
971
+ return encodeURIComponent(value).replace(/[!'()*]/g, (character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`);
972
+ }
973
+ function appendLegacyFormValue$1(pairs, key, value) {
974
+ if (value === undefined)
975
+ return;
976
+ if (value === null) {
977
+ pairs.push([key, '']);
978
+ return;
979
+ }
980
+ if (Array.isArray(value)) {
981
+ value.forEach((item) => appendLegacyFormValue$1(pairs, key, item));
982
+ return;
983
+ }
984
+ if (typeof value === 'object' && !(value instanceof Date)) {
985
+ Object.entries(value).forEach(([childKey, childValue]) => appendLegacyFormValue$1(pairs, `${key}[${childKey}]`, childValue));
986
+ return;
987
+ }
988
+ pairs.push([key, value instanceof Date ? value.toISOString() : String(value)]);
989
+ }
990
+ function createLegacyFormBody$1(data) {
991
+ const pairs = [];
992
+ if (data && typeof data === 'object') {
993
+ Object.entries(data).forEach(([key, value]) => appendLegacyFormValue$1(pairs, key, value));
994
+ }
995
+ return pairs.map(([key, value]) => `${encodeLegacyFormComponent$1(key)}=${encodeLegacyFormComponent$1(value)}`).join('&');
996
+ }
966
997
  function safeJsonParse(text) {
967
998
  try {
968
999
  return JSON.parse(text);
@@ -1098,7 +1129,7 @@ function createDevSessionRoutes(options) {
1098
1129
  };
1099
1130
  }
1100
1131
  function validateDevSessionCreatePayload(payload, allowedMiniUrlOrigins) {
1101
- if (!isRecord$3(payload) || Object.keys(payload).some((key) => !['mini_url_origin', 'runtime_permissions'].includes(key))) {
1132
+ if (!isRecord$2(payload) || Object.keys(payload).some((key) => !['mini_url_origin', 'runtime_permissions'].includes(key))) {
1102
1133
  throw new TypeError('Dev Session body is invalid');
1103
1134
  }
1104
1135
  if (typeof payload.mini_url_origin !== 'string') {
@@ -1589,6 +1620,22 @@ const TOKEN_PATTERN = /^[A-Za-z0-9_-]{22}$/;
1589
1620
  const MAX_TOKEN_GENERATION_ATTEMPTS = 8;
1590
1621
  const CLOSE_WINDOW_DELAY_MS = 500;
1591
1622
  const CLOSE_WINDOW_PROTOCOL = `heybox://${encodeURIComponent(JSON.stringify({ protocol_type: 'closeWindow' }))}`;
1623
+ const MINI_PROGRAM_URL_QUERY_PARAM$1 = 'mini_url';
1624
+ const MINI_PROGRAM_SDK_VERSION_QUERY_PARAM = 'sdk_version';
1625
+ const MINI_PROGRAM_LOCAL_DEV_LAUNCH_TOKEN_QUERY_PARAM = 'local_dev_launch_token';
1626
+ const MINI_PROGRAM_DEV_SHELL_URL = 'heybox-mini-dev://sandbox';
1627
+ const OPEN_IN_APP_URL = 'https://api.xiaoheihe.cn/open_inapp/';
1628
+ function createMobileAppQrPayload(appUrl, options = {}) {
1629
+ const protocol = createHeyboxProtocol(createMiniProgramDevShellOpenWindowPayload(appUrl, options));
1630
+ return `${OPEN_IN_APP_URL}#${protocol}`;
1631
+ }
1632
+ function projectMiniProgramDevContextUrlToPrivateHost(value, host) {
1633
+ const url = parseDevContextUrl(value, 'loopback', 'devContextUrl must be a canonical loopback Dev Session URL');
1634
+ if (!isCanonicalPrivateLanIpv4(host))
1635
+ throw new TypeError('Mobile Dev Context host must be a canonical private IPv4 address');
1636
+ url.hostname = host;
1637
+ return url.href;
1638
+ }
1592
1639
  function createMobileLaunchRedirectRegistry(options = {}) {
1593
1640
  const capacity = options.capacity ?? DEFAULT_CAPACITY;
1594
1641
  const ttlMs = options.ttlMs ?? DEFAULT_TTL_MS;
@@ -1673,6 +1720,69 @@ function createMobileLaunchRedirectDocument(payload) {
1673
1720
  const closeUrl = JSON.stringify(CLOSE_WINDOW_PROTOCOL).replaceAll('<', '\\u003c');
1674
1721
  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
1722
  }
1723
+ function createMiniProgramDevShellOpenWindowPayload(appUrl, options) {
1724
+ const devShellUrl = `${MINI_PROGRAM_DEV_SHELL_URL}?${readDevShellQueryEntries(appUrl, options)
1725
+ .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
1726
+ .join('&')}`;
1727
+ const miniProgramId = options.miniProgramId?.trim();
1728
+ return {
1729
+ protocol_type: 'openWindow',
1730
+ full_screen: true,
1731
+ mini_program: '1',
1732
+ ...(miniProgramId ? { mini_program_id: miniProgramId } : {}),
1733
+ navigation_bar: { title: '' },
1734
+ webview: { url: devShellUrl, pull: false, refresh: false },
1735
+ };
1736
+ }
1737
+ function readDevShellQueryEntries(appUrl, options) {
1738
+ const entries = [[MINI_PROGRAM_URL_QUERY_PARAM$1, appUrl]];
1739
+ const miniProgramId = options.miniProgramId?.trim();
1740
+ if (miniProgramId)
1741
+ entries.push(['mini_program_id', miniProgramId]);
1742
+ const localDevLaunchToken = options.localDevLaunchToken?.trim();
1743
+ if (localDevLaunchToken)
1744
+ entries.push([MINI_PROGRAM_LOCAL_DEV_LAUNCH_TOKEN_QUERY_PARAM, localDevLaunchToken]);
1745
+ const devContextUrl = readDevContextUrl(options.devContextUrl);
1746
+ if (devContextUrl)
1747
+ entries.push([MINI_PROGRAM_DEV_CONTEXT_QUERY_PARAM, devContextUrl]);
1748
+ const sdkVersion = options.sdkVersion?.trim();
1749
+ if (sdkVersion)
1750
+ entries.push([MINI_PROGRAM_SDK_VERSION_QUERY_PARAM, sdkVersion]);
1751
+ return entries;
1752
+ }
1753
+ function readDevContextUrl(value) {
1754
+ if (value === undefined || value === '')
1755
+ return undefined;
1756
+ return parseDevContextUrl(value, 'loopback-or-private', 'devContextUrl must be a canonical Dev Session URL').href;
1757
+ }
1758
+ function parseDevContextUrl(value, hostPolicy, errorMessage) {
1759
+ if (value !== value.trim())
1760
+ throw new TypeError(errorMessage);
1761
+ let url;
1762
+ try {
1763
+ url = new URL(value);
1764
+ }
1765
+ catch {
1766
+ throw new TypeError(errorMessage);
1767
+ }
1768
+ const tokenPath = `${MINI_PROGRAM_DEV_CONTEXT_PATH}/`;
1769
+ const hostAllowed = isLoopbackHostname(url.hostname) || (hostPolicy === 'loopback-or-private' && isCanonicalPrivateLanIpv4(url.hostname));
1770
+ if (url.protocol !== 'http:' ||
1771
+ url.username !== '' ||
1772
+ url.password !== '' ||
1773
+ url.search !== '' ||
1774
+ url.hash !== '' ||
1775
+ !url.pathname.startsWith(tokenPath) ||
1776
+ !/^[a-f0-9]{64}$/.test(url.pathname.slice(tokenPath.length)) ||
1777
+ !hostAllowed ||
1778
+ url.href !== value) {
1779
+ throw new TypeError(errorMessage);
1780
+ }
1781
+ return url;
1782
+ }
1783
+ function createHeyboxProtocol(payload) {
1784
+ return `heybox://${encodeURIComponent(JSON.stringify(payload))}`;
1785
+ }
1676
1786
  function escapeHtml(value) {
1677
1787
  return value.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;').replaceAll('"', '&quot;').replaceAll("'", '&#039;');
1678
1788
  }
@@ -1713,13 +1823,12 @@ function assertAddressId(addressId) {
1713
1823
  }
1714
1824
  }
1715
1825
 
1716
- const MINI_PROGRAM_URL_QUERY_PARAM$1 = 'mini_url';
1826
+ const MINI_PROGRAM_URL_QUERY_PARAM = 'mini_url';
1717
1827
  const BROWSER_DEV_HOST_BOOTSTRAP_PATH = '/__hb_sdk_bootstrap__';
1718
1828
  const BROWSER_DEV_HOST_CHANNEL_PATH = '/__hb_sdk__/channel';
1719
1829
  const BROWSER_DEV_HOST_NETWORK_PATH = '/__hb_sdk__/network';
1720
1830
  const MOBILE_LAUNCH_REDIRECT_CONTROL_PATH = '/__hb_sdk__/mobile-launch-redirect';
1721
1831
  const MOBILE_LAUNCH_REDIRECT_CONTROL_BODY_LIMIT_BYTES = 66 * 1024;
1722
- const DEV_PERMISSIONS_PATH = '/__hb_sdk__/dev-permissions';
1723
1832
  const DEV_LISTEN_HOST$1 = '::';
1724
1833
  const DEV_PORT_PROBE_HOST = '0.0.0.0';
1725
1834
  const LOCAL_DEV_URL_HOST$1 = '127.0.0.1';
@@ -1741,7 +1850,8 @@ const DEFAULT_CHANNEL_TRANSPORT = {
1741
1850
  };
1742
1851
  const IPV4_LOOPBACK_ADDRESSES = new net.BlockList();
1743
1852
  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-XopYKLYZ.cjs', document.baseURI).href)))('ws');
1853
+ 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-CoSXtEYa.cjs', document.baseURI).href)))('ws');
1854
+ 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-CoSXtEYa.cjs', document.baseURI).href)))('parse5');
1745
1855
  const BROWSER_DEV_HOST_ROOT_CANDIDATES = [
1746
1856
  path.resolve(__dirname, 'devtools/browser-dev-host'),
1747
1857
  path.resolve(__dirname, '../devtools/browser-dev-host'),
@@ -1771,7 +1881,6 @@ async function startBrowserDevHostServer(options) {
1771
1881
  devContext: options.devContext,
1772
1882
  lanAddresses: options.lanAddresses ?? [],
1773
1883
  loginAvailable: options.loginService !== undefined,
1774
- macAppProtocol: options.macAppProtocol,
1775
1884
  miniProgram: options.miniProgram,
1776
1885
  mobileLaunchRedirect: initialMobileLaunchRedirect,
1777
1886
  nativeAppLaunchUnavailableReason: options.nativeAppLaunchUnavailableReason,
@@ -1787,7 +1896,6 @@ async function startBrowserDevHostServer(options) {
1787
1896
  isMobileLaunchRedirectPeerAllowed: options.isMobileLaunchRedirectPeerAllowed ?? isAllowedMobileLaunchRedirectPeer,
1788
1897
  lookupHostname: options.lookupHostname ?? (async (hostname) => promises.lookup(hostname, { all: true, verbatim: true })),
1789
1898
  now: options.now ?? Date.now,
1790
- permissionController: options.permissionController,
1791
1899
  channelHeartbeatIntervalMs: options.channelHeartbeatIntervalMs ?? DEFAULT_CHANNEL_HEARTBEAT_INTERVAL_MS,
1792
1900
  channelHelloTimeoutMs: options.channelHelloTimeoutMs ?? DEFAULT_CHANNEL_HELLO_TIMEOUT_MS,
1793
1901
  channelOutboundBufferLimitBytes: options.channelOutboundBufferLimitBytes ?? DEFAULT_CHANNEL_OUTBOUND_BUFFER_LIMIT_BYTES,
@@ -1855,10 +1963,6 @@ async function startBrowserDevHostServer(options) {
1855
1963
  delete bootstrap.mobileLaunchRedirect;
1856
1964
  }
1857
1965
  }
1858
- if (next.macAppProtocol === null)
1859
- delete bootstrap.macAppProtocol;
1860
- else if (next.macAppProtocol !== undefined)
1861
- bootstrap.macAppProtocol = next.macAppProtocol;
1862
1966
  if (next.miniProgram !== undefined)
1863
1967
  bootstrap.miniProgram = next.miniProgram;
1864
1968
  bootstrapJson = serializeBrowserDevHostBootstrap(bootstrap);
@@ -1891,7 +1995,36 @@ function assertCompleteMiniProgramBrowserDevHostRoot(root) {
1891
1995
  }
1892
1996
  }
1893
1997
  function isCompleteMiniProgramBrowserDevHostRoot(root) {
1894
- return fs.existsSync(path.join(root, 'index.html')) && fs.existsSync(path.join(root, 'main.js'));
1998
+ const entryPath = path.join(root, 'index.html');
1999
+ if (!fs.existsSync(entryPath))
2000
+ return false;
2001
+ // 测试夹具与旧发布产物仍使用固定入口;Vue 3 构建使用 HTML 中的哈希资源。
2002
+ if (fs.statSync(path.join(root, 'main.js'), { throwIfNoEntry: false })?.isFile())
2003
+ return true;
2004
+ try {
2005
+ const references = collectBrowserDevHostLocalReferences(parseHtml(fs.readFileSync(entryPath, 'utf8')));
2006
+ return (references.some((reference) => /\.m?js(?:$|\?)/.test(reference)) &&
2007
+ references.every((reference) => {
2008
+ const pathname = decodeURIComponent(reference.split(/[?#]/, 1)[0]);
2009
+ const resolved = path.resolve(root, pathname.replace(/^\/+/, ''));
2010
+ return resolved.startsWith(`${root}${path.sep}`) && fs.statSync(resolved, { throwIfNoEntry: false })?.isFile() === true;
2011
+ }));
2012
+ }
2013
+ catch {
2014
+ return false;
2015
+ }
2016
+ }
2017
+ function collectBrowserDevHostLocalReferences(node, references = []) {
2018
+ for (const attribute of node.attrs ?? []) {
2019
+ if (!['href', 'src'].includes(attribute.name))
2020
+ continue;
2021
+ if (attribute.value && !/^(?:[a-z][a-z\d+.-]*:|\/\/|#)/i.test(attribute.value))
2022
+ references.push(attribute.value);
2023
+ }
2024
+ for (const child of node.childNodes ?? []) {
2025
+ collectBrowserDevHostLocalReferences(child, references);
2026
+ }
2027
+ return [...new Set(references)];
1895
2028
  }
1896
2029
  function createMissingBrowserDevHostError() {
1897
2030
  return new Error('未找到完整的 hb-sdk browser dev host 静态产物。请先执行 @heybox/hb-sdk 的 build:browser-dev-host。');
@@ -1905,7 +2038,7 @@ function createBrowserDevHostNetworkUrls(options) {
1905
2038
  }
1906
2039
  function createBrowserDevHostUrlWithHost(options) {
1907
2040
  const url = new URL(`http://${options.host}:${options.port}/`);
1908
- url.searchParams.set(MINI_PROGRAM_URL_QUERY_PARAM$1, options.appUrl);
2041
+ url.searchParams.set(MINI_PROGRAM_URL_QUERY_PARAM, options.appUrl);
1909
2042
  return url.toString();
1910
2043
  }
1911
2044
  function serializeBrowserDevHostBootstrap(bootstrap) {
@@ -2015,10 +2148,10 @@ function createBrowserDevHostServer(root, runtime) {
2015
2148
  writeForbidden(response);
2016
2149
  return;
2017
2150
  }
2018
- if (isBrowserDevHostDocumentPath(pathname) && !requestUrl.searchParams.has(MINI_PROGRAM_URL_QUERY_PARAM$1)) {
2151
+ if (isBrowserDevHostDocumentPath(pathname) && !requestUrl.searchParams.has(MINI_PROGRAM_URL_QUERY_PARAM)) {
2019
2152
  const targetUrl = new URL(requestUrl);
2020
2153
  targetUrl.pathname = '/';
2021
- targetUrl.searchParams.set(MINI_PROGRAM_URL_QUERY_PARAM$1, runtime.appUrl);
2154
+ targetUrl.searchParams.set(MINI_PROGRAM_URL_QUERY_PARAM, runtime.appUrl);
2022
2155
  response.writeHead(302, {
2023
2156
  location: `${targetUrl.pathname}${targetUrl.search}`,
2024
2157
  'cache-control': 'no-store',
@@ -2129,28 +2262,6 @@ function createBrowserDevHostServer(root, runtime) {
2129
2262
  request.once('close', () => eventStreams.delete(response));
2130
2263
  return;
2131
2264
  }
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
2265
  if (pathname === MINI_PROGRAM_DEV_CONTEXT_PATH) {
2155
2266
  if (request.method !== 'POST') {
2156
2267
  writeMethodNotAllowed(response, 'POST');
@@ -2531,7 +2642,7 @@ function createBrowserDevHostChannelServer(server, options) {
2531
2642
  }
2532
2643
  async function readBrowserDevHostChannelSnapshot(runtime, cookieHeader) {
2533
2644
  const status = await readAccountStatus(runtime, cookieHeader);
2534
- const permissions = await readBrowserDevPermissionState(runtime.permissionController, runtime.readDevContext());
2645
+ const permissions = context.createBrowserDevPermissionState(runtime.readDevContext());
2535
2646
  return {
2536
2647
  account: {
2537
2648
  revision: status.revision,
@@ -2549,13 +2660,6 @@ async function readAccountStatus(runtime, cookieHeader) {
2549
2660
  ...(status.authenticated ? { userId: status.userId } : {}),
2550
2661
  };
2551
2662
  }
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
2663
  function createConnectionEpoch(random) {
2560
2664
  const value = random(16).toString('base64url');
2561
2665
  if (!/^[A-Za-z0-9_-]{22}$/.test(value))
@@ -2607,7 +2711,7 @@ function rejectWebSocketUpgrade(socket) {
2607
2711
  async function handleLoginIntent(request, response, controller) {
2608
2712
  try {
2609
2713
  const payload = await readJsonRequestBody(request);
2610
- if (!isRecord$3(payload) || Object.keys(payload).some((key) => key !== 'return_path') || typeof payload.return_path !== 'string') {
2714
+ if (!isRecord$2(payload) || Object.keys(payload).some((key) => key !== 'return_path') || typeof payload.return_path !== 'string') {
2611
2715
  throw new BrowserDevSessionError(400, 'INVALID_LOGIN_INTENT', 'Browser Dev Host login intent is invalid');
2612
2716
  }
2613
2717
  const result = await controller.createLoginIntent({
@@ -2654,8 +2758,7 @@ async function handleLoginCallback(request, response, requestUrl, controller) {
2654
2758
  }
2655
2759
  }
2656
2760
  async function handleAuthenticatedRequest(request, response, runtime) {
2657
- const abort = new AbortController();
2658
- request.once('aborted', () => abort.abort());
2761
+ const abort = createBrowserDevHostRequestAbortScope(request, response);
2659
2762
  try {
2660
2763
  const payload = await readJsonRequestBody(request);
2661
2764
  const result = runtime.cliAuth
@@ -2666,6 +2769,9 @@ async function handleAuthenticatedRequest(request, response, runtime) {
2666
2769
  catch (error) {
2667
2770
  writeSessionError(response, error);
2668
2771
  }
2772
+ finally {
2773
+ abort.dispose();
2774
+ }
2669
2775
  }
2670
2776
  async function handleMobileLaunchRedirectRotation(request, response, rotate) {
2671
2777
  try {
@@ -2676,7 +2782,7 @@ async function handleMobileLaunchRedirectRotation(request, response, rotate) {
2676
2782
  destroyOnLimit: false,
2677
2783
  maxBytes: MOBILE_LAUNCH_REDIRECT_CONTROL_BODY_LIMIT_BYTES,
2678
2784
  });
2679
- if (!isRecord$3(value) ||
2785
+ if (!isRecord$2(value) ||
2680
2786
  Object.keys(value).length !== 3 ||
2681
2787
  typeof value.address_id !== 'string' ||
2682
2788
  typeof value.payload !== 'string' ||
@@ -2730,49 +2836,6 @@ function hasValidCsrf(request, csrfToken) {
2730
2836
  const value = request.headers['x-hb-sdk-csrf'];
2731
2837
  return typeof value === 'string' && value === csrfToken;
2732
2838
  }
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
2839
  function writeMethodNotAllowed(response, allowedMethod) {
2777
2840
  response.writeHead(405, {
2778
2841
  allow: allowedMethod,
@@ -4819,7 +4882,7 @@ const DEFAULT_RUNTIME_SANITIZE_MAX_STRING_LENGTH = 2000;
4819
4882
  *
4820
4883
  * @param value - 待判断的值。
4821
4884
  */
4822
- function isRecord$2(value) {
4885
+ function isRecord$1(value) {
4823
4886
  return Boolean(value && typeof value === 'object');
4824
4887
  }
4825
4888
  /**
@@ -4939,14 +5002,14 @@ function normalizeRuntimeError(error, options = {}) {
4939
5002
  if (error instanceof RuntimeError) {
4940
5003
  return error;
4941
5004
  }
4942
- if (isRecord$2(error)) {
5005
+ if (isRecord$1(error)) {
4943
5006
  const code = readString(error, 'code') ?? options.code ?? 'runtime.error.unknown';
4944
5007
  const message = readString(error, 'message') ?? options.message ?? 'Unknown runtime error';
4945
5008
  const domain = readString(error, 'domain') ?? options.domain ?? inferRuntimeErrorDomain(code);
4946
5009
  const severity = readString(error, 'severity') ?? options.severity;
4947
5010
  const details = sanitizeRuntimeRecord({
4948
5011
  ...options.details,
4949
- ...((isRecord$2(error.details) ? error.details : undefined) ?? {}),
5012
+ ...((isRecord$1(error.details) ? error.details : undefined) ?? {}),
4950
5013
  });
4951
5014
  return createRuntimeError({
4952
5015
  cause: error instanceof Error ? error.cause : error.cause,
@@ -5016,7 +5079,7 @@ function serializeRuntimeError(error, options = {}, depth = 0) {
5016
5079
  const normalized = normalizeRuntimeError(error);
5017
5080
  const maxCauseDepth = options.maxCauseDepth ?? 4;
5018
5081
  const cause = depth < maxCauseDepth
5019
- ? (normalized.cause ?? (isRecord$2(error) && 'cause' in error ? error.cause : undefined))
5082
+ ? (normalized.cause ?? (isRecord$1(error) && 'cause' in error ? error.cause : undefined))
5020
5083
  : undefined;
5021
5084
  const details = sanitizeRuntimeRecord(normalized.details, options);
5022
5085
  const serialized = {
@@ -5686,6 +5749,7 @@ function createEndpointObservationConfig(endpoint, options = {}) {
5686
5749
  errorMode: options.errorMode ?? endpoint.errorMode,
5687
5750
  failurePresentation: options.failurePresentation ?? endpoint.failurePresentation,
5688
5751
  jsonParseMode: options.jsonParseMode ?? endpoint.jsonParseMode,
5752
+ maxResponseBytes: options.maxResponseBytes ?? endpoint.maxResponseBytes,
5689
5753
  metadata: {
5690
5754
  ...options.metadata,
5691
5755
  endpointId: endpoint.id,
@@ -5693,10 +5757,12 @@ function createEndpointObservationConfig(endpoint, options = {}) {
5693
5757
  method: endpoint.method,
5694
5758
  observability: options.observability ?? endpoint.observability,
5695
5759
  queryEncoding: options.queryEncoding ?? endpoint.queryEncoding,
5760
+ redirectPolicy: options.redirectPolicy ?? endpoint.redirectPolicy,
5696
5761
  responseType: options.responseType ?? endpoint.responseType,
5697
5762
  security: options.security ?? endpoint.security,
5698
5763
  timeout: options.timeout ?? endpoint.timeout,
5699
5764
  url: typeof endpoint.path === 'string' ? endpoint.path : `endpoint:${endpoint.id}`,
5765
+ withCredentials: options.withCredentials ?? endpoint.withCredentials,
5700
5766
  };
5701
5767
  }
5702
5768
  /**
@@ -5783,13 +5849,16 @@ async function createEndpointConfig(endpoint, input, options = {}) {
5783
5849
  },
5784
5850
  method: endpoint.method,
5785
5851
  jsonParseMode: options.jsonParseMode ?? endpoint.jsonParseMode,
5852
+ maxResponseBytes: options.maxResponseBytes ?? endpoint.maxResponseBytes,
5786
5853
  observability: options.observability ?? endpoint.observability,
5787
5854
  query: mergeRecord(await endpoint.query?.(input), options.params, options.query),
5788
5855
  queryEncoding: options.queryEncoding ?? endpoint.queryEncoding,
5856
+ redirectPolicy: options.redirectPolicy ?? endpoint.redirectPolicy,
5789
5857
  responseType: options.responseType ?? endpoint.responseType,
5790
5858
  security: options.security ?? endpoint.security,
5791
5859
  timeout: options.timeout ?? endpoint.timeout,
5792
5860
  url: getEndpointPath(endpoint, input),
5861
+ withCredentials: options.withCredentials ?? endpoint.withCredentials,
5793
5862
  };
5794
5863
  }
5795
5864
  /**
@@ -5993,15 +6062,18 @@ function createRuntimeRequest(options) {
5993
6062
  channel: transportConfig.channel,
5994
6063
  headers: transportConfig.headers,
5995
6064
  jsonParseMode: transportConfig.jsonParseMode,
6065
+ maxResponseBytes: transportConfig.maxResponseBytes,
5996
6066
  metadata: transportConfig.metadata,
5997
6067
  method: transportConfig.method,
5998
6068
  query: transportConfig.query,
5999
6069
  queryEncoding: transportConfig.queryEncoding,
6070
+ redirectPolicy: transportConfig.redirectPolicy,
6000
6071
  responseType: transportConfig.responseType,
6001
6072
  signal: transportConfig.signal,
6002
6073
  timeout: transportConfig.timeout,
6003
6074
  traceId: transportConfig.traceId,
6004
6075
  url: transportConfig.url,
6076
+ withCredentials: transportConfig.withCredentials,
6005
6077
  });
6006
6078
  return {
6007
6079
  fallbackUsed: transportIndex > 0,
@@ -7867,7 +7939,7 @@ const DEFAULT_NODE_RUNTIME_CONFIG_VALUE_PREFIX = 'RUNTIME_VALUE_';
7867
7939
  *
7868
7940
  * @param value - 待判断的值。
7869
7941
  */
7870
- function isRecord$1(value) {
7942
+ function isRecord(value) {
7871
7943
  return Boolean(value && typeof value === 'object' && !Array.isArray(value));
7872
7944
  }
7873
7945
  /**
@@ -7987,7 +8059,7 @@ function parseEnvValue(value) {
7987
8059
  * @param value - 原始值。
7988
8060
  */
7989
8061
  function normalizeFlags(value) {
7990
- if (!isRecord$1(value)) {
8062
+ if (!isRecord(value)) {
7991
8063
  return undefined;
7992
8064
  }
7993
8065
  const flags = {};
@@ -8004,11 +8076,11 @@ function normalizeFlags(value) {
8004
8076
  * @param value - 原始值。
8005
8077
  */
8006
8078
  function normalizeConfigInput(value) {
8007
- if (!isRecord$1(value)) {
8079
+ if (!isRecord(value)) {
8008
8080
  return undefined;
8009
8081
  }
8010
8082
  const input = {};
8011
- if (isRecord$1(value.build)) {
8083
+ if (isRecord(value.build)) {
8012
8084
  input.build = value.build;
8013
8085
  }
8014
8086
  if (typeof value.channel === 'string') {
@@ -8017,16 +8089,16 @@ function normalizeConfigInput(value) {
8017
8089
  if (typeof value.env === 'string') {
8018
8090
  input.env = value.env;
8019
8091
  }
8020
- if (isRecord$1(value.flags)) {
8092
+ if (isRecord(value.flags)) {
8021
8093
  input.flags = normalizeFlags(value.flags);
8022
8094
  }
8023
8095
  if (typeof value.isProd === 'boolean') {
8024
8096
  input.isProd = value.isProd;
8025
8097
  }
8026
- if (isRecord$1(value.tenant)) {
8098
+ if (isRecord(value.tenant)) {
8027
8099
  input.tenant = value.tenant;
8028
8100
  }
8029
- if (isRecord$1(value.values)) {
8101
+ if (isRecord(value.values)) {
8030
8102
  input.values = value.values;
8031
8103
  }
8032
8104
  return hasConfigInput(input) ? input : undefined;
@@ -8570,23 +8642,47 @@ function createFetchRequestControl(signal, timeout) {
8570
8642
  * @param response - transport 响应对象。
8571
8643
  * @param responseType - responseType 参数。
8572
8644
  */
8573
- async function parseFetchResponse(response, responseType, jsonParseMode) {
8645
+ async function parseFetchResponse(response, responseType, jsonParseMode, maxResponseBytes) {
8646
+ const limit = normalizeMaxResponseBytes(maxResponseBytes);
8574
8647
  if (responseType === 'raw') {
8648
+ if (limit !== undefined) {
8649
+ throw createRuntimeError({
8650
+ code: 'runtime.transport.raw_response_limit_unsupported',
8651
+ domain: 'transport',
8652
+ message: 'Raw fetch response cannot enforce maxResponseBytes',
8653
+ recoverable: false,
8654
+ severity: 'error',
8655
+ });
8656
+ }
8575
8657
  return response;
8576
8658
  }
8577
8659
  if (response.status === 204) {
8578
8660
  return undefined;
8579
8661
  }
8580
- if (responseType === 'text') {
8662
+ if (limit === undefined && responseType === 'text') {
8581
8663
  return response.text();
8582
8664
  }
8583
- if (responseType === 'blob') {
8665
+ if (limit === undefined && responseType === 'blob') {
8584
8666
  return response.blob();
8585
8667
  }
8586
- if (responseType === 'arrayBuffer') {
8668
+ if (limit === undefined && responseType === 'arrayBuffer') {
8587
8669
  return response.arrayBuffer();
8588
8670
  }
8589
- const text = await response.text();
8671
+ if (limit === undefined) {
8672
+ return parseFetchText(await response.text(), responseType, jsonParseMode);
8673
+ }
8674
+ const bytes = await readBoundedResponse(response, limit);
8675
+ if (responseType === 'arrayBuffer')
8676
+ return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
8677
+ if (responseType === 'blob') {
8678
+ const blobBytes = bytes.slice().buffer;
8679
+ return new Blob([blobBytes], { type: response.headers.get('content-type') ?? '' });
8680
+ }
8681
+ return parseFetchText(new TextDecoder().decode(bytes), responseType, jsonParseMode);
8682
+ }
8683
+ function parseFetchText(text, responseType, jsonParseMode) {
8684
+ if (responseType === 'text')
8685
+ return text;
8590
8686
  if (!text) {
8591
8687
  return undefined;
8592
8688
  }
@@ -8600,6 +8696,62 @@ async function parseFetchResponse(response, responseType, jsonParseMode) {
8600
8696
  throw error;
8601
8697
  }
8602
8698
  }
8699
+ function normalizeMaxResponseBytes(value) {
8700
+ if (value === undefined)
8701
+ return undefined;
8702
+ if (!Number.isSafeInteger(value) || value <= 0)
8703
+ throw new TypeError('maxResponseBytes must be a positive safe integer');
8704
+ return value;
8705
+ }
8706
+ function responseTooLarge(maxResponseBytes, receivedBytes) {
8707
+ return createRuntimeError({
8708
+ code: 'runtime.transport.response_too_large',
8709
+ details: {
8710
+ maxResponseBytes,
8711
+ ...(receivedBytes === undefined ? {} : { receivedBytes }),
8712
+ },
8713
+ domain: 'transport',
8714
+ message: `Fetch response exceeds ${maxResponseBytes} bytes`,
8715
+ recoverable: false,
8716
+ severity: 'error',
8717
+ });
8718
+ }
8719
+ async function readBoundedResponse(response, maxResponseBytes) {
8720
+ const declared = response.headers.get('content-length');
8721
+ if (declared && /^(?:0|[1-9]\d*)$/.test(declared)) {
8722
+ const declaredBytes = Number(declared);
8723
+ if (Number.isSafeInteger(declaredBytes) && declaredBytes > maxResponseBytes)
8724
+ throw responseTooLarge(maxResponseBytes, declaredBytes);
8725
+ }
8726
+ const reader = response.body?.getReader();
8727
+ if (!reader)
8728
+ return new Uint8Array();
8729
+ const chunks = [];
8730
+ let receivedBytes = 0;
8731
+ try {
8732
+ while (true) {
8733
+ const next = await reader.read();
8734
+ if (next.done)
8735
+ break;
8736
+ receivedBytes += next.value.byteLength;
8737
+ if (receivedBytes > maxResponseBytes) {
8738
+ await reader.cancel().catch(() => undefined);
8739
+ throw responseTooLarge(maxResponseBytes, receivedBytes);
8740
+ }
8741
+ chunks.push(next.value);
8742
+ }
8743
+ }
8744
+ finally {
8745
+ reader.releaseLock();
8746
+ }
8747
+ const result = new Uint8Array(receivedBytes);
8748
+ let offset = 0;
8749
+ for (const chunk of chunks) {
8750
+ result.set(chunk, offset);
8751
+ offset += chunk.byteLength;
8752
+ }
8753
+ return result;
8754
+ }
8603
8755
  /**
8604
8756
  * 创建基于 fetch 的 runtime transport。
8605
8757
  *
@@ -8638,13 +8790,14 @@ function createFetchRuntimeTransport(options = {}) {
8638
8790
  try {
8639
8791
  const response = await requestControl.wait(fetcher(url, {
8640
8792
  body: createRequestBody(request.body, headers, request.bodyEncoding),
8641
- credentials: options.credentials,
8793
+ credentials: request.withCredentials === undefined ? options.credentials : request.withCredentials ? 'include' : 'omit',
8642
8794
  headers,
8643
8795
  method: request.method ?? 'GET',
8796
+ ...(request.redirectPolicy === undefined ? {} : { redirect: request.redirectPolicy }),
8644
8797
  ...(requestControl.signal ? { signal: requestControl.signal } : undefined),
8645
8798
  }));
8646
8799
  return {
8647
- data: await parseFetchResponse(response, request.responseType ?? 'json', request.jsonParseMode ?? 'strict'),
8800
+ data: await parseFetchResponse(response, request.responseType ?? 'json', request.jsonParseMode ?? 'strict', request.maxResponseBytes),
8648
8801
  headers: Object.fromEntries(response.headers.entries()),
8649
8802
  raw: response,
8650
8803
  request: {
@@ -10741,7 +10894,7 @@ function assertNodeRuntimeCapabilities(ctx, settings) {
10741
10894
  function createNodeRealtimeDriverRegistry() {
10742
10895
  const registry = createRuntimeRealtimeDriverRegistry();
10743
10896
  registry.registerLazy('node-websocket', async () => {
10744
- const mod = await Promise.resolve().then(function () { return require('./index.esm-SXAQ3WVR.cjs'); });
10897
+ const mod = await Promise.resolve().then(function () { return require('./index.esm-BoBHPfpq.cjs'); });
10745
10898
  return mod.createNodeWebSocketRuntimeDriver();
10746
10899
  });
10747
10900
  return registry;
@@ -14527,6 +14680,7 @@ const websitePolicy = {
14527
14680
  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
14681
  function createBrowserDevHostCliAuth(options = {}) {
14529
14682
  const fetchImpl = options.fetchImpl ?? fetch;
14683
+ const noRedirectFetch = (input, init) => fetchImpl(input, { ...init, redirect: 'manual' });
14530
14684
  const store = options.store ?? { env: options.env };
14531
14685
  const readSession = options.readSession ?? (() => session.readHeyboxAuthSession(store));
14532
14686
  let lastKey = '';
@@ -14538,7 +14692,7 @@ function createBrowserDevHostCliAuth(options = {}) {
14538
14692
  runtimePromise ??= createNodeProcessRuntime({
14539
14693
  appId: 'hb-sdk-browser-dev-host',
14540
14694
  environment: createNodeProcessRuntimeEnvironment({
14541
- transport: createFetchRuntimeTransport({ fetch: fetchImpl }),
14695
+ transport: createFetchRuntimeTransport({ fetch: noRedirectFetch }),
14542
14696
  }),
14543
14697
  identity: {
14544
14698
  container: 'browser',
@@ -14609,10 +14763,10 @@ async function readCliUserProfile(runtime, session) {
14609
14763
  }
14610
14764
  }
14611
14765
  function readCliUserProfileFields(value) {
14612
- if (!isRecord$3(value))
14766
+ if (!isRecord$2(value))
14613
14767
  return undefined;
14614
- const data = isRecord$3(value.data) ? value.data : value;
14615
- const result = isRecord$3(data.result) ? data.result : data;
14768
+ const data = isRecord$2(value.data) ? value.data : value;
14769
+ const result = isRecord$2(data.result) ? data.result : data;
14616
14770
  const nickname = typeof result.display_username === 'string' ? result.display_username.trim() : '';
14617
14771
  const avatar = typeof result.display_avatar === 'string' ? result.display_avatar.trim() : '';
14618
14772
  if (!nickname && !avatar)
@@ -14673,7 +14827,7 @@ async function executeCliHeyboxAuthenticatedRequest(runtime, session, request, s
14673
14827
  }
14674
14828
  function readQueryParams(params) {
14675
14829
  const query = {};
14676
- if (!isRecord$3(params))
14830
+ if (!isRecord$2(params))
14677
14831
  return query;
14678
14832
  for (const [key, value] of Object.entries(params)) {
14679
14833
  if (value === undefined || value === null || key === 'heybox_id')
@@ -14698,111 +14852,6 @@ function containsSecret(value, secret) {
14698
14852
  }
14699
14853
  }
14700
14854
 
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
14855
  const LAUNCH_CORS_HEADERS = {
14807
14856
  'access-control-allow-methods': 'GET',
14808
14857
  'access-control-allow-origin': '*',
@@ -14908,123 +14957,7 @@ function writeLaunchResponse(response, status, body) {
14908
14957
  /** 构建时替换为当前发布包的实际版本。 */
14909
14958
  const HB_SDK_VERSION = typeof undefined === 'string'
14910
14959
  ? undefined
14911
- : '0.7.5-alpha.0';
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
- }
14960
+ : '0.8.0-alpha.2';
15028
14961
 
15029
14962
  const DEFAULT_APP_PORT = 5173;
15030
14963
  const DEFAULT_BROWSER_DEV_HOST_PORT = 5174;
@@ -15062,44 +14995,7 @@ async function runDevCommand(options, runtime = {}) {
15062
14995
  projectRoot,
15063
14996
  timeoutMs: runtime.devContextTimeoutMs ?? DEFAULT_DEV_CONTEXT_TIMEOUT_MS,
15064
14997
  });
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
- };
14998
+ const launchRuntimePermissions = context.createBrowserDevRuntimePermissions(context.createBrowserDevPermissionState(devLaunchContext));
15103
14999
  const vite = await logger.task('正在加载项目 Vite', () => projectVite.loadProjectVite(projectRoot), { successText: '已加载项目 Vite' });
15104
15000
  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
15001
  const mobileDevContextUrlsByOrigin = new Map();
@@ -15146,18 +15042,12 @@ async function runDevCommand(options, runtime = {}) {
15146
15042
  loginService: runtime.loginService,
15147
15043
  miniProgram,
15148
15044
  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
15045
  onMobileDevSessionCreated: ({ devContextUrl, miniUrlOrigin }) => {
15155
15046
  mobileDevContextUrlsByOrigin.set(miniUrlOrigin, devContextUrl);
15156
15047
  browserDevHost.updateBootstrap({
15157
15048
  lanAddresses: buildLanAddresses(),
15158
15049
  });
15159
15050
  },
15160
- permissionController,
15161
15051
  port: options.browserDevHostPort ?? DEFAULT_BROWSER_DEV_HOST_PORT,
15162
15052
  root: runtime.browserDevHostRoot,
15163
15053
  rootCandidates: runtime.browserDevHostRootCandidates,
@@ -15186,11 +15076,6 @@ async function runDevCommand(options, runtime = {}) {
15186
15076
  browserDevHost.updateBootstrap({
15187
15077
  devContext: tokenContext,
15188
15078
  lanAddresses: buildLanAddresses(),
15189
- macAppProtocol: createMacAppProtocol(appUrl, {
15190
- miniProgramId: devLaunchContext.miniProgramId,
15191
- localDevLaunchToken,
15192
- sdkVersion: HB_SDK_VERSION,
15193
- }),
15194
15079
  });
15195
15080
  },
15196
15081
  projectRoot,
@@ -15250,72 +15135,6 @@ function createMiniProgramSummary(miniProgramId, detail) {
15250
15135
  ...(typeof detail.developer_name === 'string' && detail.developer_name.trim() ? { developerName: detail.developer_name.trim() } : {}),
15251
15136
  };
15252
15137
  }
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
15138
  async function loadRemoteDevContextWithTimeout(options) {
15320
15139
  const controller = new AbortController();
15321
15140
  const fetchImpl = ((input, init) => options.fetchImpl(input, { ...init, signal: controller.signal }));