@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.
- package/CHANGELOG.md +44 -1
- package/README.md +87 -14
- package/THIRD_PARTY_NOTICES.md +1755 -0
- package/dist/cli-chunks/{build-DJWFSM1B.cjs → build-qWzAbpS7.cjs} +2 -2
- package/dist/cli-chunks/{context-DV2UK1Nz.cjs → context-CtS2Thp0.cjs} +1 -26
- package/dist/cli-chunks/{create-2HfoB48V.cjs → create-PV5ua977.cjs} +1 -1
- package/dist/cli-chunks/{dev-Dgt2zS9k.cjs → dev-CwKbAm_H.cjs} +337 -522
- package/dist/cli-chunks/doctor-tJUGOYrm.cjs +65 -0
- package/dist/cli-chunks/{index-BjoSXl8C.cjs → index-DVuD75Hr.cjs} +1 -1
- package/dist/cli-chunks/{index-D62ANeBv.cjs → index-De687C6-.cjs} +33 -24
- package/dist/cli-chunks/{index.esm-CigcxJ2B.cjs → index.esm-B-4yrLNm.cjs} +6 -5
- package/dist/cli-chunks/{login-Cumknwdx.cjs → login-DolpqD8K.cjs} +2 -2
- package/dist/cli-chunks/{project-vite-CcE-HMmd.cjs → project-vite-1rvkK-M8.cjs} +1 -1
- package/dist/cli-chunks/{remote-DDdP3xcE.cjs → remote-rIAQE_G2.cjs} +4 -4
- package/dist/cli-chunks/{session-BDi_AZSv.cjs → session-CzaM2Cq3.cjs} +1 -1
- package/dist/cli-chunks/skill-CM40_9WH.cjs +83 -0
- package/dist/cli-chunks/version-Bz-AfXQU.cjs +8 -0
- package/dist/cli.cjs +1 -1
- package/dist/devtools/browser-dev-host/assets/browser-dev-host-uq-Wac6k.js +97 -0
- package/dist/devtools/browser-dev-host/assets/heybox-logo-CogNENsk.svg +6 -0
- package/dist/devtools/browser-dev-host/assets/index-CeP6SLB3.js +567 -0
- package/dist/devtools/browser-dev-host/assets/index-KD2f3Jdz.css +1 -0
- package/dist/devtools/browser-dev-host/assets/workbench-state-D-1U0JRq.js +5 -0
- package/dist/devtools/browser-dev-host/index.html +6 -435
- package/dist/index.cjs.js +924 -28
- package/dist/index.esm.js +924 -29
- package/dist/protocol.cjs.js +208 -6
- package/dist/protocol.esm.js +182 -7
- package/dist/vite.cjs.js +1 -1
- package/dist/vite.esm.js +1 -1
- package/package.json +29 -10
- package/skill/SKILL.md +16 -13
- package/skill/references/api-protocol.md +100 -4
- package/skill/references/api-root.md +142 -15
- package/skill/references/cli.md +27 -22
- package/skill/references/examples.md +30 -1
- package/skill/references/llms-index.md +1 -1
- package/skill/references/recipes.md +106 -2
- package/skill/references/safety-boundaries.md +12 -1
- package/skill/skill.json +10 -5
- package/types/core/client.d.ts +17 -1
- package/types/core/sdk.d.ts +3 -0
- package/types/core/singleton.d.ts +3 -0
- package/types/index.d.ts +4 -2
- package/types/modules/files/index.d.ts +5 -0
- package/types/modules/files/registry.d.ts +35 -0
- package/types/modules/files/types.d.ts +159 -0
- package/types/modules/network/index.d.ts +50 -3
- package/types/protocol/capabilities.d.ts +2 -2
- package/types/protocol/constants.d.ts +1 -1
- package/types/protocol/guards.d.ts +1 -1
- package/types/protocol/types.d.ts +1 -1
- package/types/protocol.d.ts +4 -3
- package/types/skill-metadata.d.ts +0 -4
- package/dist/cli-chunks/doctor-C95gIao_.cjs +0 -204
- package/dist/devtools/browser-dev-host/main.js +0 -12263
- package/skill/scripts/check-references.mjs +0 -14
- package/skill/scripts/markdown-sections.mjs +0 -36
- package/skill/scripts/package-skill.mjs +0 -60
- package/skill/scripts/package-skill.sh +0 -6
- package/skill/scripts/skill-metadata.mjs +0 -77
- package/skill/scripts/sync-agent-skills-payload.mjs +0 -359
- package/skill/scripts/sync-references.mjs +0 -794
- 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-
|
|
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-
|
|
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-
|
|
17
|
+
var session = require('./session-CzaM2Cq3.cjs');
|
|
18
18
|
var browser = require('./browser-RAy8e8cV.cjs');
|
|
19
|
-
var projectVite = require('./project-vite-
|
|
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$
|
|
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 =
|
|
619
|
-
|
|
620
|
-
requestAbort.
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
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$
|
|
662
|
+
if (isRecord$2(payload) && typeof payload.url === 'string') {
|
|
643
663
|
detail.url = sanitizeNetworkRequestUrl(payload.url);
|
|
644
664
|
}
|
|
645
|
-
if (isRecord$
|
|
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$
|
|
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
|
|
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
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
options.
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
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$
|
|
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$
|
|
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'
|
|
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 (
|
|
959
|
-
|
|
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$
|
|
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('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"').replaceAll("'", ''');
|
|
1678
1789
|
}
|
|
@@ -1713,13 +1824,12 @@ function assertAddressId(addressId) {
|
|
|
1713
1824
|
}
|
|
1714
1825
|
}
|
|
1715
1826
|
|
|
1716
|
-
const MINI_PROGRAM_URL_QUERY_PARAM
|
|
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-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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$
|
|
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 =
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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
|
|
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
|
|
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
|
|
8080
|
+
if (!isRecord(value)) {
|
|
8008
8081
|
return undefined;
|
|
8009
8082
|
}
|
|
8010
8083
|
const input = {};
|
|
8011
|
-
if (isRecord
|
|
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
|
|
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
|
|
8099
|
+
if (isRecord(value.tenant)) {
|
|
8027
8100
|
input.tenant = value.tenant;
|
|
8028
8101
|
}
|
|
8029
|
-
if (isRecord
|
|
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
|
-
|
|
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-
|
|
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:
|
|
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$
|
|
14767
|
+
if (!isRecord$2(value))
|
|
14613
14768
|
return undefined;
|
|
14614
|
-
const data = isRecord$
|
|
14615
|
-
const result = isRecord$
|
|
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$
|
|
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
|
|
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 }));
|