@heybox/hb-sdk 0.7.5-alpha.0 → 0.8.0-alpha.10
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 +99 -352
- package/README.md +103 -26
- package/THIRD_PARTY_NOTICES.md +1755 -0
- package/dist/cli-chunks/{build-V1YBdpzY.cjs → build-aDJbiFqF.cjs} +9 -5
- package/dist/cli-chunks/{context-Ba1Je-wT.cjs → context-Dp36pZ9a.cjs} +39 -81
- package/dist/cli-chunks/{create-CKGjqo9E.cjs → create-P3g0ricz.cjs} +2 -2
- package/dist/cli-chunks/{dev-XopYKLYZ.cjs → dev-CisJkXuQ.cjs} +396 -576
- package/dist/cli-chunks/doctor-B-LF5-uj.cjs +65 -0
- package/dist/cli-chunks/{index-C9mpajVG.cjs → index-BDaeBI_B.cjs} +50 -30
- package/dist/cli-chunks/{index-DKWfX6Ut.cjs → index-CZGkk7fQ.cjs} +2 -2
- package/dist/cli-chunks/{index.esm-SXAQ3WVR.cjs → index.esm-NNLG29Tt.cjs} +8 -7
- package/dist/cli-chunks/{login-BVWicWqe.cjs → login-DTY5GolC.cjs} +2 -2
- package/dist/cli-chunks/{project-vite-CBb38HJ3.cjs → project-vite-DlCjHlu_.cjs} +1 -1
- package/dist/cli-chunks/{remote-BG1u0NKT.cjs → remote-BBMr7j8W.cjs} +61 -27
- package/dist/cli-chunks/{runtime-gate-CtV7rWyX.cjs → runtime-gate-BppCl1r3.cjs} +30 -3
- package/dist/cli-chunks/{runtime-permission-env-D-8_jPG3.cjs → runtime-permission-env-CqsTHeas.cjs} +364 -13
- package/dist/cli-chunks/{session-CJS_SEp9.cjs → session-CnGeZCRZ.cjs} +1 -1
- package/dist/cli-chunks/skill-B0yAnPOJ.cjs +83 -0
- package/dist/cli-chunks/version-DN5jrixS.cjs +8 -0
- package/dist/cli.cjs +1 -1
- package/dist/devtools/browser-dev-host/assets/browser-dev-host-BhZGUyYw.js +97 -0
- package/dist/devtools/browser-dev-host/assets/heybox-logo-CogNENsk.svg +6 -0
- package/dist/devtools/browser-dev-host/assets/index-DJFB5ySU.css +1 -0
- package/dist/devtools/browser-dev-host/assets/index-Dh9H1JOm.js +567 -0
- package/dist/devtools/browser-dev-host/assets/workbench-state-wHgWRb7I.js +5 -0
- package/dist/devtools/browser-dev-host/index.html +6 -435
- package/dist/index.cjs.js +1051 -91
- package/dist/index.esm.js +1051 -92
- package/dist/miniapp-publish.cjs.js +13 -13
- package/dist/miniapp-publish.esm.js +13 -13
- package/dist/protocol.cjs.js +381 -37
- package/dist/protocol.esm.js +355 -38
- package/dist/templates/{vue3-vite-ts → vanilla-vite-js}/.gitignore.ejs +0 -1
- package/dist/templates/vanilla-vite-js/README.md.ejs +14 -0
- package/dist/templates/vanilla-vite-js/index.html.ejs +20 -0
- package/dist/templates/vanilla-vite-js/package.json.ejs +22 -0
- package/dist/templates/vanilla-vite-js/src/assets/heybox-logo.svg +8 -0
- package/dist/templates/vanilla-vite-js/src/main.js +39 -0
- package/dist/templates/vanilla-vite-js/src/styles.css +155 -0
- package/dist/templates/{vue3-vite-ts/vite.config.ts → vanilla-vite-js/vite.config.js} +1 -2
- package/dist/vite.cjs.js +256 -10
- package/dist/vite.esm.js +256 -11
- package/package.json +37 -11
- package/skill/SKILL.md +22 -20
- package/skill/references/api-protocol.md +112 -6
- package/skill/references/api-root.md +194 -30
- package/skill/references/cli.md +41 -24
- package/skill/references/examples.md +31 -2
- package/skill/references/llms-index.md +1 -1
- package/skill/references/recipes.md +139 -36
- package/skill/references/safety-boundaries.md +15 -6
- package/skill/skill.json +10 -5
- 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/index.d.ts +1 -0
- package/types/miniapp-manifest/node.d.ts +3 -0
- package/types/miniapp-manifest/permissions.d.ts +37 -0
- package/types/miniapp-manifest/schema.d.ts +10 -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 +4 -4
- package/types/modules/share/types.d.ts +2 -4
- 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/skill-metadata.d.ts +0 -4
- package/types/vite/index.d.ts +15 -7
- package/dist/cli-chunks/doctor-BHbrYQqT.cjs +0 -204
- package/dist/devtools/browser-dev-host/main.js +0 -12158
- package/dist/templates/vue3-vite-ts/README.md.ejs +0 -45
- package/dist/templates/vue3-vite-ts/index.html.ejs +0 -12
- package/dist/templates/vue3-vite-ts/package.json.ejs +0 -33
- package/dist/templates/vue3-vite-ts/src/App.vue +0 -78
- package/dist/templates/vue3-vite-ts/src/__tests__/App.spec.ts +0 -148
- package/dist/templates/vue3-vite-ts/src/auth-handoff.ts +0 -46
- package/dist/templates/vue3-vite-ts/src/main.ts +0 -5
- package/dist/templates/vue3-vite-ts/src/styles.css +0 -60
- package/dist/templates/vue3-vite-ts/src/vite-env.d.ts +0 -1
- package/dist/templates/vue3-vite-ts/tsconfig.app.json +0 -17
- package/dist/templates/vue3-vite-ts/tsconfig.json +0 -11
- package/dist/templates/vue3-vite-ts/tsconfig.node.json +0 -11
- package/dist/templates/vue3-vite-ts/vitest.config.ts +0 -10
- 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 -792
- package/skill/scripts/validate-skill.mjs +0 -263
package/dist/index.esm.js
CHANGED
|
@@ -292,9 +292,9 @@ class HbMiniProgramSDKError extends Error {
|
|
|
292
292
|
/**
|
|
293
293
|
* 创建 SDK 标准错误。
|
|
294
294
|
*
|
|
295
|
-
* @param code 稳定错误码。
|
|
296
|
-
* @param message 面向开发者的错误说明。
|
|
297
|
-
* @param data 可选调试数据。
|
|
295
|
+
* @param code - 稳定错误码。
|
|
296
|
+
* @param message - 面向开发者的错误说明。
|
|
297
|
+
* @param data - 可选调试数据。
|
|
298
298
|
* @returns 标准化 `HbMiniProgramSDKError` 实例。
|
|
299
299
|
*
|
|
300
300
|
* @remarks
|
|
@@ -314,7 +314,7 @@ function createSDKError(code, message, data) {
|
|
|
314
314
|
* 仅在请求已经成功走完 bridge / runtime / 宿主调用链、但最终 HTTP 状态不满足
|
|
315
315
|
* `validateStatus` 时抛出。它不表示握手失败或 bridge 级错误。
|
|
316
316
|
*
|
|
317
|
-
* @typeParam T 标准化响应数据的类型。
|
|
317
|
+
* @typeParam T - 标准化响应数据的类型。
|
|
318
318
|
*/
|
|
319
319
|
class HbMiniProgramNetworkError extends Error {
|
|
320
320
|
/** HTTP 状态码。 */
|
|
@@ -328,7 +328,7 @@ class HbMiniProgramNetworkError extends Error {
|
|
|
328
328
|
/** 完整标准化响应。 */
|
|
329
329
|
response;
|
|
330
330
|
/**
|
|
331
|
-
* @param response 已完成请求的标准化网络响应。
|
|
331
|
+
* @param response - 已完成请求的标准化网络响应。
|
|
332
332
|
*/
|
|
333
333
|
constructor(response) {
|
|
334
334
|
const method = (response.config.method || 'GET').toUpperCase();
|
|
@@ -572,6 +572,22 @@ const VIEWPORT_SET_NAVIGATION_BAR_STYLE_METHOD = 'viewport.setNavigationBarStyle
|
|
|
572
572
|
const STORAGE_GET_STORAGE_METHOD = 'storage.getStorage';
|
|
573
573
|
const STORAGE_SET_STORAGE_METHOD = 'storage.setStorage';
|
|
574
574
|
const NETWORK_REQUEST_METHOD = 'network.request';
|
|
575
|
+
const NETWORK_DOWNLOAD_METHOD = 'network.download';
|
|
576
|
+
const FILES_PICK_FILES_METHOD = 'files.pickFiles';
|
|
577
|
+
const FILES_PICK_DIRECTORY_METHOD = 'files.pickDirectory';
|
|
578
|
+
const FILES_SAVE_FILE_METHOD = 'files.saveFile';
|
|
579
|
+
const FILE_CREATE_METHOD = 'file.create';
|
|
580
|
+
const FILE_REMOVE_METHOD = 'file.remove';
|
|
581
|
+
const FILE_EXISTS_METHOD = 'file.exists';
|
|
582
|
+
const FILE_READ_TEXT_METHOD = 'file.readText';
|
|
583
|
+
const FILE_WRITE_TEXT_METHOD = 'file.writeText';
|
|
584
|
+
const FILE_READ_BYTES_METHOD = 'file.readBytes';
|
|
585
|
+
const FILE_WRITE_BYTES_METHOD = 'file.writeBytes';
|
|
586
|
+
const FILE_STAT_METHOD = 'file.stat';
|
|
587
|
+
const DIRECTORY_CREATE_METHOD = 'directory.create';
|
|
588
|
+
const DIRECTORY_REMOVE_METHOD = 'directory.remove';
|
|
589
|
+
const DIRECTORY_EXISTS_METHOD = 'directory.exists';
|
|
590
|
+
const DIRECTORY_LIST_METHOD = 'directory.list';
|
|
575
591
|
const UI_SHOW_TOAST_METHOD = 'ui.showToast';
|
|
576
592
|
const UI_SHOW_LOADING_METHOD = 'ui.showLoading';
|
|
577
593
|
const UI_HIDE_LOADING_METHOD = 'ui.hideLoading';
|
|
@@ -593,20 +609,131 @@ const SDK_HANDSHAKE_METHOD = 'sdk.handshake';
|
|
|
593
609
|
const RUNTIME_LOCATION_PROBE_METHOD = 'runtime.location.probe';
|
|
594
610
|
const SDK_LOCATION_REPORT_METHOD = 'sdk.location.report';
|
|
595
611
|
const SDK_CSP_VIOLATION_METHOD = 'sdk.csp.violation';
|
|
612
|
+
const MINI_PROGRAM_OPERATION_PROGRESS_METHOD = 'operation.progress';
|
|
596
613
|
|
|
597
614
|
function isMiniProgramBridgeMessage(value) {
|
|
598
|
-
if (!value
|
|
615
|
+
if (!isRecord$1(value))
|
|
599
616
|
return false;
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
617
|
+
if (value.namespace !== MINI_PROGRAM_MESSAGE_NAMESPACE || (value.version !== 1 && value.version !== 2) || !isNonEmptyString(value.nonce)) {
|
|
618
|
+
return false;
|
|
619
|
+
}
|
|
620
|
+
if (value.type === 'handshake') {
|
|
621
|
+
return isNonEmptyString(value.id) && value.method === SDK_HANDSHAKE_METHOD && value.error === undefined && isSDKHandshakePayload(value.payload);
|
|
622
|
+
}
|
|
623
|
+
if (value.type === 'request') {
|
|
624
|
+
return isNonEmptyString(value.id) && isNonEmptyString(value.method) && value.error === undefined;
|
|
625
|
+
}
|
|
626
|
+
if (value.type === 'response') {
|
|
627
|
+
return (isNonEmptyString(value.id) &&
|
|
628
|
+
(value.method === undefined || isNonEmptyString(value.method)) &&
|
|
629
|
+
(value.error === undefined || isBridgeError(value.error)));
|
|
630
|
+
}
|
|
631
|
+
if (value.type === 'event') {
|
|
632
|
+
if (!isNonEmptyString(value.method) || value.error !== undefined)
|
|
633
|
+
return false;
|
|
634
|
+
if (value.method === MINI_PROGRAM_OPERATION_PROGRESS_METHOD) {
|
|
635
|
+
return value.version === 2 && isNonEmptyString(value.id) && isMiniProgramDownloadProgressPayload(value.payload);
|
|
636
|
+
}
|
|
637
|
+
return value.id === undefined || isNonEmptyString(value.id);
|
|
638
|
+
}
|
|
639
|
+
if (value.type === 'cancel') {
|
|
640
|
+
return (value.version === 2 && isNonEmptyString(value.id) && value.method === undefined && value.payload === undefined && value.error === undefined);
|
|
641
|
+
}
|
|
642
|
+
return false;
|
|
643
|
+
}
|
|
644
|
+
function isMiniProgramRelativePath(value) {
|
|
645
|
+
if (typeof value !== 'string' || !value || value.startsWith('/') || value.endsWith('/')) {
|
|
646
|
+
return false;
|
|
647
|
+
}
|
|
648
|
+
if (/[\\\u0000-\u001f\u007f]/.test(value))
|
|
649
|
+
return false;
|
|
650
|
+
return value.split('/').every((segment) => Boolean(segment) && segment !== '.' && segment !== '..');
|
|
651
|
+
}
|
|
652
|
+
function isMiniProgramPathRootRef(value) {
|
|
653
|
+
if (!isRecord$1(value))
|
|
654
|
+
return false;
|
|
655
|
+
if (value.kind === 'sandbox')
|
|
656
|
+
return hasOnlyKeys(value, ['kind']);
|
|
657
|
+
return value.kind === 'directory' && isNonEmptyString(value.handleId) && hasOnlyKeys(value, ['kind', 'handleId']);
|
|
658
|
+
}
|
|
659
|
+
function isMiniProgramFileRef(value) {
|
|
660
|
+
if (!isRecord$1(value) || value.kind !== 'file')
|
|
661
|
+
return false;
|
|
662
|
+
if (isNonEmptyString(value.handleId)) {
|
|
663
|
+
return hasOnlyKeys(value, ['kind', 'handleId']);
|
|
664
|
+
}
|
|
665
|
+
return (isMiniProgramPathRootRef(value.root) && isMiniProgramRelativePath(value.relativePath) && hasOnlyKeys(value, ['kind', 'root', 'relativePath']));
|
|
666
|
+
}
|
|
667
|
+
function isMiniProgramDirectoryRef(value) {
|
|
668
|
+
if (!isRecord$1(value) || value.kind !== 'directory')
|
|
669
|
+
return false;
|
|
670
|
+
if (isNonEmptyString(value.handleId)) {
|
|
671
|
+
return hasOnlyKeys(value, ['kind', 'handleId']);
|
|
672
|
+
}
|
|
673
|
+
return (isMiniProgramPathRootRef(value.root) && isMiniProgramRelativePath(value.relativePath) && hasOnlyKeys(value, ['kind', 'root', 'relativePath']));
|
|
674
|
+
}
|
|
675
|
+
function isMiniProgramByteArray(value) {
|
|
676
|
+
return value instanceof Uint8Array && value.buffer instanceof ArrayBuffer;
|
|
677
|
+
}
|
|
678
|
+
function isMiniProgramFileStat(value) {
|
|
679
|
+
return (isRecord$1(value) &&
|
|
680
|
+
value.kind === 'file' &&
|
|
681
|
+
isNonNegativeSafeInteger(value.size) &&
|
|
682
|
+
(value.modifiedAt === undefined || isNonNegativeFiniteNumber(value.modifiedAt)) &&
|
|
683
|
+
(value.createdAt === undefined || isNonNegativeFiniteNumber(value.createdAt)) &&
|
|
684
|
+
hasOnlyKeys(value, ['kind', 'size', 'modifiedAt', 'createdAt']));
|
|
685
|
+
}
|
|
686
|
+
function isMiniProgramDownloadProgressPayload(value) {
|
|
687
|
+
if (!isRecord$1(value) ||
|
|
688
|
+
!isNonNegativeSafeInteger(value.loaded) ||
|
|
689
|
+
typeof value.lengthComputable !== 'boolean' ||
|
|
690
|
+
!hasOnlyKeys(value, ['loaded', 'total', 'lengthComputable'])) {
|
|
691
|
+
return false;
|
|
692
|
+
}
|
|
693
|
+
if (!value.lengthComputable)
|
|
694
|
+
return value.total === undefined;
|
|
695
|
+
return isNonNegativeSafeInteger(value.total) && value.loaded <= value.total;
|
|
696
|
+
}
|
|
697
|
+
function isSDKHandshakePayload(value) {
|
|
698
|
+
return isRecord$1(value) && isNonEmptyString(value.href) && typeof value.userAgent === 'string' && isNonEmptyString(value.sdkVersion);
|
|
699
|
+
}
|
|
700
|
+
function isBridgeError(value) {
|
|
701
|
+
return isRecord$1(value) && isNonEmptyString(value.code) && typeof value.message === 'string';
|
|
702
|
+
}
|
|
703
|
+
function isNonNegativeSafeInteger(value) {
|
|
704
|
+
return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0;
|
|
705
|
+
}
|
|
706
|
+
function isNonNegativeFiniteNumber(value) {
|
|
707
|
+
return typeof value === 'number' && Number.isFinite(value) && value >= 0;
|
|
708
|
+
}
|
|
709
|
+
function isNonEmptyString(value) {
|
|
710
|
+
return typeof value === 'string' && value.length > 0;
|
|
711
|
+
}
|
|
712
|
+
function hasOnlyKeys(value, allowedKeys) {
|
|
713
|
+
const allowed = new Set(allowedKeys);
|
|
714
|
+
return Object.keys(value).every((key) => allowed.has(key));
|
|
715
|
+
}
|
|
716
|
+
function isRecord$1(value) {
|
|
717
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
605
718
|
}
|
|
606
719
|
|
|
607
720
|
/** 当前用户信息与登录能力支持的完整 scope 目录。 */
|
|
608
721
|
const USER_INFO_AUTHORIZATION_SCOPES = ['identity', 'profile'];
|
|
609
722
|
|
|
723
|
+
const MINI_PROGRAM_PERMISSION_KEYS = [
|
|
724
|
+
'userInfo',
|
|
725
|
+
'steamLibrary',
|
|
726
|
+
'share',
|
|
727
|
+
'storage',
|
|
728
|
+
'filesystem',
|
|
729
|
+
'clipboard',
|
|
730
|
+
'leaderboard',
|
|
731
|
+
'network',
|
|
732
|
+
];
|
|
733
|
+
new Set(MINI_PROGRAM_PERMISSION_KEYS);
|
|
734
|
+
|
|
735
|
+
new Set(MINI_PROGRAM_PERMISSION_KEYS);
|
|
736
|
+
|
|
610
737
|
/** 获取浏览器全局 window。 */
|
|
611
738
|
function getGlobalWindow() {
|
|
612
739
|
return typeof window === 'undefined' ? undefined : window;
|
|
@@ -668,7 +795,7 @@ function createMessageId() {
|
|
|
668
795
|
/** 构建时替换为当前发布包的实际版本。 */
|
|
669
796
|
const HB_SDK_VERSION = typeof undefined === 'string'
|
|
670
797
|
? undefined
|
|
671
|
-
: '0.
|
|
798
|
+
: '0.8.0-alpha.10';
|
|
672
799
|
|
|
673
800
|
const DEFAULT_TIMEOUT = 10000;
|
|
674
801
|
const HANDSHAKE_RETRY_INTERVAL = 250;
|
|
@@ -703,8 +830,7 @@ class MiniProgramBridgeClient {
|
|
|
703
830
|
constructor(options = {}) {
|
|
704
831
|
this.timeout = options.timeout || DEFAULT_TIMEOUT;
|
|
705
832
|
this.selfWindow = options.selfWindow || getGlobalWindow();
|
|
706
|
-
this.targetWindow =
|
|
707
|
-
options.targetWindow === undefined ? getParentWindow(this.selfWindow) : options.targetWindow;
|
|
833
|
+
this.targetWindow = options.targetWindow === undefined ? getParentWindow(this.selfWindow) : options.targetWindow;
|
|
708
834
|
this.targetOrigin = options.targetOrigin || readParentOrigin(this.selfWindow) || '*';
|
|
709
835
|
this.nonce = options.nonce || readBridgeNonce(this.selfWindow);
|
|
710
836
|
this.handleMessage = this.onMessage.bind(this);
|
|
@@ -737,20 +863,42 @@ class MiniProgramBridgeClient {
|
|
|
737
863
|
}
|
|
738
864
|
/** 调用父容器开放能力。 */
|
|
739
865
|
async request(method, ...args) {
|
|
866
|
+
return this.performRequest(method, args[0], true);
|
|
867
|
+
}
|
|
868
|
+
/** 发起不使用固定总时长 timer 的长操作。 */
|
|
869
|
+
async requestOperation(method, payload, options = {}) {
|
|
870
|
+
return this.performRequest(method, payload, false, options);
|
|
871
|
+
}
|
|
872
|
+
async performRequest(method, payload, useTimeout, options = {}) {
|
|
740
873
|
if (this.destroyed) {
|
|
741
874
|
throw createSDKError('SDK_DESTROYED', '小程序 SDK 已销毁');
|
|
742
875
|
}
|
|
743
876
|
if (this.runtimeUnavailable) {
|
|
744
877
|
throw this.getRuntimeUnavailableError();
|
|
745
878
|
}
|
|
746
|
-
|
|
879
|
+
if (!useTimeout && options.signal?.aborted) {
|
|
880
|
+
throw options.createAbortError?.() ?? createSDKError('REQUEST_CANCELLED', `${method} 已取消`);
|
|
881
|
+
}
|
|
882
|
+
if (!useTimeout && options.signal && !this.handshakeSettled) {
|
|
883
|
+
await waitForHandshakeOrAbort(this.waitForHandshake(), options.signal, () => options.createAbortError?.() ?? createSDKError('REQUEST_CANCELLED', `${method} 已取消`), () => {
|
|
884
|
+
const state = this.handshakeState.getState();
|
|
885
|
+
if (state.status === 'failed')
|
|
886
|
+
return state.error;
|
|
887
|
+
return this.destroyed ? createSDKError('SDK_DESTROYED', '小程序 SDK 已销毁') : undefined;
|
|
888
|
+
});
|
|
889
|
+
}
|
|
890
|
+
else {
|
|
891
|
+
await this.waitForHandshake();
|
|
892
|
+
}
|
|
747
893
|
if (this.destroyed) {
|
|
748
894
|
throw createSDKError('SDK_DESTROYED', '小程序 SDK 已销毁');
|
|
749
895
|
}
|
|
750
896
|
if (this.runtimeUnavailable) {
|
|
751
897
|
throw this.getRuntimeUnavailableError();
|
|
752
898
|
}
|
|
753
|
-
|
|
899
|
+
if (options.signal?.aborted) {
|
|
900
|
+
throw options.createAbortError?.() ?? createSDKError('REQUEST_CANCELLED', `${method} 已取消`);
|
|
901
|
+
}
|
|
754
902
|
const id = createMessageId();
|
|
755
903
|
const message = {
|
|
756
904
|
namespace: MINI_PROGRAM_MESSAGE_NAMESPACE,
|
|
@@ -762,27 +910,46 @@ class MiniProgramBridgeClient {
|
|
|
762
910
|
payload,
|
|
763
911
|
};
|
|
764
912
|
return new Promise((resolve, reject) => {
|
|
765
|
-
const
|
|
766
|
-
this.pendingRequests.delete(id);
|
|
767
|
-
reject(createSDKError('REQUEST_TIMEOUT', `${method} 调用超时`));
|
|
768
|
-
}, this.timeout);
|
|
769
|
-
this.pendingRequests.set(id, {
|
|
913
|
+
const pending = {
|
|
770
914
|
resolve: resolve,
|
|
771
915
|
reject,
|
|
772
|
-
|
|
773
|
-
|
|
916
|
+
isOperation: !useTimeout,
|
|
917
|
+
...(options.onProgress ? { onProgress: options.onProgress } : {}),
|
|
918
|
+
...(options.signal ? { signal: options.signal } : {}),
|
|
919
|
+
};
|
|
920
|
+
if (useTimeout) {
|
|
921
|
+
pending.timer = setTimeout(() => {
|
|
922
|
+
const active = this.pendingRequests.get(id);
|
|
923
|
+
if (!active) {
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
this.cleanupPending(active);
|
|
927
|
+
this.pendingRequests.delete(id);
|
|
928
|
+
reject(createSDKError('REQUEST_TIMEOUT', `${method} 调用超时`));
|
|
929
|
+
}, this.timeout);
|
|
930
|
+
}
|
|
931
|
+
this.pendingRequests.set(id, pending);
|
|
774
932
|
try {
|
|
775
933
|
this.postMessage(message);
|
|
776
934
|
}
|
|
777
935
|
catch (error) {
|
|
778
|
-
|
|
936
|
+
this.cleanupPending(pending);
|
|
779
937
|
this.pendingRequests.delete(id);
|
|
780
938
|
reject(error);
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
if (options.signal) {
|
|
942
|
+
pending.abortHandler = () => this.sendCancel(id);
|
|
943
|
+
options.signal.addEventListener('abort', pending.abortHandler, { once: true });
|
|
944
|
+
if (options.signal.aborted) {
|
|
945
|
+
pending.abortHandler();
|
|
946
|
+
}
|
|
781
947
|
}
|
|
782
948
|
});
|
|
783
949
|
}
|
|
784
950
|
/** 销毁 SDK 实例,并拒绝尚未完成的请求。 */
|
|
785
951
|
destroy() {
|
|
952
|
+
this.pendingRequests.forEach((_pending, id) => this.sendCancel(id));
|
|
786
953
|
this.destroyed = true;
|
|
787
954
|
this.selfWindow?.removeEventListener('message', this.handleMessage);
|
|
788
955
|
this.selfWindow?.removeEventListener('popstate', this.handlePopState);
|
|
@@ -835,16 +1002,12 @@ class MiniProgramBridgeClient {
|
|
|
835
1002
|
this.postHandshake();
|
|
836
1003
|
}
|
|
837
1004
|
catch (error) {
|
|
838
|
-
this.failHandshake(error instanceof HbMiniProgramSDKError
|
|
839
|
-
? error
|
|
840
|
-
: createSDKError('HANDSHAKE_FAILED', '小程序沙盒握手发送失败', error));
|
|
1005
|
+
this.failHandshake(error instanceof HbMiniProgramSDKError ? error : createSDKError('HANDSHAKE_FAILED', '小程序沙盒握手发送失败', error));
|
|
841
1006
|
}
|
|
842
1007
|
}, HANDSHAKE_RETRY_INTERVAL);
|
|
843
1008
|
}
|
|
844
1009
|
catch (error) {
|
|
845
|
-
this.failHandshake(error instanceof HbMiniProgramSDKError
|
|
846
|
-
? error
|
|
847
|
-
: createSDKError('HANDSHAKE_FAILED', '小程序沙盒握手发送失败', error));
|
|
1010
|
+
this.failHandshake(error instanceof HbMiniProgramSDKError ? error : createSDKError('HANDSHAKE_FAILED', '小程序沙盒握手发送失败', error));
|
|
848
1011
|
}
|
|
849
1012
|
}
|
|
850
1013
|
postHandshake() {
|
|
@@ -873,6 +1036,10 @@ class MiniProgramBridgeClient {
|
|
|
873
1036
|
return;
|
|
874
1037
|
}
|
|
875
1038
|
if (event.data.type === 'event') {
|
|
1039
|
+
if (event.data.id && event.data.method === MINI_PROGRAM_OPERATION_PROGRESS_METHOD) {
|
|
1040
|
+
this.handleOperationProgress(event.data);
|
|
1041
|
+
return;
|
|
1042
|
+
}
|
|
876
1043
|
this.handleEvent(event.data);
|
|
877
1044
|
return;
|
|
878
1045
|
}
|
|
@@ -954,7 +1121,7 @@ class MiniProgramBridgeClient {
|
|
|
954
1121
|
if (!pending) {
|
|
955
1122
|
return;
|
|
956
1123
|
}
|
|
957
|
-
|
|
1124
|
+
this.cleanupPending(pending);
|
|
958
1125
|
this.pendingRequests.delete(message.id);
|
|
959
1126
|
if (message.error) {
|
|
960
1127
|
pending.reject(new HbMiniProgramSDKError(message.error));
|
|
@@ -962,6 +1129,52 @@ class MiniProgramBridgeClient {
|
|
|
962
1129
|
}
|
|
963
1130
|
pending.resolve(message.payload);
|
|
964
1131
|
}
|
|
1132
|
+
handleOperationProgress(message) {
|
|
1133
|
+
if (!message.id) {
|
|
1134
|
+
return;
|
|
1135
|
+
}
|
|
1136
|
+
const pending = this.pendingRequests.get(message.id);
|
|
1137
|
+
if (!pending?.onProgress) {
|
|
1138
|
+
return;
|
|
1139
|
+
}
|
|
1140
|
+
try {
|
|
1141
|
+
pending.onProgress(message.payload);
|
|
1142
|
+
}
|
|
1143
|
+
catch {
|
|
1144
|
+
// Mini-program 回调失败不能改变 Host 长操作的生命周期。
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
sendCancel(id) {
|
|
1148
|
+
const pending = this.pendingRequests.get(id);
|
|
1149
|
+
if (!pending?.isOperation || pending.cancelSent) {
|
|
1150
|
+
return;
|
|
1151
|
+
}
|
|
1152
|
+
pending.cancelSent = true;
|
|
1153
|
+
try {
|
|
1154
|
+
const message = {
|
|
1155
|
+
namespace: MINI_PROGRAM_MESSAGE_NAMESPACE,
|
|
1156
|
+
version: MINI_PROGRAM_MESSAGE_VERSION,
|
|
1157
|
+
nonce: this.nonce,
|
|
1158
|
+
type: 'cancel',
|
|
1159
|
+
id,
|
|
1160
|
+
};
|
|
1161
|
+
this.postMessage(message);
|
|
1162
|
+
}
|
|
1163
|
+
catch {
|
|
1164
|
+
// cancel 只是意图,发送失败后仍等待唯一 terminal response。
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
cleanupPending(pending) {
|
|
1168
|
+
if (pending.timer) {
|
|
1169
|
+
clearTimeout(pending.timer);
|
|
1170
|
+
}
|
|
1171
|
+
if (pending.signal && pending.abortHandler) {
|
|
1172
|
+
pending.signal.removeEventListener('abort', pending.abortHandler);
|
|
1173
|
+
}
|
|
1174
|
+
pending.onProgress = undefined;
|
|
1175
|
+
pending.abortHandler = undefined;
|
|
1176
|
+
pending.signal = undefined;
|
|
1177
|
+
}
|
|
965
1178
|
postMessage(message) {
|
|
966
1179
|
if (!this.targetWindow) {
|
|
967
1180
|
throw createSDKError('NOT_IN_IFRAME', '当前页面不在小程序沙盒 iframe 中');
|
|
@@ -1013,13 +1226,34 @@ class MiniProgramBridgeClient {
|
|
|
1013
1226
|
return this.runtimeUnavailableError;
|
|
1014
1227
|
}
|
|
1015
1228
|
rejectAllPending(error) {
|
|
1016
|
-
this.pendingRequests.forEach(pending => {
|
|
1017
|
-
|
|
1229
|
+
this.pendingRequests.forEach((pending) => {
|
|
1230
|
+
this.cleanupPending(pending);
|
|
1018
1231
|
pending.reject(error);
|
|
1019
1232
|
});
|
|
1020
1233
|
this.pendingRequests.clear();
|
|
1021
1234
|
}
|
|
1022
1235
|
}
|
|
1236
|
+
function waitForHandshakeOrAbort(handshake, signal, createAbortError, getTerminalError) {
|
|
1237
|
+
if (!signal)
|
|
1238
|
+
return handshake;
|
|
1239
|
+
if (signal.aborted)
|
|
1240
|
+
return Promise.reject(createAbortError());
|
|
1241
|
+
return new Promise((resolve, reject) => {
|
|
1242
|
+
let settled = false;
|
|
1243
|
+
const settle = (callback) => {
|
|
1244
|
+
if (settled)
|
|
1245
|
+
return;
|
|
1246
|
+
settled = true;
|
|
1247
|
+
signal.removeEventListener('abort', onAbort);
|
|
1248
|
+
callback();
|
|
1249
|
+
};
|
|
1250
|
+
const onAbort = () => settle(() => reject(getTerminalError() ?? createAbortError()));
|
|
1251
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
1252
|
+
handshake.then(() => settle(() => (signal.aborted ? reject(createAbortError()) : resolve())), (error) => settle(() => reject(error)));
|
|
1253
|
+
if (signal.aborted)
|
|
1254
|
+
onAbort();
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1023
1257
|
|
|
1024
1258
|
/** 获取短期授权码。 */
|
|
1025
1259
|
function login(requester, options) {
|
|
@@ -1048,10 +1282,10 @@ function createCloudModule(requester) {
|
|
|
1048
1282
|
/**
|
|
1049
1283
|
* 复制当前小程序的通用分享链接。
|
|
1050
1284
|
*
|
|
1051
|
-
* @param requester 底层 bridge 请求能力。
|
|
1052
|
-
* @param options 分享扩展数据;不传时复制默认首页链接。
|
|
1285
|
+
* @param requester - 底层 bridge 请求能力。
|
|
1286
|
+
* @param options - 分享扩展数据;不传时复制默认首页链接。
|
|
1053
1287
|
* @returns 已写入系统剪贴板的完整分享链接。
|
|
1054
|
-
* @throws {HbMiniProgramSDKError} 当参数、bridge、父容器或剪贴板能力调用失败时抛出。
|
|
1288
|
+
* @throws {@link HbMiniProgramSDKError} 当参数、bridge、父容器或剪贴板能力调用失败时抛出。
|
|
1055
1289
|
*/
|
|
1056
1290
|
function copyLink(requester, options) {
|
|
1057
1291
|
return requester.request(SHARE_COPY_LINK_METHOD, options);
|
|
@@ -2251,22 +2485,22 @@ function decodeBase64Url(value) {
|
|
|
2251
2485
|
/**
|
|
2252
2486
|
* 截图并唤起分享。
|
|
2253
2487
|
*
|
|
2254
|
-
* @param requester 底层 bridge 请求能力。
|
|
2255
|
-
* @param options 截图区域、延迟与保存相册等配置。
|
|
2488
|
+
* @param requester - 底层 bridge 请求能力。
|
|
2489
|
+
* @param options - 截图区域、延迟与保存相册等配置。
|
|
2256
2490
|
* @returns 由宿主客户端协议决定的结果。
|
|
2257
|
-
* @throws {HbMiniProgramSDKError} 当 bridge、父容器或宿主能力调用失败时抛出。
|
|
2491
|
+
* @throws {@link HbMiniProgramSDKError} 当 bridge、父容器或宿主能力调用失败时抛出。
|
|
2258
2492
|
*/
|
|
2259
2493
|
function screenshot(requester, options) {
|
|
2260
2494
|
return requester.request(SHARE_SCREENSHOT_METHOD, options);
|
|
2261
2495
|
}
|
|
2262
2496
|
|
|
2263
2497
|
/**
|
|
2264
|
-
*
|
|
2498
|
+
* 展示以当前小程序通用分享页为落地页的基础分享面板。
|
|
2265
2499
|
*
|
|
2266
|
-
* @param requester 底层 bridge 请求能力。
|
|
2267
|
-
* @param options 基础分享参数。
|
|
2500
|
+
* @param requester - 底层 bridge 请求能力。
|
|
2501
|
+
* @param options - 基础分享参数。
|
|
2268
2502
|
* @returns 由宿主客户端协议决定的结果。
|
|
2269
|
-
* @throws {HbMiniProgramSDKError} 当 bridge、父容器或宿主能力调用失败时抛出。
|
|
2503
|
+
* @throws {@link HbMiniProgramSDKError} 当 bridge、父容器或宿主能力调用失败时抛出。
|
|
2270
2504
|
*/
|
|
2271
2505
|
function showShareMenu(requester, options) {
|
|
2272
2506
|
return requester.request(SHARE_SHOW_SHARE_MENU_METHOD, options);
|
|
@@ -2275,25 +2509,25 @@ function showShareMenu(requester, options) {
|
|
|
2275
2509
|
/**
|
|
2276
2510
|
* 创建分享模块。
|
|
2277
2511
|
*
|
|
2278
|
-
* @param requester 底层 bridge 请求能力。
|
|
2512
|
+
* @param requester - 底层 bridge 请求能力。
|
|
2279
2513
|
* @returns 面向业务层的分享模块对象。
|
|
2280
2514
|
*/
|
|
2281
2515
|
function createShareModule(requester, launchHref) {
|
|
2282
2516
|
return {
|
|
2283
|
-
copyLink: options => copyLink(requester, options),
|
|
2517
|
+
copyLink: (options) => copyLink(requester, options),
|
|
2284
2518
|
getExtra: () => readMiniProgramShareExtra(launchHref),
|
|
2285
|
-
showShareMenu: options => showShareMenu(requester, options),
|
|
2286
|
-
screenshot: options => screenshot(requester, options),
|
|
2519
|
+
showShareMenu: (options) => showShareMenu(requester, options),
|
|
2520
|
+
screenshot: (options) => screenshot(requester, options),
|
|
2287
2521
|
};
|
|
2288
2522
|
}
|
|
2289
2523
|
|
|
2290
2524
|
/**
|
|
2291
2525
|
* 获取小程序隔离 storage。
|
|
2292
2526
|
*
|
|
2293
|
-
* @param requester 底层 bridge 请求能力。
|
|
2294
|
-
* @param options 读取的 storage key。
|
|
2527
|
+
* @param requester - 底层 bridge 请求能力。
|
|
2528
|
+
* @param options - 读取的 storage key。
|
|
2295
2529
|
* @returns 对应 key 的标准化读取结果。
|
|
2296
|
-
* @throws {HbMiniProgramSDKError} 当 bridge、父容器或宿主能力调用失败时抛出。
|
|
2530
|
+
* @throws {@link HbMiniProgramSDKError} 当 bridge、父容器或宿主能力调用失败时抛出。
|
|
2297
2531
|
*/
|
|
2298
2532
|
function getStorage(requester, options) {
|
|
2299
2533
|
return requester.request(STORAGE_GET_STORAGE_METHOD, options);
|
|
@@ -2301,10 +2535,10 @@ function getStorage(requester, options) {
|
|
|
2301
2535
|
/**
|
|
2302
2536
|
* 写入小程序隔离 storage。
|
|
2303
2537
|
*
|
|
2304
|
-
* @param requester 底层 bridge 请求能力。
|
|
2305
|
-
* @param options 要写入的 storage key 与数据。
|
|
2538
|
+
* @param requester - 底层 bridge 请求能力。
|
|
2539
|
+
* @param options - 要写入的 storage key 与数据。
|
|
2306
2540
|
* @returns 当写入完成后 resolve。
|
|
2307
|
-
* @throws {HbMiniProgramSDKError} 当 bridge、父容器或宿主能力调用失败时抛出。
|
|
2541
|
+
* @throws {@link HbMiniProgramSDKError} 当 bridge、父容器或宿主能力调用失败时抛出。
|
|
2308
2542
|
*/
|
|
2309
2543
|
function setStorage(requester, options) {
|
|
2310
2544
|
return requester.request(STORAGE_SET_STORAGE_METHOD, options);
|
|
@@ -2312,15 +2546,382 @@ function setStorage(requester, options) {
|
|
|
2312
2546
|
/**
|
|
2313
2547
|
* 创建 storage 模块。
|
|
2314
2548
|
*
|
|
2315
|
-
* @param requester 底层 bridge 请求能力。
|
|
2549
|
+
* @param requester - 底层 bridge 请求能力。
|
|
2316
2550
|
* @returns 面向业务层的 storage 模块对象。
|
|
2317
2551
|
*/
|
|
2318
2552
|
function createStorageModule(requester) {
|
|
2319
2553
|
return {
|
|
2320
|
-
getStorage: options => getStorage(requester, options),
|
|
2321
|
-
setStorage: options => setStorage(requester, options),
|
|
2554
|
+
getStorage: (options) => getStorage(requester, options),
|
|
2555
|
+
setStorage: (options) => setStorage(requester, options),
|
|
2556
|
+
};
|
|
2557
|
+
}
|
|
2558
|
+
|
|
2559
|
+
const registries = new WeakMap();
|
|
2560
|
+
const brandedFileSystemValues = new WeakSet();
|
|
2561
|
+
const CONTROL_CHARACTER_PATTERN = /[\u0000-\u001f\u007f]/;
|
|
2562
|
+
function invalidParams$1(message, data) {
|
|
2563
|
+
return createSDKError('INVALID_PARAMS', message, data);
|
|
2564
|
+
}
|
|
2565
|
+
function clonePathRootRef(ref) {
|
|
2566
|
+
return ref.kind === 'sandbox' ? Object.freeze({ kind: 'sandbox' }) : Object.freeze({ kind: 'directory', handleId: ref.handleId });
|
|
2567
|
+
}
|
|
2568
|
+
function cloneFileRef(ref) {
|
|
2569
|
+
return 'handleId' in ref
|
|
2570
|
+
? Object.freeze({ kind: 'file', handleId: ref.handleId })
|
|
2571
|
+
: Object.freeze({
|
|
2572
|
+
kind: 'file',
|
|
2573
|
+
root: clonePathRootRef(ref.root),
|
|
2574
|
+
relativePath: ref.relativePath,
|
|
2575
|
+
});
|
|
2576
|
+
}
|
|
2577
|
+
function cloneDirectoryRef(ref) {
|
|
2578
|
+
return 'handleId' in ref
|
|
2579
|
+
? Object.freeze({ kind: 'directory', handleId: ref.handleId })
|
|
2580
|
+
: Object.freeze({
|
|
2581
|
+
kind: 'directory',
|
|
2582
|
+
root: clonePathRootRef(ref.root),
|
|
2583
|
+
relativePath: ref.relativePath,
|
|
2584
|
+
});
|
|
2585
|
+
}
|
|
2586
|
+
function assertMode(mode) {
|
|
2587
|
+
if (mode !== 'read' && mode !== 'readwrite') {
|
|
2588
|
+
throw createSDKError('FILE_IO_FAILED', 'Host 返回了无效的文件访问模式');
|
|
2589
|
+
}
|
|
2590
|
+
}
|
|
2591
|
+
function assertName(name) {
|
|
2592
|
+
if (typeof name !== 'string' || name.length === 0 || name.includes('/') || name.includes('\\') || CONTROL_CHARACTER_PATTERN.test(name)) {
|
|
2593
|
+
throw createSDKError('FILE_IO_FAILED', 'Host 返回了无效的文件名');
|
|
2594
|
+
}
|
|
2595
|
+
}
|
|
2596
|
+
function assertFileRef(ref) {
|
|
2597
|
+
if (!isMiniProgramFileRef(ref)) {
|
|
2598
|
+
throw createSDKError('FILE_IO_FAILED', 'Host 返回了无效的 File handle');
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
function assertDirectoryRef(ref) {
|
|
2602
|
+
if (!isMiniProgramDirectoryRef(ref)) {
|
|
2603
|
+
throw createSDKError('FILE_IO_FAILED', 'Host 返回了无效的 Directory handle');
|
|
2604
|
+
}
|
|
2605
|
+
}
|
|
2606
|
+
function defineReadonlyValue(target, key, value, enumerable = true) {
|
|
2607
|
+
Object.defineProperty(target, key, {
|
|
2608
|
+
value,
|
|
2609
|
+
enumerable,
|
|
2610
|
+
configurable: false,
|
|
2611
|
+
writable: false,
|
|
2612
|
+
});
|
|
2613
|
+
}
|
|
2614
|
+
function joinRelativePath(prefix, relativePath) {
|
|
2615
|
+
return prefix ? `${prefix}/${relativePath}` : relativePath;
|
|
2616
|
+
}
|
|
2617
|
+
function basename(relativePath) {
|
|
2618
|
+
const segments = relativePath.split('/');
|
|
2619
|
+
return segments[segments.length - 1];
|
|
2620
|
+
}
|
|
2621
|
+
function assertWritable(mode) {
|
|
2622
|
+
if (mode !== 'readwrite') {
|
|
2623
|
+
throw createSDKError('FILE_ACCESS_DENIED', '当前文件句柄不允许写入');
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
function assertSandboxRef(ref) {
|
|
2627
|
+
if ('handleId' in ref || ref.root.kind !== 'sandbox') {
|
|
2628
|
+
throw createSDKError('FILE_ACCESS_DENIED', '外部文件授权不允许删除');
|
|
2629
|
+
}
|
|
2630
|
+
}
|
|
2631
|
+
function normalizeCreateOptions(options) {
|
|
2632
|
+
if (options !== undefined && (!options || typeof options !== 'object' || Array.isArray(options))) {
|
|
2633
|
+
throw invalidParams$1('create options 必须是对象');
|
|
2634
|
+
}
|
|
2635
|
+
if (options?.recursive !== undefined && typeof options.recursive !== 'boolean') {
|
|
2636
|
+
throw invalidParams$1('recursive 必须是 boolean');
|
|
2637
|
+
}
|
|
2638
|
+
if (options?.exclusive !== undefined && typeof options.exclusive !== 'boolean') {
|
|
2639
|
+
throw invalidParams$1('exclusive 必须是 boolean');
|
|
2640
|
+
}
|
|
2641
|
+
return {
|
|
2642
|
+
recursive: options?.recursive ?? false,
|
|
2643
|
+
exclusive: options?.exclusive ?? false,
|
|
2322
2644
|
};
|
|
2323
2645
|
}
|
|
2646
|
+
function normalizeListOptions(options) {
|
|
2647
|
+
if (options !== undefined && (!options || typeof options !== 'object' || Array.isArray(options))) {
|
|
2648
|
+
throw invalidParams$1('list options 必须是对象');
|
|
2649
|
+
}
|
|
2650
|
+
if (options?.limit !== undefined && (!Number.isSafeInteger(options.limit) || options.limit <= 0)) {
|
|
2651
|
+
throw invalidParams$1('limit 必须是正的 safe integer');
|
|
2652
|
+
}
|
|
2653
|
+
return options?.limit;
|
|
2654
|
+
}
|
|
2655
|
+
function normalizeRemoveOptions(options) {
|
|
2656
|
+
if (options !== undefined && (!options || typeof options !== 'object' || Array.isArray(options))) {
|
|
2657
|
+
throw invalidParams$1('remove options 必须是对象');
|
|
2658
|
+
}
|
|
2659
|
+
if (options?.recursive !== undefined && typeof options.recursive !== 'boolean') {
|
|
2660
|
+
throw invalidParams$1('recursive 必须是 boolean');
|
|
2661
|
+
}
|
|
2662
|
+
return { recursive: options?.recursive ?? false };
|
|
2663
|
+
}
|
|
2664
|
+
function cloneBytes(content) {
|
|
2665
|
+
if (!(content instanceof Uint8Array)) {
|
|
2666
|
+
throw invalidParams$1('content 必须是 Uint8Array');
|
|
2667
|
+
}
|
|
2668
|
+
if (typeof SharedArrayBuffer !== 'undefined' && content.buffer instanceof SharedArrayBuffer) {
|
|
2669
|
+
throw invalidParams$1('content 不能由 SharedArrayBuffer 承载');
|
|
2670
|
+
}
|
|
2671
|
+
return new Uint8Array(content);
|
|
2672
|
+
}
|
|
2673
|
+
function normalizeStat(stat) {
|
|
2674
|
+
if (!isMiniProgramFileStat(stat)) {
|
|
2675
|
+
throw createSDKError('FILE_IO_FAILED', 'Host 返回了无效的 FileStat');
|
|
2676
|
+
}
|
|
2677
|
+
return {
|
|
2678
|
+
kind: 'file',
|
|
2679
|
+
size: stat.size,
|
|
2680
|
+
...(stat.modifiedAt === undefined ? {} : { modifiedAt: stat.modifiedAt }),
|
|
2681
|
+
...(stat.createdAt === undefined ? {} : { createdAt: stat.createdAt }),
|
|
2682
|
+
};
|
|
2683
|
+
}
|
|
2684
|
+
/** 校验并返回平台无关的 `/` 分隔逻辑相对路径。 */
|
|
2685
|
+
function normalizeRelativePath(value) {
|
|
2686
|
+
if (!isMiniProgramRelativePath(value)) {
|
|
2687
|
+
throw invalidParams$1('relativePath 必须是规范的 `/` 分隔逻辑相对路径');
|
|
2688
|
+
}
|
|
2689
|
+
return value;
|
|
2690
|
+
}
|
|
2691
|
+
class MiniProgramFileHandleRegistry {
|
|
2692
|
+
requester;
|
|
2693
|
+
fileStates = new WeakMap();
|
|
2694
|
+
directoryStates = new WeakMap();
|
|
2695
|
+
pathRootStates = new WeakMap();
|
|
2696
|
+
sandboxRoot;
|
|
2697
|
+
constructor(requester) {
|
|
2698
|
+
this.requester = requester;
|
|
2699
|
+
}
|
|
2700
|
+
getSandbox() {
|
|
2701
|
+
if (this.sandboxRoot) {
|
|
2702
|
+
return this.sandboxRoot;
|
|
2703
|
+
}
|
|
2704
|
+
const sandbox = {};
|
|
2705
|
+
const state = {
|
|
2706
|
+
root: Object.freeze({ kind: 'sandbox' }),
|
|
2707
|
+
prefix: '',
|
|
2708
|
+
mode: 'readwrite',
|
|
2709
|
+
};
|
|
2710
|
+
this.definePathRootMethods(sandbox, state);
|
|
2711
|
+
this.pathRootStates.set(sandbox, state);
|
|
2712
|
+
brandedFileSystemValues.add(sandbox);
|
|
2713
|
+
this.sandboxRoot = Object.freeze(sandbox);
|
|
2714
|
+
return this.sandboxRoot;
|
|
2715
|
+
}
|
|
2716
|
+
createFile(descriptor) {
|
|
2717
|
+
this.assertFileDescriptor(descriptor);
|
|
2718
|
+
const ref = cloneFileRef(descriptor.ref);
|
|
2719
|
+
const state = { ref, mode: descriptor.mode };
|
|
2720
|
+
const handle = {};
|
|
2721
|
+
defineReadonlyValue(handle, 'kind', 'file');
|
|
2722
|
+
defineReadonlyValue(handle, 'name', descriptor.name);
|
|
2723
|
+
defineReadonlyValue(handle, 'mode', descriptor.mode);
|
|
2724
|
+
defineReadonlyValue(handle, 'create', async (options) => {
|
|
2725
|
+
assertWritable(state.mode);
|
|
2726
|
+
await this.requester.request(FILE_CREATE_METHOD, {
|
|
2727
|
+
target: state.ref,
|
|
2728
|
+
...normalizeCreateOptions(options),
|
|
2729
|
+
});
|
|
2730
|
+
return handle;
|
|
2731
|
+
}, false);
|
|
2732
|
+
defineReadonlyValue(handle, 'remove', async () => {
|
|
2733
|
+
assertWritable(state.mode);
|
|
2734
|
+
assertSandboxRef(state.ref);
|
|
2735
|
+
await this.requester.request(FILE_REMOVE_METHOD, { target: state.ref });
|
|
2736
|
+
}, false);
|
|
2737
|
+
defineReadonlyValue(handle, 'exists', async () => {
|
|
2738
|
+
const result = await this.requester.request(FILE_EXISTS_METHOD, { target: state.ref });
|
|
2739
|
+
if (typeof result !== 'boolean') {
|
|
2740
|
+
throw createSDKError('FILE_IO_FAILED', 'Host 返回了无效的 exists 结果');
|
|
2741
|
+
}
|
|
2742
|
+
return result;
|
|
2743
|
+
}, false);
|
|
2744
|
+
defineReadonlyValue(handle, 'readText', async () => {
|
|
2745
|
+
const result = await this.requester.request(FILE_READ_TEXT_METHOD, { target: state.ref });
|
|
2746
|
+
if (typeof result !== 'string') {
|
|
2747
|
+
throw createSDKError('FILE_IO_FAILED', 'Host 返回了无效的文本内容');
|
|
2748
|
+
}
|
|
2749
|
+
return result;
|
|
2750
|
+
}, false);
|
|
2751
|
+
defineReadonlyValue(handle, 'writeText', async (content) => {
|
|
2752
|
+
assertWritable(state.mode);
|
|
2753
|
+
if (typeof content !== 'string') {
|
|
2754
|
+
throw invalidParams$1('content 必须是 string');
|
|
2755
|
+
}
|
|
2756
|
+
await this.requester.request(FILE_WRITE_TEXT_METHOD, { target: state.ref, content });
|
|
2757
|
+
}, false);
|
|
2758
|
+
defineReadonlyValue(handle, 'readBytes', async () => {
|
|
2759
|
+
const result = await this.requester.request(FILE_READ_BYTES_METHOD, { target: state.ref });
|
|
2760
|
+
if (!isMiniProgramByteArray(result)) {
|
|
2761
|
+
throw createSDKError('FILE_IO_FAILED', 'Host 返回了无效的二进制内容');
|
|
2762
|
+
}
|
|
2763
|
+
return new Uint8Array(result);
|
|
2764
|
+
}, false);
|
|
2765
|
+
defineReadonlyValue(handle, 'writeBytes', async (content) => {
|
|
2766
|
+
assertWritable(state.mode);
|
|
2767
|
+
const snapshot = cloneBytes(content);
|
|
2768
|
+
await this.requester.request(FILE_WRITE_BYTES_METHOD, { target: state.ref, content: snapshot });
|
|
2769
|
+
}, false);
|
|
2770
|
+
defineReadonlyValue(handle, 'stat', async () => {
|
|
2771
|
+
const result = await this.requester.request(FILE_STAT_METHOD, { target: state.ref });
|
|
2772
|
+
return normalizeStat(result);
|
|
2773
|
+
}, false);
|
|
2774
|
+
this.fileStates.set(handle, state);
|
|
2775
|
+
brandedFileSystemValues.add(handle);
|
|
2776
|
+
return Object.freeze(handle);
|
|
2777
|
+
}
|
|
2778
|
+
createDirectFile(descriptor) {
|
|
2779
|
+
this.assertFileDescriptor(descriptor);
|
|
2780
|
+
if (!('handleId' in descriptor.ref)) {
|
|
2781
|
+
throw createSDKError('FILE_IO_FAILED', 'Host 返回的 File 不是精确文件授权');
|
|
2782
|
+
}
|
|
2783
|
+
return this.createFile(descriptor);
|
|
2784
|
+
}
|
|
2785
|
+
createDirectory(descriptor) {
|
|
2786
|
+
this.assertDirectoryDescriptor(descriptor);
|
|
2787
|
+
const ref = cloneDirectoryRef(descriptor.ref);
|
|
2788
|
+
const state = { ref, mode: descriptor.mode };
|
|
2789
|
+
const pathRootState = 'handleId' in ref ? { root: ref, prefix: '', mode: descriptor.mode } : { root: ref.root, prefix: ref.relativePath, mode: descriptor.mode };
|
|
2790
|
+
const handle = {};
|
|
2791
|
+
defineReadonlyValue(handle, 'kind', 'directory');
|
|
2792
|
+
defineReadonlyValue(handle, 'name', descriptor.name);
|
|
2793
|
+
defineReadonlyValue(handle, 'mode', descriptor.mode);
|
|
2794
|
+
this.definePathRootMethods(handle, pathRootState);
|
|
2795
|
+
defineReadonlyValue(handle, 'create', async (options) => {
|
|
2796
|
+
assertWritable(state.mode);
|
|
2797
|
+
await this.requester.request(DIRECTORY_CREATE_METHOD, {
|
|
2798
|
+
target: state.ref,
|
|
2799
|
+
...normalizeCreateOptions(options),
|
|
2800
|
+
});
|
|
2801
|
+
return handle;
|
|
2802
|
+
}, false);
|
|
2803
|
+
defineReadonlyValue(handle, 'remove', async (options) => {
|
|
2804
|
+
assertWritable(state.mode);
|
|
2805
|
+
assertSandboxRef(state.ref);
|
|
2806
|
+
await this.requester.request(DIRECTORY_REMOVE_METHOD, {
|
|
2807
|
+
target: state.ref,
|
|
2808
|
+
...normalizeRemoveOptions(options),
|
|
2809
|
+
});
|
|
2810
|
+
}, false);
|
|
2811
|
+
defineReadonlyValue(handle, 'exists', async () => {
|
|
2812
|
+
const result = await this.requester.request(DIRECTORY_EXISTS_METHOD, { target: state.ref });
|
|
2813
|
+
if (typeof result !== 'boolean') {
|
|
2814
|
+
throw createSDKError('FILE_IO_FAILED', 'Host 返回了无效的 exists 结果');
|
|
2815
|
+
}
|
|
2816
|
+
return result;
|
|
2817
|
+
}, false);
|
|
2818
|
+
defineReadonlyValue(handle, 'list', async (options) => {
|
|
2819
|
+
const limit = normalizeListOptions(options);
|
|
2820
|
+
const result = await this.requester.request(DIRECTORY_LIST_METHOD, {
|
|
2821
|
+
target: state.ref,
|
|
2822
|
+
...(limit === undefined ? {} : { limit }),
|
|
2823
|
+
});
|
|
2824
|
+
if (!Array.isArray(result)) {
|
|
2825
|
+
throw createSDKError('FILE_IO_FAILED', 'Host 返回了无效的目录列表');
|
|
2826
|
+
}
|
|
2827
|
+
if (result.some((entry) => entry?.mode !== state.mode)) {
|
|
2828
|
+
throw createSDKError('FILE_IO_FAILED', 'Host 返回的目录项未继承父目录 mode');
|
|
2829
|
+
}
|
|
2830
|
+
return result.map((entry) => this.createEntity(entry));
|
|
2831
|
+
}, false);
|
|
2832
|
+
this.directoryStates.set(handle, state);
|
|
2833
|
+
this.pathRootStates.set(handle, pathRootState);
|
|
2834
|
+
brandedFileSystemValues.add(handle);
|
|
2835
|
+
return Object.freeze(handle);
|
|
2836
|
+
}
|
|
2837
|
+
createDirectDirectory(descriptor) {
|
|
2838
|
+
this.assertDirectoryDescriptor(descriptor);
|
|
2839
|
+
if (!('handleId' in descriptor.ref)) {
|
|
2840
|
+
throw createSDKError('FILE_IO_FAILED', 'Host 返回的 Directory 不是精确目录授权');
|
|
2841
|
+
}
|
|
2842
|
+
return this.createDirectory(descriptor);
|
|
2843
|
+
}
|
|
2844
|
+
createEntity(descriptor) {
|
|
2845
|
+
if (descriptor?.kind === 'file') {
|
|
2846
|
+
return this.createFile(descriptor);
|
|
2847
|
+
}
|
|
2848
|
+
if (descriptor?.kind === 'directory') {
|
|
2849
|
+
return this.createDirectory(descriptor);
|
|
2850
|
+
}
|
|
2851
|
+
throw createSDKError('FILE_IO_FAILED', 'Host 返回了无效的文件实体');
|
|
2852
|
+
}
|
|
2853
|
+
requireFile(handle) {
|
|
2854
|
+
const state = handle && typeof handle === 'object' ? this.fileStates.get(handle) : undefined;
|
|
2855
|
+
if (!state) {
|
|
2856
|
+
throw invalidParams$1('to 必须是当前 SDK session 创建的 FileHandle');
|
|
2857
|
+
}
|
|
2858
|
+
return state;
|
|
2859
|
+
}
|
|
2860
|
+
requireDirectory(handle) {
|
|
2861
|
+
const state = handle && typeof handle === 'object' ? this.directoryStates.get(handle) : undefined;
|
|
2862
|
+
if (!state) {
|
|
2863
|
+
throw invalidParams$1('to 必须是当前 SDK session 创建的 DirectoryHandle');
|
|
2864
|
+
}
|
|
2865
|
+
return state;
|
|
2866
|
+
}
|
|
2867
|
+
definePathRootMethods(target, state) {
|
|
2868
|
+
defineReadonlyValue(target, 'file', (relativePath) => {
|
|
2869
|
+
const normalized = normalizeRelativePath(relativePath);
|
|
2870
|
+
const fullPath = joinRelativePath(state.prefix, normalized);
|
|
2871
|
+
return this.createFile({
|
|
2872
|
+
kind: 'file',
|
|
2873
|
+
name: basename(normalized),
|
|
2874
|
+
mode: state.mode,
|
|
2875
|
+
ref: {
|
|
2876
|
+
kind: 'file',
|
|
2877
|
+
root: state.root,
|
|
2878
|
+
relativePath: fullPath,
|
|
2879
|
+
},
|
|
2880
|
+
});
|
|
2881
|
+
}, false);
|
|
2882
|
+
defineReadonlyValue(target, 'directory', (relativePath) => {
|
|
2883
|
+
const normalized = normalizeRelativePath(relativePath);
|
|
2884
|
+
const fullPath = joinRelativePath(state.prefix, normalized);
|
|
2885
|
+
return this.createDirectory({
|
|
2886
|
+
kind: 'directory',
|
|
2887
|
+
name: basename(normalized),
|
|
2888
|
+
mode: state.mode,
|
|
2889
|
+
ref: {
|
|
2890
|
+
kind: 'directory',
|
|
2891
|
+
root: state.root,
|
|
2892
|
+
relativePath: fullPath,
|
|
2893
|
+
},
|
|
2894
|
+
});
|
|
2895
|
+
}, false);
|
|
2896
|
+
}
|
|
2897
|
+
assertFileDescriptor(descriptor) {
|
|
2898
|
+
if (!descriptor || descriptor.kind !== 'file') {
|
|
2899
|
+
throw createSDKError('FILE_IO_FAILED', 'Host 返回了无效的 File descriptor');
|
|
2900
|
+
}
|
|
2901
|
+
assertName(descriptor.name);
|
|
2902
|
+
assertMode(descriptor.mode);
|
|
2903
|
+
assertFileRef(descriptor.ref);
|
|
2904
|
+
}
|
|
2905
|
+
assertDirectoryDescriptor(descriptor) {
|
|
2906
|
+
if (!descriptor || descriptor.kind !== 'directory') {
|
|
2907
|
+
throw createSDKError('FILE_IO_FAILED', 'Host 返回了无效的 Directory descriptor');
|
|
2908
|
+
}
|
|
2909
|
+
assertName(descriptor.name);
|
|
2910
|
+
assertMode(descriptor.mode);
|
|
2911
|
+
assertDirectoryRef(descriptor.ref);
|
|
2912
|
+
}
|
|
2913
|
+
}
|
|
2914
|
+
function getFileHandleRegistry(requester) {
|
|
2915
|
+
let registry = registries.get(requester);
|
|
2916
|
+
if (!registry) {
|
|
2917
|
+
registry = new MiniProgramFileHandleRegistry(requester);
|
|
2918
|
+
registries.set(requester, registry);
|
|
2919
|
+
}
|
|
2920
|
+
return registry;
|
|
2921
|
+
}
|
|
2922
|
+
function isMiniProgramFileSystemValue(value) {
|
|
2923
|
+
return !!value && typeof value === 'object' && brandedFileSystemValues.has(value);
|
|
2924
|
+
}
|
|
2324
2925
|
|
|
2325
2926
|
const LOG_PREFIX = '[hb-sdk][network.request]';
|
|
2326
2927
|
/**
|
|
@@ -2393,13 +2994,13 @@ function formatNetworkRequestFailureMessage(detail) {
|
|
|
2393
2994
|
return `${detail.kind} ${detail.method} ${detail.url}${statusPart}${codePart}`;
|
|
2394
2995
|
}
|
|
2395
2996
|
|
|
2396
|
-
const DEFAULT_VALIDATE_STATUS = status => status >= 200 && status < 300;
|
|
2997
|
+
const DEFAULT_VALIDATE_STATUS = (status) => status >= 200 && status < 300;
|
|
2397
2998
|
function isPlainObject(value) {
|
|
2398
2999
|
return Object.prototype.toString.call(value) === '[object Object]';
|
|
2399
3000
|
}
|
|
2400
3001
|
function clonePublicValue(value) {
|
|
2401
3002
|
if (Array.isArray(value)) {
|
|
2402
|
-
return value.map(item => clonePublicValue(item));
|
|
3003
|
+
return value.map((item) => clonePublicValue(item));
|
|
2403
3004
|
}
|
|
2404
3005
|
if (isPlainObject(value)) {
|
|
2405
3006
|
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, clonePublicValue(item)]));
|
|
@@ -2453,11 +3054,11 @@ function toNetworkResponse(payload, config) {
|
|
|
2453
3054
|
/**
|
|
2454
3055
|
* 发起网络请求并返回标准化响应。
|
|
2455
3056
|
*
|
|
2456
|
-
* @param requester 底层 bridge 请求能力。
|
|
2457
|
-
* @param config 面向业务层的网络请求配置。
|
|
3057
|
+
* @param requester - 底层 bridge 请求能力。
|
|
3058
|
+
* @param config - 面向业务层的网络请求配置。
|
|
2458
3059
|
* @returns 标准化网络响应。HTTP 2xx 默认返回 resolve。
|
|
2459
|
-
* @throws {HbMiniProgramNetworkError} 当请求已完成但 HTTP 状态不满足 `validateStatus` 时抛出。
|
|
2460
|
-
* @throws {HbMiniProgramSDKError} 当 bridge、运行时或宿主能力调用失败时抛出。
|
|
3060
|
+
* @throws {@link HbMiniProgramNetworkError} 当请求已完成但 HTTP 状态不满足 `validateStatus` 时抛出。
|
|
3061
|
+
* @throws {@link HbMiniProgramSDKError} 当 bridge、运行时或宿主能力调用失败时抛出。
|
|
2461
3062
|
*
|
|
2462
3063
|
* @remarks
|
|
2463
3064
|
* `validateStatus` 仅在 SDK 侧执行,不会跨 bridge 传输函数值。
|
|
@@ -2475,7 +3076,7 @@ async function request(requester, config) {
|
|
|
2475
3076
|
const validateStatus = config.validateStatus || DEFAULT_VALIDATE_STATUS;
|
|
2476
3077
|
try {
|
|
2477
3078
|
assertSupportedPublicNetworkRequest(config);
|
|
2478
|
-
const responsePayload = await requester.request(NETWORK_REQUEST_METHOD, toRequestPayload(config));
|
|
3079
|
+
const responsePayload = (await requester.request(NETWORK_REQUEST_METHOD, toRequestPayload(config)));
|
|
2479
3080
|
const response = toNetworkResponse(responsePayload, config);
|
|
2480
3081
|
if (!validateStatus(response.status)) {
|
|
2481
3082
|
const error = new HbMiniProgramNetworkError(response);
|
|
@@ -2523,25 +3124,319 @@ function assertSupportedPublicNetworkRequest(config) {
|
|
|
2523
3124
|
if (isUnsupportedMultipartNetworkRequest(config)) {
|
|
2524
3125
|
throw createSDKError('INVALID_PARAMS', NETWORK_REQUEST_MULTIPART_UNSUPPORTED_MESSAGE);
|
|
2525
3126
|
}
|
|
3127
|
+
if (containsUnsupportedNetworkData(config.data)) {
|
|
3128
|
+
throw createSDKError('INVALID_PARAMS', 'network.request data 不支持 FileHandle、FileSystem、Blob、FormData 或二进制数据');
|
|
3129
|
+
}
|
|
3130
|
+
}
|
|
3131
|
+
function containsUnsupportedNetworkData(value, visiting = new WeakSet(), scanned = new WeakSet()) {
|
|
3132
|
+
if (isMiniProgramFileSystemValue(value))
|
|
3133
|
+
return true;
|
|
3134
|
+
if (typeof Blob !== 'undefined' && value instanceof Blob)
|
|
3135
|
+
return true;
|
|
3136
|
+
if (typeof FormData !== 'undefined' && value instanceof FormData)
|
|
3137
|
+
return true;
|
|
3138
|
+
if (value instanceof ArrayBuffer || ArrayBuffer.isView(value))
|
|
3139
|
+
return true;
|
|
3140
|
+
if (typeof SharedArrayBuffer !== 'undefined' && value instanceof SharedArrayBuffer)
|
|
3141
|
+
return true;
|
|
3142
|
+
if (!value || typeof value !== 'object' || value instanceof URLSearchParams)
|
|
3143
|
+
return false;
|
|
3144
|
+
if (visiting.has(value))
|
|
3145
|
+
return true;
|
|
3146
|
+
if (scanned.has(value))
|
|
3147
|
+
return false;
|
|
3148
|
+
visiting.add(value);
|
|
3149
|
+
let unsupported = false;
|
|
3150
|
+
if (Array.isArray(value))
|
|
3151
|
+
unsupported = value.some((item) => containsUnsupportedNetworkData(item, visiting, scanned));
|
|
3152
|
+
if (isPlainObject(value)) {
|
|
3153
|
+
unsupported ||= Object.values(value).some((item) => containsUnsupportedNetworkData(item, visiting, scanned));
|
|
3154
|
+
}
|
|
3155
|
+
visiting.delete(value);
|
|
3156
|
+
if (!unsupported)
|
|
3157
|
+
scanned.add(value);
|
|
3158
|
+
return unsupported;
|
|
3159
|
+
}
|
|
3160
|
+
function assertFinitePositive(value, name) {
|
|
3161
|
+
if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0) {
|
|
3162
|
+
throw createSDKError('INVALID_PARAMS', `${name} 必须是有限正数`);
|
|
3163
|
+
}
|
|
3164
|
+
}
|
|
3165
|
+
function normalizeDownloadProgress(value) {
|
|
3166
|
+
if (!value || typeof value !== 'object') {
|
|
3167
|
+
throw createSDKError('INVALID_NETWORK_RESPONSE', 'network.download 返回了无效的进度');
|
|
3168
|
+
}
|
|
3169
|
+
if (!isMiniProgramDownloadProgressPayload(value)) {
|
|
3170
|
+
throw createSDKError('INVALID_NETWORK_RESPONSE', 'network.download 返回了无效的进度');
|
|
3171
|
+
}
|
|
3172
|
+
return {
|
|
3173
|
+
loaded: value.loaded,
|
|
3174
|
+
...(value.total === undefined ? {} : { total: value.total }),
|
|
3175
|
+
lengthComputable: value.lengthComputable,
|
|
3176
|
+
};
|
|
3177
|
+
}
|
|
3178
|
+
function normalizeDownloadPayload(options, to, isFileTarget) {
|
|
3179
|
+
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
|
3180
|
+
throw createSDKError('INVALID_PARAMS', 'network.download options 必须是对象');
|
|
3181
|
+
}
|
|
3182
|
+
if (typeof options.url !== 'string' || options.url.length === 0) {
|
|
3183
|
+
throw createSDKError('INVALID_PARAMS', 'url 必须是非空字符串');
|
|
3184
|
+
}
|
|
3185
|
+
if (options.params !== undefined && !isPlainObject(options.params)) {
|
|
3186
|
+
throw createSDKError('INVALID_PARAMS', 'params 必须是对象');
|
|
3187
|
+
}
|
|
3188
|
+
if (options.headers !== undefined) {
|
|
3189
|
+
if (!isPlainObject(options.headers) || Object.values(options.headers).some((value) => typeof value !== 'string')) {
|
|
3190
|
+
throw createSDKError('INVALID_PARAMS', 'headers 必须是字符串字典');
|
|
3191
|
+
}
|
|
3192
|
+
}
|
|
3193
|
+
if (options.timeout !== undefined) {
|
|
3194
|
+
assertFinitePositive(options.timeout, 'timeout');
|
|
3195
|
+
}
|
|
3196
|
+
if (options.maxBytes !== undefined && (!Number.isSafeInteger(options.maxBytes) || options.maxBytes <= 0)) {
|
|
3197
|
+
throw createSDKError('INVALID_PARAMS', 'maxBytes 必须是正的 safe integer');
|
|
3198
|
+
}
|
|
3199
|
+
if (options.withCredentials !== undefined && typeof options.withCredentials !== 'boolean') {
|
|
3200
|
+
throw createSDKError('INVALID_PARAMS', 'withCredentials 必须是 boolean');
|
|
3201
|
+
}
|
|
3202
|
+
if (options.onProgress !== undefined && typeof options.onProgress !== 'function') {
|
|
3203
|
+
throw createSDKError('INVALID_PARAMS', 'onProgress 必须是函数');
|
|
3204
|
+
}
|
|
3205
|
+
if (options.signal !== undefined &&
|
|
3206
|
+
(typeof options.signal !== 'object' ||
|
|
3207
|
+
typeof options.signal.aborted !== 'boolean' ||
|
|
3208
|
+
typeof options.signal.addEventListener !== 'function' ||
|
|
3209
|
+
typeof options.signal.removeEventListener !== 'function')) {
|
|
3210
|
+
throw createSDKError('INVALID_PARAMS', 'signal 必须是 AbortSignal');
|
|
3211
|
+
}
|
|
3212
|
+
if ('method' in options || 'data' in options || 'body' in options) {
|
|
3213
|
+
throw createSDKError('INVALID_PARAMS', 'network.download 固定使用 GET 且不接受 body');
|
|
3214
|
+
}
|
|
3215
|
+
const base = {
|
|
3216
|
+
url: options.url,
|
|
3217
|
+
to,
|
|
3218
|
+
...(options.params === undefined ? {} : { params: clonePublicValue(options.params) }),
|
|
3219
|
+
...(options.headers === undefined ? {} : { headers: clonePublicValue(options.headers) }),
|
|
3220
|
+
...(options.timeout === undefined ? {} : { timeout: options.timeout }),
|
|
3221
|
+
...(options.withCredentials === undefined ? {} : { withCredentials: options.withCredentials }),
|
|
3222
|
+
...(options.maxBytes === undefined ? {} : { maxBytes: options.maxBytes }),
|
|
3223
|
+
};
|
|
3224
|
+
if (isFileTarget) {
|
|
3225
|
+
if (options.suggestedName !== undefined || options.overwrite !== undefined) {
|
|
3226
|
+
throw createSDKError('INVALID_PARAMS', 'File target 不接受 suggestedName 或 overwrite');
|
|
3227
|
+
}
|
|
3228
|
+
return base;
|
|
3229
|
+
}
|
|
3230
|
+
if (options.overwrite !== undefined && typeof options.overwrite !== 'boolean') {
|
|
3231
|
+
throw createSDKError('INVALID_PARAMS', 'overwrite 必须是 boolean');
|
|
3232
|
+
}
|
|
3233
|
+
let suggestedName;
|
|
3234
|
+
if (options.suggestedName !== undefined) {
|
|
3235
|
+
suggestedName = normalizeRelativePath(options.suggestedName);
|
|
3236
|
+
if (suggestedName.includes('/')) {
|
|
3237
|
+
throw createSDKError('INVALID_PARAMS', 'suggestedName 必须是 basename');
|
|
3238
|
+
}
|
|
3239
|
+
}
|
|
3240
|
+
return {
|
|
3241
|
+
...base,
|
|
3242
|
+
...(suggestedName === undefined ? {} : { suggestedName }),
|
|
3243
|
+
...(options.overwrite === undefined ? {} : { overwrite: options.overwrite }),
|
|
3244
|
+
};
|
|
3245
|
+
}
|
|
3246
|
+
function isSamePathRoot(left, right) {
|
|
3247
|
+
if (left.kind !== right.kind)
|
|
3248
|
+
return false;
|
|
3249
|
+
return left.kind === 'sandbox' || (right.kind === 'directory' && left.handleId === right.handleId);
|
|
3250
|
+
}
|
|
3251
|
+
function isSameFileRef(left, right) {
|
|
3252
|
+
if ('handleId' in left || 'handleId' in right) {
|
|
3253
|
+
return 'handleId' in left && 'handleId' in right && left.handleId === right.handleId;
|
|
3254
|
+
}
|
|
3255
|
+
return left.relativePath === right.relativePath && isSamePathRoot(left.root, right.root);
|
|
3256
|
+
}
|
|
3257
|
+
function isDirectChildFileRef(directory, file) {
|
|
3258
|
+
if ('handleId' in file)
|
|
3259
|
+
return false;
|
|
3260
|
+
if ('handleId' in directory) {
|
|
3261
|
+
return file.root.kind === 'directory' && file.root.handleId === directory.handleId && !file.relativePath.includes('/');
|
|
3262
|
+
}
|
|
3263
|
+
if (!isSamePathRoot(directory.root, file.root))
|
|
3264
|
+
return false;
|
|
3265
|
+
const prefix = `${directory.relativePath}/`;
|
|
3266
|
+
if (!file.relativePath.startsWith(prefix))
|
|
3267
|
+
return false;
|
|
3268
|
+
const childName = file.relativePath.slice(prefix.length);
|
|
3269
|
+
return childName.length > 0 && !childName.includes('/');
|
|
3270
|
+
}
|
|
3271
|
+
function invalidDownloadResult(message) {
|
|
3272
|
+
throw createSDKError('INVALID_NETWORK_RESPONSE', message);
|
|
3273
|
+
}
|
|
3274
|
+
/** 发起不使用 bridge 固定总时长 timer 的流式下载。 */
|
|
3275
|
+
async function download(requester, options) {
|
|
3276
|
+
if (options?.signal?.aborted) {
|
|
3277
|
+
throw createSDKError('DOWNLOAD_CANCELLED', '下载已取消');
|
|
3278
|
+
}
|
|
3279
|
+
const registry = getFileHandleRegistry(requester);
|
|
3280
|
+
const isFileTarget = options?.to?.kind === 'file';
|
|
3281
|
+
const target = isFileTarget ? registry.requireFile(options?.to) : registry.requireDirectory(options?.to);
|
|
3282
|
+
if (target.mode !== 'readwrite') {
|
|
3283
|
+
throw createSDKError('FILE_ACCESS_DENIED', '下载 target 必须是 readwrite');
|
|
3284
|
+
}
|
|
3285
|
+
const payload = normalizeDownloadPayload(options, target.ref, isFileTarget);
|
|
3286
|
+
const result = await requester.requestOperation(NETWORK_DOWNLOAD_METHOD, payload, {
|
|
3287
|
+
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
3288
|
+
...(options.onProgress === undefined
|
|
3289
|
+
? {}
|
|
3290
|
+
: {
|
|
3291
|
+
onProgress: (progress) => {
|
|
3292
|
+
options.onProgress?.(normalizeDownloadProgress(progress));
|
|
3293
|
+
},
|
|
3294
|
+
}),
|
|
3295
|
+
createAbortError: () => createSDKError('DOWNLOAD_CANCELLED', '下载已取消'),
|
|
3296
|
+
});
|
|
3297
|
+
const resultHandle = registry.createFile(result);
|
|
3298
|
+
const resultState = registry.requireFile(resultHandle);
|
|
3299
|
+
if (resultHandle.mode !== 'readwrite') {
|
|
3300
|
+
invalidDownloadResult('network.download 返回的 File 不是 readwrite');
|
|
3301
|
+
}
|
|
3302
|
+
if (isFileTarget) {
|
|
3303
|
+
const original = options.to;
|
|
3304
|
+
if (resultHandle.name !== original.name || !isSameFileRef(target.ref, resultState.ref)) {
|
|
3305
|
+
invalidDownloadResult('network.download 返回的 File 与 target 不一致');
|
|
3306
|
+
}
|
|
3307
|
+
return original;
|
|
3308
|
+
}
|
|
3309
|
+
if (!isDirectChildFileRef(target.ref, resultState.ref) ||
|
|
3310
|
+
'handleId' in resultState.ref ||
|
|
3311
|
+
resultHandle.name !== resultState.ref.relativePath.split('/').at(-1)) {
|
|
3312
|
+
invalidDownloadResult('network.download 返回的 File 不在 target Directory 内');
|
|
3313
|
+
}
|
|
3314
|
+
return resultHandle;
|
|
2526
3315
|
}
|
|
2527
3316
|
/**
|
|
2528
3317
|
* 创建 network 模块。
|
|
2529
3318
|
*
|
|
2530
|
-
* @param requester 底层 bridge 请求能力。
|
|
3319
|
+
* @param requester - 底层 bridge 请求能力。
|
|
2531
3320
|
* @returns 面向业务层的网络模块对象。
|
|
2532
3321
|
*/
|
|
2533
3322
|
function createNetworkModule(requester) {
|
|
2534
3323
|
return {
|
|
2535
|
-
request: config => request(requester, config),
|
|
3324
|
+
request: (config) => request(requester, config),
|
|
3325
|
+
download: (options) => download(requester, options),
|
|
2536
3326
|
};
|
|
2537
3327
|
}
|
|
2538
3328
|
|
|
3329
|
+
function invalidParams(message) {
|
|
3330
|
+
return createSDKError('INVALID_PARAMS', message);
|
|
3331
|
+
}
|
|
3332
|
+
function normalizeMode(mode) {
|
|
3333
|
+
if (mode === undefined) {
|
|
3334
|
+
return undefined;
|
|
3335
|
+
}
|
|
3336
|
+
if (mode !== 'read' && mode !== 'readwrite') {
|
|
3337
|
+
throw invalidParams('mode 必须是 read 或 readwrite');
|
|
3338
|
+
}
|
|
3339
|
+
return mode;
|
|
3340
|
+
}
|
|
3341
|
+
function assertOptionsObject(value, name) {
|
|
3342
|
+
if (value !== undefined && (!value || typeof value !== 'object' || Array.isArray(value))) {
|
|
3343
|
+
throw invalidParams(`${name} 必须是对象`);
|
|
3344
|
+
}
|
|
3345
|
+
}
|
|
3346
|
+
function normalizeAccept(accept) {
|
|
3347
|
+
if (accept === undefined) {
|
|
3348
|
+
return undefined;
|
|
3349
|
+
}
|
|
3350
|
+
if (!Array.isArray(accept)) {
|
|
3351
|
+
throw invalidParams('accept 必须是扩展名数组');
|
|
3352
|
+
}
|
|
3353
|
+
return accept.map((extension) => {
|
|
3354
|
+
if (typeof extension !== 'string' ||
|
|
3355
|
+
!/^\.[a-z0-9][a-z0-9._-]*$/i.test(extension)) {
|
|
3356
|
+
throw invalidParams('accept 只能包含规范扩展名,例如 .json');
|
|
3357
|
+
}
|
|
3358
|
+
return extension;
|
|
3359
|
+
});
|
|
3360
|
+
}
|
|
3361
|
+
function normalizePickFilesOptions(options) {
|
|
3362
|
+
assertOptionsObject(options, 'pickFiles options');
|
|
3363
|
+
if (options?.multiple !== undefined && typeof options.multiple !== 'boolean') {
|
|
3364
|
+
throw invalidParams('multiple 必须是 boolean');
|
|
3365
|
+
}
|
|
3366
|
+
const mode = normalizeMode(options?.mode);
|
|
3367
|
+
const accept = normalizeAccept(options?.accept);
|
|
3368
|
+
if (options === undefined) {
|
|
3369
|
+
return undefined;
|
|
3370
|
+
}
|
|
3371
|
+
return {
|
|
3372
|
+
...(mode === undefined ? {} : { mode }),
|
|
3373
|
+
...(accept === undefined ? {} : { accept }),
|
|
3374
|
+
...(options.multiple === undefined ? {} : { multiple: options.multiple }),
|
|
3375
|
+
};
|
|
3376
|
+
}
|
|
3377
|
+
function normalizePickDirectoryOptions(options) {
|
|
3378
|
+
assertOptionsObject(options, 'pickDirectory options');
|
|
3379
|
+
const mode = normalizeMode(options?.mode);
|
|
3380
|
+
return options === undefined ? undefined : mode === undefined ? {} : { mode };
|
|
3381
|
+
}
|
|
3382
|
+
function normalizeSaveFileOptions(options) {
|
|
3383
|
+
assertOptionsObject(options, 'saveFile options');
|
|
3384
|
+
if (!options || typeof options.suggestedName !== 'string') {
|
|
3385
|
+
throw invalidParams('suggestedName 必须是非空字符串');
|
|
3386
|
+
}
|
|
3387
|
+
const suggestedName = normalizeRelativePath(options.suggestedName);
|
|
3388
|
+
if (suggestedName.includes('/')) {
|
|
3389
|
+
throw invalidParams('suggestedName 必须是 basename');
|
|
3390
|
+
}
|
|
3391
|
+
if ('accept' in options) {
|
|
3392
|
+
throw invalidParams('saveFile V1 不支持 accept');
|
|
3393
|
+
}
|
|
3394
|
+
return { suggestedName };
|
|
3395
|
+
}
|
|
3396
|
+
/** 创建当前 SDK session 的 files 模块。 */
|
|
3397
|
+
function createFilesModule(requester) {
|
|
3398
|
+
const registry = getFileHandleRegistry(requester);
|
|
3399
|
+
return Object.freeze({
|
|
3400
|
+
sandbox: registry.getSandbox(),
|
|
3401
|
+
async pickFiles(options) {
|
|
3402
|
+
const normalizedOptions = normalizePickFilesOptions(options);
|
|
3403
|
+
const descriptors = await requester.request(FILES_PICK_FILES_METHOD, normalizedOptions);
|
|
3404
|
+
if (!Array.isArray(descriptors) || descriptors.length === 0 || (normalizedOptions?.multiple !== true && descriptors.length > 1)) {
|
|
3405
|
+
throw createSDKError('FILE_IO_FAILED', 'Host 返回了无效的 picker 结果');
|
|
3406
|
+
}
|
|
3407
|
+
const expectedMode = normalizedOptions?.mode ?? 'read';
|
|
3408
|
+
const handles = descriptors.map((descriptor) => registry.createDirectFile(descriptor));
|
|
3409
|
+
if (handles.some((handle) => handle.mode !== expectedMode)) {
|
|
3410
|
+
throw createSDKError('FILE_IO_FAILED', 'Host 返回的 File mode 与 picker 请求不一致');
|
|
3411
|
+
}
|
|
3412
|
+
return handles;
|
|
3413
|
+
},
|
|
3414
|
+
async pickDirectory(options) {
|
|
3415
|
+
const normalizedOptions = normalizePickDirectoryOptions(options);
|
|
3416
|
+
const descriptor = await requester.request(FILES_PICK_DIRECTORY_METHOD, normalizedOptions);
|
|
3417
|
+
const handle = registry.createDirectDirectory(descriptor);
|
|
3418
|
+
if (handle.mode !== (normalizedOptions?.mode ?? 'read')) {
|
|
3419
|
+
throw createSDKError('FILE_IO_FAILED', 'Host 返回的 Directory mode 与 picker 请求不一致');
|
|
3420
|
+
}
|
|
3421
|
+
return handle;
|
|
3422
|
+
},
|
|
3423
|
+
async saveFile(options) {
|
|
3424
|
+
const descriptor = await requester.request(FILES_SAVE_FILE_METHOD, normalizeSaveFileOptions(options));
|
|
3425
|
+
const handle = registry.createDirectFile(descriptor);
|
|
3426
|
+
if (handle.mode !== 'readwrite') {
|
|
3427
|
+
throw createSDKError('FILE_IO_FAILED', 'Host 返回的 saveFile 不是 readwrite 授权');
|
|
3428
|
+
}
|
|
3429
|
+
return handle;
|
|
3430
|
+
},
|
|
3431
|
+
});
|
|
3432
|
+
}
|
|
3433
|
+
|
|
2539
3434
|
/**
|
|
2540
3435
|
* 获取当前小程序窗口信息。
|
|
2541
3436
|
*
|
|
2542
|
-
* @param requester 底层 bridge 请求能力。
|
|
3437
|
+
* @param requester - 底层 bridge 请求能力。
|
|
2543
3438
|
* @returns 当前小程序可用窗口信息。
|
|
2544
|
-
* @throws {HbMiniProgramSDKError} 当 bridge、父容器或宿主能力调用失败时抛出。
|
|
3439
|
+
* @throws {@link HbMiniProgramSDKError} 当 bridge、父容器或宿主能力调用失败时抛出。
|
|
2545
3440
|
*/
|
|
2546
3441
|
function getWindowInfo(requester) {
|
|
2547
3442
|
return requester.request(VIEWPORT_GET_WINDOW_INFO_METHOD);
|
|
@@ -2549,10 +3444,10 @@ function getWindowInfo(requester) {
|
|
|
2549
3444
|
/**
|
|
2550
3445
|
* 设置导航栏关闭按钮与状态栏图标/文字的前景样式。
|
|
2551
3446
|
*
|
|
2552
|
-
* @param requester 底层 bridge 请求能力。
|
|
2553
|
-
* @param options 导航栏样式配置。
|
|
3447
|
+
* @param requester - 底层 bridge 请求能力。
|
|
3448
|
+
* @param options - 导航栏样式配置。
|
|
2554
3449
|
* @returns 宿主接受设置后 resolve。
|
|
2555
|
-
* @throws {HbMiniProgramSDKError} 当 bridge、父容器或宿主能力调用失败时抛出。
|
|
3450
|
+
* @throws {@link HbMiniProgramSDKError} 当 bridge、父容器或宿主能力调用失败时抛出。
|
|
2556
3451
|
*/
|
|
2557
3452
|
function setNavigationBarStyle(requester, options) {
|
|
2558
3453
|
return requester.request(VIEWPORT_SET_NAVIGATION_BAR_STYLE_METHOD, options);
|
|
@@ -2560,13 +3455,13 @@ function setNavigationBarStyle(requester, options) {
|
|
|
2560
3455
|
/**
|
|
2561
3456
|
* 创建 Viewport 模块。
|
|
2562
3457
|
*
|
|
2563
|
-
* @param requester 底层 bridge 请求能力。
|
|
3458
|
+
* @param requester - 底层 bridge 请求能力。
|
|
2564
3459
|
* @returns 面向业务层的 Viewport 模块对象。
|
|
2565
3460
|
*/
|
|
2566
3461
|
function createViewportModule(requester) {
|
|
2567
3462
|
return {
|
|
2568
3463
|
getWindowInfo: () => getWindowInfo(requester),
|
|
2569
|
-
setNavigationBarStyle: options => setNavigationBarStyle(requester, options),
|
|
3464
|
+
setNavigationBarStyle: (options) => setNavigationBarStyle(requester, options),
|
|
2570
3465
|
};
|
|
2571
3466
|
}
|
|
2572
3467
|
|
|
@@ -2579,7 +3474,7 @@ function createViewportModule(requester) {
|
|
|
2579
3474
|
* `app_user_id`,并隐式授予 `identity` 与 `profile` 后返回昵称与头像,不展示授权 UI。未登录时返回
|
|
2580
3475
|
* `{ isHeyboxAppLoggedIn: false, authorization: null, userInfo: null }`。
|
|
2581
3476
|
*
|
|
2582
|
-
* @throws {HbMiniProgramSDKError} 当 SDK 调用失败时抛出。
|
|
3477
|
+
* @throws {@link HbMiniProgramSDKError} 当 SDK 调用失败时抛出。
|
|
2583
3478
|
*/
|
|
2584
3479
|
function getInfo(requester) {
|
|
2585
3480
|
return requester.request(USER_GET_INFO_METHOD);
|
|
@@ -2592,8 +3487,8 @@ function revokeAuthorization(requester) {
|
|
|
2592
3487
|
/**
|
|
2593
3488
|
* 获取当前用户 Steam 游戏库。
|
|
2594
3489
|
*
|
|
2595
|
-
* @param requester 底层 bridge 请求能力。
|
|
2596
|
-
* @param options 查询与分页参数。
|
|
3490
|
+
* @param requester - 底层 bridge 请求能力。
|
|
3491
|
+
* @param options - 查询与分页参数。
|
|
2597
3492
|
* @returns 当前用户 Steam 游戏库;未登录或未绑定 Steam 时返回状态对象。
|
|
2598
3493
|
*/
|
|
2599
3494
|
function getSteamGameList(requester, options) {
|
|
@@ -2623,8 +3518,8 @@ function hideLoading(requester) {
|
|
|
2623
3518
|
/** 创建 UI 模块。 */
|
|
2624
3519
|
function createUiModule(requester) {
|
|
2625
3520
|
return {
|
|
2626
|
-
showToast: options => showToast(requester, options),
|
|
2627
|
-
showLoading: options => showLoading(requester, options),
|
|
3521
|
+
showToast: (options) => showToast(requester, options),
|
|
3522
|
+
showLoading: (options) => showLoading(requester, options),
|
|
2628
3523
|
hideLoading: () => hideLoading(requester),
|
|
2629
3524
|
};
|
|
2630
3525
|
}
|
|
@@ -2640,8 +3535,8 @@ function setClipboard(requester, options) {
|
|
|
2640
3535
|
/** 创建设备能力模块。 */
|
|
2641
3536
|
function createDeviceModule(requester) {
|
|
2642
3537
|
return {
|
|
2643
|
-
vibrate: options => vibrate(requester, options),
|
|
2644
|
-
setClipboard: options => setClipboard(requester, options),
|
|
3538
|
+
vibrate: (options) => vibrate(requester, options),
|
|
3539
|
+
setClipboard: (options) => setClipboard(requester, options),
|
|
2645
3540
|
};
|
|
2646
3541
|
}
|
|
2647
3542
|
|
|
@@ -2752,7 +3647,7 @@ function createNavigationModule(requester) {
|
|
|
2752
3647
|
return {
|
|
2753
3648
|
close: () => close(requester),
|
|
2754
3649
|
reload: () => reload(requester),
|
|
2755
|
-
openAppPage: options => openAppPage(requester, options),
|
|
3650
|
+
openAppPage: (options) => openAppPage(requester, options),
|
|
2756
3651
|
};
|
|
2757
3652
|
}
|
|
2758
3653
|
|
|
@@ -2782,6 +3677,8 @@ class MiniProgramSDK {
|
|
|
2782
3677
|
storage;
|
|
2783
3678
|
/** 网络请求相关开放能力。 */
|
|
2784
3679
|
network;
|
|
3680
|
+
/** 受控文件与目录能力。 */
|
|
3681
|
+
files;
|
|
2785
3682
|
/** UI 交互相关开放能力。 */
|
|
2786
3683
|
ui;
|
|
2787
3684
|
/** 设备相关开放能力。 */
|
|
@@ -2798,6 +3695,7 @@ class MiniProgramSDK {
|
|
|
2798
3695
|
this.share = createShareModule(this.client, launchHref);
|
|
2799
3696
|
this.viewport = createViewportModule(this.client);
|
|
2800
3697
|
this.storage = createStorageModule(this.client);
|
|
3698
|
+
this.files = createFilesModule(this.client);
|
|
2801
3699
|
this.network = createNetworkModule(this.client);
|
|
2802
3700
|
this.ui = createUiModule(this.client);
|
|
2803
3701
|
this.device = createDeviceModule(this.client);
|
|
@@ -2815,8 +3713,8 @@ class MiniProgramSDK {
|
|
|
2815
3713
|
/**
|
|
2816
3714
|
* 注册小程序生命周期或业务事件。
|
|
2817
3715
|
*
|
|
2818
|
-
* @param eventName 要监听的事件名。
|
|
2819
|
-
* @param handler 事件处理函数。
|
|
3716
|
+
* @param eventName - 要监听的事件名。
|
|
3717
|
+
* @param handler - 事件处理函数。
|
|
2820
3718
|
* @returns 事件解绑函数。
|
|
2821
3719
|
*/
|
|
2822
3720
|
on(eventName, handler) {
|
|
@@ -2825,8 +3723,8 @@ class MiniProgramSDK {
|
|
|
2825
3723
|
/**
|
|
2826
3724
|
* 移除小程序生命周期或业务事件。
|
|
2827
3725
|
*
|
|
2828
|
-
* @param eventName 要移除的事件名。
|
|
2829
|
-
* @param handler 对应的事件处理函数。
|
|
3726
|
+
* @param eventName - 要移除的事件名。
|
|
3727
|
+
* @param handler - 对应的事件处理函数。
|
|
2830
3728
|
*/
|
|
2831
3729
|
off(eventName, handler) {
|
|
2832
3730
|
this.client.off(eventName, handler);
|
|
@@ -2845,7 +3743,7 @@ class MiniProgramSDK {
|
|
|
2845
3743
|
/**
|
|
2846
3744
|
* 创建独立 SDK 实例。
|
|
2847
3745
|
*
|
|
2848
|
-
* @param options SDK 运行配置,例如超时时间、nonce 或测试环境注入的 window。
|
|
3746
|
+
* @param options - SDK 运行配置,例如超时时间、nonce 或测试环境注入的 window。
|
|
2849
3747
|
* @returns 可独立管理生命周期的 `MiniProgramSDK` 实例。
|
|
2850
3748
|
*
|
|
2851
3749
|
* @remarks
|
|
@@ -2871,20 +3769,59 @@ function getDefaultSDK() {
|
|
|
2871
3769
|
}
|
|
2872
3770
|
return defaultSDK;
|
|
2873
3771
|
}
|
|
2874
|
-
/**
|
|
3772
|
+
/**
|
|
3773
|
+
* 获取默认 SDK 实例的当前握手状态。
|
|
3774
|
+
*
|
|
3775
|
+
* @since 0.7.0-alpha.9
|
|
3776
|
+
* @hbPlatform android
|
|
3777
|
+
* @hbPlatform ios
|
|
3778
|
+
* @hbPlatform ohos
|
|
3779
|
+
* @hbPlatform windows
|
|
3780
|
+
* @hbPlatform macos
|
|
3781
|
+
* @hbClient android none
|
|
3782
|
+
* @hbClient ios none
|
|
3783
|
+
* @hbClient ohos none
|
|
3784
|
+
* @hbClient windows none
|
|
3785
|
+
* @hbClient macos none
|
|
3786
|
+
*/
|
|
2875
3787
|
function getHandshakeState() {
|
|
2876
3788
|
return getDefaultSDK().getHandshakeState();
|
|
2877
3789
|
}
|
|
2878
|
-
/**
|
|
3790
|
+
/**
|
|
3791
|
+
* 订阅默认 SDK 实例的握手状态,并立即接收当前状态。
|
|
3792
|
+
*
|
|
3793
|
+
* @since 0.7.0-alpha.9
|
|
3794
|
+
* @hbPlatform android
|
|
3795
|
+
* @hbPlatform ios
|
|
3796
|
+
* @hbPlatform ohos
|
|
3797
|
+
* @hbPlatform windows
|
|
3798
|
+
* @hbPlatform macos
|
|
3799
|
+
* @hbClient android none
|
|
3800
|
+
* @hbClient ios none
|
|
3801
|
+
* @hbClient ohos none
|
|
3802
|
+
* @hbClient windows none
|
|
3803
|
+
* @hbClient macos none
|
|
3804
|
+
*/
|
|
2879
3805
|
function onHandshakeStateChange(handler) {
|
|
2880
3806
|
return getDefaultSDK().onHandshakeStateChange(handler);
|
|
2881
3807
|
}
|
|
2882
3808
|
/**
|
|
2883
3809
|
* 注册默认 SDK 实例的事件监听。
|
|
2884
3810
|
*
|
|
2885
|
-
* @param eventName 要监听的事件名。
|
|
2886
|
-
* @param handler 事件处理函数。
|
|
3811
|
+
* @param eventName - 要监听的事件名。
|
|
3812
|
+
* @param handler - 事件处理函数。
|
|
2887
3813
|
* @returns 事件解绑函数。
|
|
3814
|
+
* @since 0.2.0-alpha.0
|
|
3815
|
+
* @hbPlatform android
|
|
3816
|
+
* @hbPlatform ios
|
|
3817
|
+
* @hbPlatform ohos
|
|
3818
|
+
* @hbPlatform windows
|
|
3819
|
+
* @hbPlatform macos
|
|
3820
|
+
* @hbClient android none
|
|
3821
|
+
* @hbClient ios none
|
|
3822
|
+
* @hbClient ohos none
|
|
3823
|
+
* @hbClient windows none
|
|
3824
|
+
* @hbClient macos none
|
|
2888
3825
|
*/
|
|
2889
3826
|
function on(eventName, handler) {
|
|
2890
3827
|
return getDefaultSDK().on(eventName, handler);
|
|
@@ -2892,9 +3829,20 @@ function on(eventName, handler) {
|
|
|
2892
3829
|
/**
|
|
2893
3830
|
* 移除默认 SDK 实例的事件监听。
|
|
2894
3831
|
*
|
|
2895
|
-
* @param eventName 要移除的事件名。
|
|
2896
|
-
* @param handler 对应的事件处理函数。
|
|
3832
|
+
* @param eventName - 要移除的事件名。
|
|
3833
|
+
* @param handler - 对应的事件处理函数。
|
|
2897
3834
|
* @returns 无返回值。
|
|
3835
|
+
* @since 0.2.0-alpha.0
|
|
3836
|
+
* @hbPlatform android
|
|
3837
|
+
* @hbPlatform ios
|
|
3838
|
+
* @hbPlatform ohos
|
|
3839
|
+
* @hbPlatform windows
|
|
3840
|
+
* @hbPlatform macos
|
|
3841
|
+
* @hbClient android none
|
|
3842
|
+
* @hbClient ios none
|
|
3843
|
+
* @hbClient ohos none
|
|
3844
|
+
* @hbClient windows none
|
|
3845
|
+
* @hbClient macos none
|
|
2898
3846
|
*/
|
|
2899
3847
|
function off(eventName, handler) {
|
|
2900
3848
|
getDefaultSDK().off(eventName, handler);
|
|
@@ -2929,6 +3877,16 @@ const storage = {
|
|
|
2929
3877
|
/** 默认 SDK 实例的 network 模块。 */
|
|
2930
3878
|
const network = {
|
|
2931
3879
|
request: (config) => getDefaultSDK().network.request(config),
|
|
3880
|
+
download: (options) => getDefaultSDK().network.download(options),
|
|
3881
|
+
};
|
|
3882
|
+
/** 默认 SDK 实例的 files 模块。 */
|
|
3883
|
+
const files = {
|
|
3884
|
+
get sandbox() {
|
|
3885
|
+
return getDefaultSDK().files.sandbox;
|
|
3886
|
+
},
|
|
3887
|
+
pickFiles: (options) => getDefaultSDK().files.pickFiles(options),
|
|
3888
|
+
pickDirectory: (options) => getDefaultSDK().files.pickDirectory(options),
|
|
3889
|
+
saveFile: (options) => getDefaultSDK().files.saveFile(options),
|
|
2932
3890
|
};
|
|
2933
3891
|
/** 默认 SDK 实例的 UI 模块。 */
|
|
2934
3892
|
const ui = {
|
|
@@ -2968,6 +3926,7 @@ const hbSDK = {
|
|
|
2968
3926
|
share,
|
|
2969
3927
|
viewport,
|
|
2970
3928
|
storage,
|
|
3929
|
+
files,
|
|
2971
3930
|
network,
|
|
2972
3931
|
ui,
|
|
2973
3932
|
device,
|
|
@@ -2975,4 +3934,4 @@ const hbSDK = {
|
|
|
2975
3934
|
cloud,
|
|
2976
3935
|
};
|
|
2977
3936
|
|
|
2978
|
-
export { HbMiniProgramNetworkError, HbMiniProgramSDKError, USER_INFO_AUTHORIZATION_SCOPES, auth, cloud, hbSDK as default, device, getHandshakeState, navigation, network, off, on, onHandshakeStateChange, share, storage, ui, user, viewport };
|
|
3937
|
+
export { HbMiniProgramNetworkError, HbMiniProgramSDKError, USER_INFO_AUTHORIZATION_SCOPES, auth, cloud, hbSDK as default, device, files, getHandshakeState, navigation, network, off, on, onHandshakeStateChange, share, storage, ui, user, viewport };
|