@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.
- package/CHANGELOG.md +86 -0
- package/README.md +69 -16
- package/THIRD_PARTY_NOTICES.md +1755 -0
- package/dist/cli-chunks/{build-V1YBdpzY.cjs → build-CCLWgXyA.cjs} +6 -5
- package/dist/cli-chunks/{context-Ba1Je-wT.cjs → context-Brh56h56.cjs} +2 -27
- package/dist/cli-chunks/{create-CKGjqo9E.cjs → create-BZ-hi2s1.cjs} +1 -1
- package/dist/cli-chunks/{dev-XopYKLYZ.cjs → dev-CoSXtEYa.cjs} +336 -517
- package/dist/cli-chunks/{doctor-BHbrYQqT.cjs → doctor-EsCYJGhV.cjs} +1 -1
- package/dist/cli-chunks/{index-C9mpajVG.cjs → index-BL5eEPap.cjs} +14 -14
- package/dist/cli-chunks/{index-DKWfX6Ut.cjs → index-CS6Q0o5C.cjs} +2 -2
- package/dist/cli-chunks/{index.esm-SXAQ3WVR.cjs → index.esm-BoBHPfpq.cjs} +6 -6
- package/dist/cli-chunks/{login-BVWicWqe.cjs → login-CILLxGuf.cjs} +2 -2
- package/dist/cli-chunks/{project-vite-CBb38HJ3.cjs → project-vite-Qu6Xe9Dn.cjs} +1 -1
- package/dist/cli-chunks/{remote-BG1u0NKT.cjs → remote-DRuTQ51u.cjs} +10 -8
- package/dist/cli-chunks/{runtime-gate-CtV7rWyX.cjs → runtime-gate-DFjw66kF.cjs} +20 -1
- package/dist/cli-chunks/{runtime-permission-env-D-8_jPG3.cjs → runtime-permission-env-CjsCe5bp.cjs} +13 -13
- package/dist/cli-chunks/{session-CJS_SEp9.cjs → session-D-_N3WVL.cjs} +1 -1
- 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 +1036 -90
- package/dist/index.esm.js +1036 -91
- package/dist/miniapp-publish.cjs.js +13 -13
- package/dist/miniapp-publish.esm.js +13 -13
- package/dist/protocol.cjs.js +208 -6
- package/dist/protocol.esm.js +182 -7
- package/dist/templates/vue3-vite-ts/README.md.ejs +2 -0
- package/dist/templates/vue3-vite-ts/vite.config.ts +1 -1
- package/dist/vite.cjs.js +31 -4
- package/dist/vite.esm.js +31 -5
- package/package.json +28 -11
- package/skill/SKILL.md +9 -5
- package/skill/references/api-protocol.md +111 -3
- package/skill/references/api-root.md +170 -22
- package/skill/references/cli.md +21 -17
- package/skill/references/examples.md +30 -1
- package/skill/references/recipes.md +105 -1
- package/skill/references/safety-boundaries.md +12 -1
- package/skill/scripts/sync-references.mjs +37 -3
- package/skill/skill.json +4 -4
- package/types/core/client.d.ts +17 -1
- package/types/core/errors.d.ts +5 -5
- package/types/core/sdk.d.ts +8 -5
- package/types/core/singleton.d.ts +59 -6
- package/types/index.d.ts +4 -2
- package/types/miniapp-manifest/schema.d.ts +5 -0
- package/types/miniapp-publish/index.d.ts +8 -8
- package/types/modules/auth/index.d.ts +15 -1
- package/types/modules/cloud/index.d.ts +75 -5
- package/types/modules/device/index.d.ts +31 -3
- 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/navigation/index.d.ts +46 -4
- package/types/modules/network/index.d.ts +72 -14
- package/types/modules/share/copy-link.d.ts +3 -3
- package/types/modules/share/index.d.ts +61 -5
- package/types/modules/share/screenshot.d.ts +3 -3
- package/types/modules/share/show-share-menu.d.ts +3 -3
- package/types/modules/storage/index.d.ts +38 -10
- package/types/modules/ui/index.d.ts +46 -4
- package/types/modules/user/get-info.d.ts +1 -1
- package/types/modules/user/index.d.ts +46 -4
- package/types/modules/user/steam-game-list.d.ts +2 -2
- package/types/modules/viewport/index.d.ts +36 -8
- 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/vite/index.d.ts +15 -7
- 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-
|
|
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-
|
|
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-
|
|
17
|
+
var session = require('./session-D-_N3WVL.cjs');
|
|
18
18
|
var browser = require('./browser-RAy8e8cV.cjs');
|
|
19
|
-
var projectVite = require('./project-vite-
|
|
20
|
-
var runtimePermissionEnv = require('./runtime-permission-env-
|
|
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$
|
|
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 =
|
|
619
|
-
|
|
620
|
-
requestAbort.
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
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$
|
|
661
|
+
if (isRecord$2(payload) && typeof payload.url === 'string') {
|
|
643
662
|
detail.url = sanitizeNetworkRequestUrl(payload.url);
|
|
644
663
|
}
|
|
645
|
-
if (isRecord$
|
|
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$
|
|
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
|
|
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
|
|
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');
|
|
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$
|
|
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$
|
|
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'
|
|
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 (
|
|
959
|
-
|
|
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$
|
|
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('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"').replaceAll("'", ''');
|
|
1678
1788
|
}
|
|
@@ -1713,13 +1823,12 @@ function assertAddressId(addressId) {
|
|
|
1713
1823
|
}
|
|
1714
1824
|
}
|
|
1715
1825
|
|
|
1716
|
-
const MINI_PROGRAM_URL_QUERY_PARAM
|
|
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-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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$
|
|
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 =
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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
|
|
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
|
|
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
|
|
8079
|
+
if (!isRecord(value)) {
|
|
8008
8080
|
return undefined;
|
|
8009
8081
|
}
|
|
8010
8082
|
const input = {};
|
|
8011
|
-
if (isRecord
|
|
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
|
|
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
|
|
8098
|
+
if (isRecord(value.tenant)) {
|
|
8027
8099
|
input.tenant = value.tenant;
|
|
8028
8100
|
}
|
|
8029
|
-
if (isRecord
|
|
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
|
-
|
|
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-
|
|
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:
|
|
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$
|
|
14766
|
+
if (!isRecord$2(value))
|
|
14613
14767
|
return undefined;
|
|
14614
|
-
const data = isRecord$
|
|
14615
|
-
const result = isRecord$
|
|
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$
|
|
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.
|
|
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
|
|
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 }));
|