@heybox/hb-sdk 0.1.2 → 0.2.0-alpha.0
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/README.md +172 -39
- package/bin/hb-sdk.cjs +3 -0
- package/dist/cli.cjs +9639 -0
- package/dist/devtools/mock-host/index.html +626 -0
- package/dist/index.cjs.js +513 -83
- package/dist/index.esm.js +499 -78
- package/dist/protocol.cjs.js +104 -0
- package/dist/protocol.esm.js +90 -0
- package/dist/templates/vue3-vite-ts/.gitignore.ejs +5 -0
- package/dist/templates/vue3-vite-ts/README.md.ejs +46 -0
- package/dist/templates/vue3-vite-ts/index.html.ejs +12 -0
- package/dist/templates/vue3-vite-ts/package.json.ejs +29 -0
- package/dist/templates/vue3-vite-ts/src/App.vue +63 -0
- package/dist/templates/vue3-vite-ts/src/__tests__/App.spec.ts +67 -0
- package/dist/templates/vue3-vite-ts/src/main.ts +5 -0
- package/dist/templates/vue3-vite-ts/src/styles.css +60 -0
- package/dist/templates/vue3-vite-ts/src/vite-env.d.ts +1 -0
- package/dist/templates/vue3-vite-ts/tsconfig.app.json +17 -0
- package/dist/templates/vue3-vite-ts/tsconfig.json +11 -0
- package/dist/templates/vue3-vite-ts/tsconfig.node.json +11 -0
- package/dist/templates/vue3-vite-ts/vite.config.ts +6 -0
- package/dist/templates/vue3-vite-ts/vitest.config.ts +10 -0
- package/package.json +28 -5
- package/types/core/client.d.ts +27 -4
- package/types/core/errors.d.ts +45 -2
- package/types/core/sdk.d.ts +78 -10
- package/types/core/singleton.d.ts +33 -7
- package/types/core/utils.d.ts +2 -0
- package/types/index.d.ts +10 -4
- package/types/modules/auth/index.d.ts +42 -0
- package/types/modules/network/index.d.ts +125 -0
- package/types/modules/share/index.d.ts +12 -2
- package/types/modules/share/screenshot.d.ts +14 -2
- package/types/modules/share/show-share-menu.d.ts +14 -2
- package/types/modules/share/types.d.ts +24 -4
- package/types/modules/storage/index.d.ts +70 -0
- package/types/modules/user/get-info.d.ts +11 -1
- package/types/modules/user/index.d.ts +13 -9
- package/types/modules/user/types.d.ts +1 -0
- package/types/modules/viewport/index.d.ts +78 -0
- package/types/protocol/guards.d.ts +6 -1
- package/types/protocol/types.d.ts +19 -4
- package/types/protocol.d.ts +18 -0
- package/types/modules/system/get-storage.d.ts +0 -15
- package/types/modules/system/get-window-info.d.ts +0 -16
- package/types/modules/system/index.d.ts +0 -23
- package/types/modules/system/set-storage.d.ts +0 -12
- package/types/modules/system/types.d.ts +0 -34
- package/types/modules/user/login.d.ts +0 -18
package/dist/index.esm.js
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* SDK 对外抛出的标准 bridge / runtime 错误类型。
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* 该错误用于表示握手失败、bridge 调用失败、父容器运行时错误等
|
|
6
|
+
* 非 HTTP 结果错误。其 `code` 字段可用于业务分支处理,
|
|
7
|
+
* `data` 仅作为可选调试信息,不保证结构稳定。
|
|
8
|
+
*/
|
|
2
9
|
class HbMiniProgramSDKError extends Error {
|
|
3
10
|
/** 稳定错误码。 */
|
|
4
11
|
code;
|
|
@@ -11,7 +18,17 @@ class HbMiniProgramSDKError extends Error {
|
|
|
11
18
|
this.data = error.data;
|
|
12
19
|
}
|
|
13
20
|
}
|
|
14
|
-
/**
|
|
21
|
+
/**
|
|
22
|
+
* 创建 SDK 标准错误。
|
|
23
|
+
*
|
|
24
|
+
* @param code 稳定错误码。
|
|
25
|
+
* @param message 面向开发者的错误说明。
|
|
26
|
+
* @param data 可选调试数据。
|
|
27
|
+
* @returns 标准化 `HbMiniProgramSDKError` 实例。
|
|
28
|
+
*
|
|
29
|
+
* @remarks
|
|
30
|
+
* 仅供 SDK 内部或同仓运行时层统一构造 bridge / runtime 错误。
|
|
31
|
+
*/
|
|
15
32
|
function createSDKError(code, message, data) {
|
|
16
33
|
return new HbMiniProgramSDKError({
|
|
17
34
|
code,
|
|
@@ -19,6 +36,39 @@ function createSDKError(code, message, data) {
|
|
|
19
36
|
data,
|
|
20
37
|
});
|
|
21
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* SDK 对外抛出的 HTTP 错误类型。
|
|
41
|
+
*
|
|
42
|
+
* @remarks
|
|
43
|
+
* 仅在请求已经成功走完 bridge / runtime / 宿主调用链、但最终 HTTP 状态不满足
|
|
44
|
+
* `validateStatus` 时抛出。它不表示握手失败或 bridge 级错误。
|
|
45
|
+
*
|
|
46
|
+
* @typeParam T 标准化响应数据的类型。
|
|
47
|
+
*/
|
|
48
|
+
class HbMiniProgramNetworkError extends Error {
|
|
49
|
+
/** HTTP 状态码。 */
|
|
50
|
+
status;
|
|
51
|
+
/** 标准化响应数据。 */
|
|
52
|
+
data;
|
|
53
|
+
/** 标准化响应头。 */
|
|
54
|
+
headers;
|
|
55
|
+
/** SDK 公共请求配置快照。 */
|
|
56
|
+
config;
|
|
57
|
+
/** 完整标准化响应。 */
|
|
58
|
+
response;
|
|
59
|
+
/**
|
|
60
|
+
* @param response 已完成请求的标准化网络响应。
|
|
61
|
+
*/
|
|
62
|
+
constructor(response) {
|
|
63
|
+
super(`network.request failed with status ${response.status}`);
|
|
64
|
+
this.name = 'HbMiniProgramNetworkError';
|
|
65
|
+
this.status = response.status;
|
|
66
|
+
this.data = response.data;
|
|
67
|
+
this.headers = response.headers;
|
|
68
|
+
this.config = response.config;
|
|
69
|
+
this.response = response;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
22
72
|
|
|
23
73
|
/** SDK 内部事件总线,负责管理沙盒生命周期与业务事件监听。 */
|
|
24
74
|
class MiniProgramEventBus {
|
|
@@ -73,6 +123,31 @@ function getParentWindow(currentWindow) {
|
|
|
73
123
|
}
|
|
74
124
|
return currentWindow.parent;
|
|
75
125
|
}
|
|
126
|
+
/** 尝试读取父窗口 origin;跨域读取失败时回退到 document.referrer。 */
|
|
127
|
+
function readParentOrigin(currentWindow) {
|
|
128
|
+
const parentWindow = getParentWindow(currentWindow);
|
|
129
|
+
if (parentWindow) {
|
|
130
|
+
try {
|
|
131
|
+
const origin = parentWindow.location?.origin;
|
|
132
|
+
if (origin && origin !== 'null') {
|
|
133
|
+
return origin;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
// ignore cross-origin parent access and fall back to referrer
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
const referrer = currentWindow?.document?.referrer;
|
|
141
|
+
if (!referrer) {
|
|
142
|
+
return '';
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
return new URL(referrer).origin;
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return '';
|
|
149
|
+
}
|
|
150
|
+
}
|
|
76
151
|
/** 从父容器注入到 URL 的 query 中读取 bridge nonce。 */
|
|
77
152
|
function readBridgeNonce(currentWindow) {
|
|
78
153
|
const href = currentWindow?.location?.href;
|
|
@@ -95,7 +170,12 @@ function createMessageId() {
|
|
|
95
170
|
return `${Date.now().toString(36)}_${Math.random().toString(36).slice(2)}`;
|
|
96
171
|
}
|
|
97
172
|
|
|
98
|
-
/**
|
|
173
|
+
/**
|
|
174
|
+
* 判断未知数据是否符合小程序 bridge 消息信封。
|
|
175
|
+
*
|
|
176
|
+
* @param value 待判断的未知数据。
|
|
177
|
+
* @returns 当数据满足小程序 bridge 消息基础结构时返回 `true`。
|
|
178
|
+
*/
|
|
99
179
|
function isMiniProgramBridgeMessage(value) {
|
|
100
180
|
if (!value || typeof value !== 'object') {
|
|
101
181
|
return false;
|
|
@@ -108,11 +188,13 @@ function isMiniProgramBridgeMessage(value) {
|
|
|
108
188
|
}
|
|
109
189
|
|
|
110
190
|
const DEFAULT_TIMEOUT = 10000;
|
|
191
|
+
const HANDSHAKE_RETRY_INTERVAL = 250;
|
|
111
192
|
/** 底层 bridge client,负责握手、请求响应、事件分发与超时清理。 */
|
|
112
193
|
class MiniProgramBridgeClient {
|
|
113
194
|
timeout;
|
|
114
195
|
selfWindow;
|
|
115
196
|
targetWindow;
|
|
197
|
+
targetOrigin;
|
|
116
198
|
nonce;
|
|
117
199
|
pendingRequests = new Map();
|
|
118
200
|
eventBus = new MiniProgramEventBus();
|
|
@@ -123,11 +205,14 @@ class MiniProgramBridgeClient {
|
|
|
123
205
|
resolveReady;
|
|
124
206
|
rejectReady;
|
|
125
207
|
readyTimer;
|
|
208
|
+
handshakeRetryTimer;
|
|
209
|
+
destroyed = false;
|
|
126
210
|
constructor(options = {}) {
|
|
127
211
|
this.timeout = options.timeout || DEFAULT_TIMEOUT;
|
|
128
212
|
this.selfWindow = options.selfWindow || getGlobalWindow();
|
|
129
213
|
this.targetWindow =
|
|
130
214
|
options.targetWindow === undefined ? getParentWindow(this.selfWindow) : options.targetWindow;
|
|
215
|
+
this.targetOrigin = options.targetOrigin || readParentOrigin(this.selfWindow) || '*';
|
|
131
216
|
this.nonce = options.nonce || readBridgeNonce(this.selfWindow);
|
|
132
217
|
this.handleMessage = this.onMessage.bind(this);
|
|
133
218
|
this.readyPromise = new Promise((resolve, reject) => {
|
|
@@ -185,11 +270,17 @@ class MiniProgramBridgeClient {
|
|
|
185
270
|
}
|
|
186
271
|
/** 销毁 SDK 实例,并拒绝尚未完成的请求。 */
|
|
187
272
|
destroy() {
|
|
273
|
+
this.destroyed = true;
|
|
188
274
|
this.selfWindow?.removeEventListener('message', this.handleMessage);
|
|
189
|
-
|
|
190
|
-
this.
|
|
275
|
+
const error = createSDKError('SDK_DESTROYED', '小程序 SDK 已销毁');
|
|
276
|
+
this.failReady(error);
|
|
277
|
+
this.rejectAllPending(error);
|
|
191
278
|
}
|
|
192
279
|
ensureStarted() {
|
|
280
|
+
if (this.destroyed) {
|
|
281
|
+
this.failReady(createSDKError('SDK_DESTROYED', '小程序 SDK 已销毁'));
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
193
284
|
if (this.started) {
|
|
194
285
|
return;
|
|
195
286
|
}
|
|
@@ -206,6 +297,22 @@ class MiniProgramBridgeClient {
|
|
|
206
297
|
this.readyTimer = setTimeout(() => {
|
|
207
298
|
this.failReady(createSDKError('READY_TIMEOUT', '小程序沙盒握手超时'));
|
|
208
299
|
}, this.timeout);
|
|
300
|
+
try {
|
|
301
|
+
this.postHandshake();
|
|
302
|
+
this.handshakeRetryTimer = setInterval(() => {
|
|
303
|
+
this.postHandshake();
|
|
304
|
+
}, HANDSHAKE_RETRY_INTERVAL);
|
|
305
|
+
}
|
|
306
|
+
catch (error) {
|
|
307
|
+
this.failReady(error instanceof HbMiniProgramSDKError
|
|
308
|
+
? error
|
|
309
|
+
: createSDKError('HANDSHAKE_FAILED', '小程序沙盒握手发送失败', error));
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
postHandshake() {
|
|
313
|
+
if (!this.selfWindow) {
|
|
314
|
+
throw createSDKError('NOT_IN_IFRAME', '当前页面不在小程序沙盒 iframe 中');
|
|
315
|
+
}
|
|
209
316
|
this.postMessage({
|
|
210
317
|
namespace: MINI_PROGRAM_MESSAGE_NAMESPACE,
|
|
211
318
|
version: MINI_PROGRAM_MESSAGE_VERSION,
|
|
@@ -261,14 +368,14 @@ class MiniProgramBridgeClient {
|
|
|
261
368
|
if (!this.targetWindow) {
|
|
262
369
|
throw createSDKError('NOT_IN_IFRAME', '当前页面不在小程序沙盒 iframe 中');
|
|
263
370
|
}
|
|
264
|
-
this.targetWindow.postMessage(message,
|
|
371
|
+
this.targetWindow.postMessage(message, this.targetOrigin);
|
|
265
372
|
}
|
|
266
373
|
resolveReadyOnce() {
|
|
267
374
|
if (this.readySettled) {
|
|
268
375
|
return;
|
|
269
376
|
}
|
|
270
377
|
this.readySettled = true;
|
|
271
|
-
this.
|
|
378
|
+
this.clearReadyTimers();
|
|
272
379
|
this.resolveReady();
|
|
273
380
|
}
|
|
274
381
|
failReady(error) {
|
|
@@ -276,18 +383,21 @@ class MiniProgramBridgeClient {
|
|
|
276
383
|
return;
|
|
277
384
|
}
|
|
278
385
|
this.readySettled = true;
|
|
279
|
-
this.
|
|
386
|
+
this.clearReadyTimers();
|
|
280
387
|
this.rejectReady(error);
|
|
281
388
|
}
|
|
282
|
-
|
|
283
|
-
if (
|
|
284
|
-
|
|
389
|
+
clearReadyTimers() {
|
|
390
|
+
if (this.readyTimer) {
|
|
391
|
+
clearTimeout(this.readyTimer);
|
|
392
|
+
this.readyTimer = undefined;
|
|
393
|
+
}
|
|
394
|
+
if (this.handshakeRetryTimer) {
|
|
395
|
+
clearInterval(this.handshakeRetryTimer);
|
|
396
|
+
this.handshakeRetryTimer = undefined;
|
|
285
397
|
}
|
|
286
|
-
clearTimeout(this.readyTimer);
|
|
287
|
-
this.readyTimer = undefined;
|
|
288
398
|
}
|
|
289
399
|
rejectAllPending(error) {
|
|
290
|
-
this.pendingRequests.forEach(
|
|
400
|
+
this.pendingRequests.forEach(pending => {
|
|
291
401
|
clearTimeout(pending.timer);
|
|
292
402
|
pending.reject(error);
|
|
293
403
|
});
|
|
@@ -295,21 +405,82 @@ class MiniProgramBridgeClient {
|
|
|
295
405
|
}
|
|
296
406
|
}
|
|
297
407
|
|
|
298
|
-
/**
|
|
408
|
+
/**
|
|
409
|
+
* 登录授权能力方法名。
|
|
410
|
+
*
|
|
411
|
+
* @remarks
|
|
412
|
+
* 供 SDK 与父容器 runtime 共享同一 bridge method 标识。
|
|
413
|
+
*/
|
|
414
|
+
const AUTH_LOGIN_METHOD = 'auth.login';
|
|
415
|
+
/**
|
|
416
|
+
* 唤起登录授权,并在流程返回后刷新用户公开基础资料。
|
|
417
|
+
*
|
|
418
|
+
* @param requester 底层 bridge 请求能力。
|
|
419
|
+
* @returns 登录流程完成后的最新用户登录态与公开资料。
|
|
420
|
+
* @throws {HbMiniProgramSDKError} 当 bridge、父容器或宿主运行时调用失败时抛出。
|
|
421
|
+
*
|
|
422
|
+
* @remarks
|
|
423
|
+
* 该能力不会向小程序暴露 token、cookie 或其他登录凭据。
|
|
424
|
+
*/
|
|
425
|
+
function login(requester) {
|
|
426
|
+
return requester.request(AUTH_LOGIN_METHOD);
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* 创建授权模块。
|
|
430
|
+
*
|
|
431
|
+
* @param requester 底层 bridge 请求能力。
|
|
432
|
+
* @returns 面向业务层的授权模块对象。
|
|
433
|
+
*/
|
|
434
|
+
function createAuthModule(requester) {
|
|
435
|
+
return {
|
|
436
|
+
login: () => login(requester),
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* 截图分享能力方法名。
|
|
442
|
+
*
|
|
443
|
+
* @remarks
|
|
444
|
+
* 供 SDK 与父容器 runtime 共享同一 bridge method 标识。
|
|
445
|
+
*/
|
|
299
446
|
const SHARE_SCREENSHOT_METHOD = 'share.screenshot';
|
|
300
|
-
/**
|
|
447
|
+
/**
|
|
448
|
+
* 截图并唤起分享。
|
|
449
|
+
*
|
|
450
|
+
* @param requester 底层 bridge 请求能力。
|
|
451
|
+
* @param options 截图区域、延迟与保存相册等配置。
|
|
452
|
+
* @returns 由宿主客户端协议决定的结果。
|
|
453
|
+
* @throws {HbMiniProgramSDKError} 当 bridge、父容器或宿主能力调用失败时抛出。
|
|
454
|
+
*/
|
|
301
455
|
function screenshot(requester, options) {
|
|
302
456
|
return requester.request(SHARE_SCREENSHOT_METHOD, options);
|
|
303
457
|
}
|
|
304
458
|
|
|
305
|
-
/**
|
|
459
|
+
/**
|
|
460
|
+
* 展示分享面板能力方法名。
|
|
461
|
+
*
|
|
462
|
+
* @remarks
|
|
463
|
+
* 供 SDK 与父容器 runtime 共享同一 bridge method 标识。
|
|
464
|
+
*/
|
|
306
465
|
const SHARE_SHOW_SHARE_MENU_METHOD = 'share.showShareMenu';
|
|
307
|
-
/**
|
|
466
|
+
/**
|
|
467
|
+
* 展示基础分享面板。
|
|
468
|
+
*
|
|
469
|
+
* @param requester 底层 bridge 请求能力。
|
|
470
|
+
* @param options 基础分享参数。
|
|
471
|
+
* @returns 由宿主客户端协议决定的结果。
|
|
472
|
+
* @throws {HbMiniProgramSDKError} 当 bridge、父容器或宿主能力调用失败时抛出。
|
|
473
|
+
*/
|
|
308
474
|
function showShareMenu(requester, options) {
|
|
309
475
|
return requester.request(SHARE_SHOW_SHARE_MENU_METHOD, options);
|
|
310
476
|
}
|
|
311
477
|
|
|
312
|
-
/**
|
|
478
|
+
/**
|
|
479
|
+
* 创建分享模块。
|
|
480
|
+
*
|
|
481
|
+
* @param requester 底层 bridge 请求能力。
|
|
482
|
+
* @returns 面向业务层的分享模块对象。
|
|
483
|
+
*/
|
|
313
484
|
function createShareModule(requester) {
|
|
314
485
|
return {
|
|
315
486
|
showShareMenu: options => showShareMenu(requester, options),
|
|
@@ -317,102 +488,322 @@ function createShareModule(requester) {
|
|
|
317
488
|
};
|
|
318
489
|
}
|
|
319
490
|
|
|
320
|
-
/** 用户信息能力方法名。 */
|
|
321
|
-
const USER_GET_INFO_METHOD = 'user.getInfo';
|
|
322
491
|
/**
|
|
323
|
-
*
|
|
492
|
+
* 读取小程序隔离 storage 能力方法名。
|
|
324
493
|
*
|
|
325
|
-
*
|
|
326
|
-
*
|
|
494
|
+
* @remarks
|
|
495
|
+
* 供 SDK 与父容器 runtime 共享同一 bridge method 标识。
|
|
327
496
|
*/
|
|
328
|
-
|
|
329
|
-
|
|
497
|
+
const STORAGE_GET_STORAGE_METHOD = 'storage.getStorage';
|
|
498
|
+
/**
|
|
499
|
+
* 写入小程序隔离 storage 能力方法名。
|
|
500
|
+
*
|
|
501
|
+
* @remarks
|
|
502
|
+
* 供 SDK 与父容器 runtime 共享同一 bridge method 标识。
|
|
503
|
+
*/
|
|
504
|
+
const STORAGE_SET_STORAGE_METHOD = 'storage.setStorage';
|
|
505
|
+
/**
|
|
506
|
+
* 获取小程序隔离 storage。
|
|
507
|
+
*
|
|
508
|
+
* @param requester 底层 bridge 请求能力。
|
|
509
|
+
* @param options 读取的 storage key。
|
|
510
|
+
* @returns 对应 key 的标准化读取结果。
|
|
511
|
+
* @throws {HbMiniProgramSDKError} 当 bridge、父容器或宿主能力调用失败时抛出。
|
|
512
|
+
*/
|
|
513
|
+
function getStorage(requester, options) {
|
|
514
|
+
return requester.request(STORAGE_GET_STORAGE_METHOD, options);
|
|
330
515
|
}
|
|
331
|
-
|
|
332
|
-
/** 用户登录能力方法名。 */
|
|
333
|
-
const USER_LOGIN_METHOD = 'user.login';
|
|
334
516
|
/**
|
|
335
|
-
*
|
|
517
|
+
* 写入小程序隔离 storage。
|
|
336
518
|
*
|
|
337
|
-
*
|
|
519
|
+
* @param requester 底层 bridge 请求能力。
|
|
520
|
+
* @param options 要写入的 storage key 与数据。
|
|
521
|
+
* @returns 当写入完成后 resolve。
|
|
522
|
+
* @throws {HbMiniProgramSDKError} 当 bridge、父容器或宿主能力调用失败时抛出。
|
|
338
523
|
*/
|
|
339
|
-
function
|
|
340
|
-
return requester.request(
|
|
524
|
+
function setStorage(requester, options) {
|
|
525
|
+
return requester.request(STORAGE_SET_STORAGE_METHOD, options);
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* 创建 storage 模块。
|
|
529
|
+
*
|
|
530
|
+
* @param requester 底层 bridge 请求能力。
|
|
531
|
+
* @returns 面向业务层的 storage 模块对象。
|
|
532
|
+
*/
|
|
533
|
+
function createStorageModule(requester) {
|
|
534
|
+
return {
|
|
535
|
+
getStorage: options => getStorage(requester, options),
|
|
536
|
+
setStorage: options => setStorage(requester, options),
|
|
537
|
+
};
|
|
341
538
|
}
|
|
342
539
|
|
|
343
|
-
/**
|
|
344
|
-
|
|
540
|
+
/**
|
|
541
|
+
* 发起网络请求能力方法名。
|
|
542
|
+
*
|
|
543
|
+
* @remarks
|
|
544
|
+
* 供 SDK 与父容器 runtime 共享同一 bridge method 标识。
|
|
545
|
+
*/
|
|
546
|
+
const NETWORK_REQUEST_METHOD = 'network.request';
|
|
547
|
+
const DEFAULT_VALIDATE_STATUS = status => status >= 200 && status < 300;
|
|
548
|
+
function isPlainObject(value) {
|
|
549
|
+
return Object.prototype.toString.call(value) === '[object Object]';
|
|
550
|
+
}
|
|
551
|
+
function clonePublicValue(value) {
|
|
552
|
+
if (Array.isArray(value)) {
|
|
553
|
+
return value.map(item => clonePublicValue(item));
|
|
554
|
+
}
|
|
555
|
+
if (isPlainObject(value)) {
|
|
556
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, clonePublicValue(item)]));
|
|
557
|
+
}
|
|
558
|
+
return value;
|
|
559
|
+
}
|
|
560
|
+
function snapshotRequestConfig(config) {
|
|
345
561
|
return {
|
|
346
|
-
|
|
347
|
-
|
|
562
|
+
url: config.url,
|
|
563
|
+
...(config.method === undefined ? {} : { method: config.method }),
|
|
564
|
+
...(config.params === undefined ? {} : { params: clonePublicValue(config.params) }),
|
|
565
|
+
...(config.data === undefined ? {} : { data: clonePublicValue(config.data) }),
|
|
566
|
+
...(config.headers === undefined ? {} : { headers: clonePublicValue(config.headers) }),
|
|
567
|
+
...(config.timeout === undefined ? {} : { timeout: config.timeout }),
|
|
568
|
+
...(config.withCredentials === undefined ? {} : { withCredentials: config.withCredentials }),
|
|
569
|
+
...(config.validateStatus === undefined ? {} : { validateStatus: config.validateStatus }),
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
function toRequestPayload(config) {
|
|
573
|
+
return {
|
|
574
|
+
url: config.url,
|
|
575
|
+
...(config.method === undefined ? {} : { method: config.method }),
|
|
576
|
+
...(config.params === undefined ? {} : { params: clonePublicValue(config.params) }),
|
|
577
|
+
...(config.data === undefined ? {} : { data: clonePublicValue(config.data) }),
|
|
578
|
+
...(config.headers === undefined ? {} : { headers: clonePublicValue(config.headers) }),
|
|
579
|
+
...(config.timeout === undefined ? {} : { timeout: config.timeout }),
|
|
580
|
+
...(config.withCredentials === undefined ? {} : { withCredentials: config.withCredentials }),
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
function normalizeHeaders(headers) {
|
|
584
|
+
if (!isPlainObject(headers)) {
|
|
585
|
+
return {};
|
|
586
|
+
}
|
|
587
|
+
return Object.fromEntries(Object.entries(headers).flatMap(([key, value]) => (typeof value === 'string' ? [[key, value]] : [])));
|
|
588
|
+
}
|
|
589
|
+
function toNetworkResponse(payload, config) {
|
|
590
|
+
if (typeof payload.status !== 'number' || Number.isNaN(payload.status)) {
|
|
591
|
+
throw createSDKError('INVALID_NETWORK_RESPONSE', 'network.request 返回了无效的 status', payload);
|
|
592
|
+
}
|
|
593
|
+
return {
|
|
594
|
+
data: payload.data,
|
|
595
|
+
status: payload.status,
|
|
596
|
+
...(typeof payload.statusText === 'string' ? { statusText: payload.statusText } : {}),
|
|
597
|
+
headers: normalizeHeaders(payload.headers),
|
|
598
|
+
config: snapshotRequestConfig(config),
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* 发起网络请求并返回标准化响应。
|
|
603
|
+
*
|
|
604
|
+
* @param requester 底层 bridge 请求能力。
|
|
605
|
+
* @param config 面向业务层的网络请求配置。
|
|
606
|
+
* @returns 标准化网络响应。HTTP 2xx 默认返回 resolve。
|
|
607
|
+
* @throws {HbMiniProgramNetworkError} 当请求已完成但 HTTP 状态不满足 `validateStatus` 时抛出。
|
|
608
|
+
* @throws {HbMiniProgramSDKError} 当 bridge、运行时或宿主能力调用失败时抛出。
|
|
609
|
+
*
|
|
610
|
+
* @remarks
|
|
611
|
+
* `validateStatus` 仅在 SDK 侧执行,不会跨 bridge 传输函数值。
|
|
612
|
+
* 公开配置与返回结构都保持 axios-like 的窄接口,不暴露宿主原始协议字段。
|
|
613
|
+
*
|
|
614
|
+
* @example
|
|
615
|
+
* ```ts
|
|
616
|
+
* const result = await request(requester, {
|
|
617
|
+
* url: 'https://api.xiaoheihe.cn/demo',
|
|
618
|
+
* method: 'GET',
|
|
619
|
+
* })
|
|
620
|
+
* ```
|
|
621
|
+
*/
|
|
622
|
+
async function request(requester, config) {
|
|
623
|
+
const validateStatus = config.validateStatus || DEFAULT_VALIDATE_STATUS;
|
|
624
|
+
const responsePayload = await requester.request(NETWORK_REQUEST_METHOD, toRequestPayload(config));
|
|
625
|
+
const response = toNetworkResponse(responsePayload, config);
|
|
626
|
+
if (!validateStatus(response.status)) {
|
|
627
|
+
throw new HbMiniProgramNetworkError(response);
|
|
628
|
+
}
|
|
629
|
+
return response;
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* 创建 network 模块。
|
|
633
|
+
*
|
|
634
|
+
* @param requester 底层 bridge 请求能力。
|
|
635
|
+
* @returns 面向业务层的网络模块对象。
|
|
636
|
+
*/
|
|
637
|
+
function createNetworkModule(requester) {
|
|
638
|
+
return {
|
|
639
|
+
request: config => request(requester, config),
|
|
348
640
|
};
|
|
349
641
|
}
|
|
350
642
|
|
|
351
|
-
/**
|
|
352
|
-
|
|
643
|
+
/**
|
|
644
|
+
* 视口窗口信息能力方法名。
|
|
645
|
+
*
|
|
646
|
+
* @remarks
|
|
647
|
+
* 供 SDK 与父容器 runtime 共享同一 bridge method 标识。
|
|
648
|
+
*/
|
|
649
|
+
const VIEWPORT_GET_WINDOW_INFO_METHOD = 'viewport.getWindowInfo';
|
|
353
650
|
/**
|
|
354
651
|
* 获取当前小程序窗口信息。
|
|
652
|
+
*
|
|
653
|
+
* @param requester 底层 bridge 请求能力。
|
|
654
|
+
* @returns 当前小程序可用窗口信息。
|
|
655
|
+
* @throws {HbMiniProgramSDKError} 当 bridge、父容器或宿主能力调用失败时抛出。
|
|
355
656
|
*/
|
|
356
657
|
function getWindowInfo(requester) {
|
|
357
|
-
return requester.request(
|
|
658
|
+
return requester.request(VIEWPORT_GET_WINDOW_INFO_METHOD);
|
|
358
659
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
660
|
+
/**
|
|
661
|
+
* 创建 Viewport 模块。
|
|
662
|
+
*
|
|
663
|
+
* @param requester 底层 bridge 请求能力。
|
|
664
|
+
* @returns 面向业务层的 Viewport 模块对象。
|
|
665
|
+
*/
|
|
666
|
+
function createViewportModule(requester) {
|
|
667
|
+
return {
|
|
668
|
+
getWindowInfo: () => getWindowInfo(requester),
|
|
669
|
+
};
|
|
365
670
|
}
|
|
366
671
|
|
|
367
|
-
/**
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
672
|
+
/**
|
|
673
|
+
* 用户信息能力方法名。
|
|
674
|
+
*
|
|
675
|
+
* @remarks
|
|
676
|
+
* 供 SDK 与父容器 runtime 共享同一 bridge method 标识。
|
|
677
|
+
*/
|
|
678
|
+
const USER_GET_INFO_METHOD = 'user.getInfo';
|
|
679
|
+
/**
|
|
680
|
+
* 获取当前访问小程序用户的公开基础资料。
|
|
681
|
+
*
|
|
682
|
+
* @param requester 底层 bridge 请求能力。
|
|
683
|
+
* @returns 当前用户的登录态与公开基础资料。
|
|
684
|
+
*
|
|
685
|
+
* 该能力只返回 `heybox_id`、`nickname`、`avatar` 三个公开字段。
|
|
686
|
+
* 未登录时不会触发登录流程,直接返回 `{ isLogin: false, userInfo: null }`。
|
|
687
|
+
*
|
|
688
|
+
* @throws {HbMiniProgramSDKError} 当 bridge、父容器或宿主运行时调用失败时抛出。
|
|
689
|
+
*/
|
|
690
|
+
function getInfo(requester) {
|
|
691
|
+
return requester.request(USER_GET_INFO_METHOD);
|
|
372
692
|
}
|
|
373
693
|
|
|
374
|
-
/**
|
|
375
|
-
|
|
694
|
+
/**
|
|
695
|
+
* 创建用户模块。
|
|
696
|
+
*
|
|
697
|
+
* @param requester 底层 bridge 请求能力。
|
|
698
|
+
* @returns 面向业务层的用户模块对象。
|
|
699
|
+
*/
|
|
700
|
+
function createUserModule(requester) {
|
|
376
701
|
return {
|
|
377
|
-
|
|
378
|
-
getStorage: options => getStorage(requester, options),
|
|
379
|
-
setStorage: options => setStorage(requester, options),
|
|
702
|
+
getInfo: () => getInfo(requester),
|
|
380
703
|
};
|
|
381
704
|
}
|
|
382
705
|
|
|
383
|
-
/**
|
|
706
|
+
/**
|
|
707
|
+
* 外部小程序 SDK 实例。
|
|
708
|
+
*
|
|
709
|
+
* @remarks
|
|
710
|
+
* 该实例负责组织授权、用户、分享、容器、存储与网络等开放能力,并维护
|
|
711
|
+
* iframe 内小程序与父容器之间的 bridge 生命周期。
|
|
712
|
+
*
|
|
713
|
+
* 多数业务页直接使用默认单例即可;只有在测试、多实例或需要定制运行参数时,
|
|
714
|
+
* 才建议显式创建独立实例。
|
|
715
|
+
*
|
|
716
|
+
* @example
|
|
717
|
+
* ```ts
|
|
718
|
+
* import { createMiniProgramSDK } from '@heybox/hb-sdk'
|
|
719
|
+
*
|
|
720
|
+
* const sdk = createMiniProgramSDK({
|
|
721
|
+
* timeout: 15000,
|
|
722
|
+
* })
|
|
723
|
+
*
|
|
724
|
+
* await sdk.ready()
|
|
725
|
+
* ```
|
|
726
|
+
*/
|
|
384
727
|
class MiniProgramSDK {
|
|
385
728
|
client;
|
|
386
|
-
/**
|
|
729
|
+
/** 授权相关开放能力。 */
|
|
730
|
+
auth;
|
|
731
|
+
/** 用户资料相关开放能力。 */
|
|
387
732
|
user;
|
|
388
733
|
/** 分享相关开放能力。 */
|
|
389
734
|
share;
|
|
390
|
-
/**
|
|
391
|
-
|
|
735
|
+
/** 视口相关开放能力。 */
|
|
736
|
+
viewport;
|
|
737
|
+
/** Storage 相关开放能力。 */
|
|
738
|
+
storage;
|
|
739
|
+
/** 网络请求相关开放能力。 */
|
|
740
|
+
network;
|
|
392
741
|
constructor(options) {
|
|
393
742
|
this.client = new MiniProgramBridgeClient(options);
|
|
743
|
+
this.auth = createAuthModule(this.client);
|
|
394
744
|
this.user = createUserModule(this.client);
|
|
395
745
|
this.share = createShareModule(this.client);
|
|
396
|
-
this.
|
|
746
|
+
this.viewport = createViewportModule(this.client);
|
|
747
|
+
this.storage = createStorageModule(this.client);
|
|
748
|
+
this.network = createNetworkModule(this.client);
|
|
397
749
|
}
|
|
398
|
-
/**
|
|
750
|
+
/**
|
|
751
|
+
* 等待 SDK 与父容器完成握手。
|
|
752
|
+
*
|
|
753
|
+
* @returns 当 bridge 握手成功后 resolve。
|
|
754
|
+
* @throws {HbMiniProgramSDKError} 当当前页面不在 iframe 中、缺少 nonce 或握手超时时抛出。
|
|
755
|
+
*/
|
|
399
756
|
ready() {
|
|
400
757
|
return this.client.ready();
|
|
401
758
|
}
|
|
402
|
-
/**
|
|
759
|
+
/**
|
|
760
|
+
* 注册小程序生命周期或业务事件。
|
|
761
|
+
*
|
|
762
|
+
* @param eventName 要监听的事件名。
|
|
763
|
+
* @param handler 事件处理函数。
|
|
764
|
+
* @returns 事件解绑函数。
|
|
765
|
+
*/
|
|
403
766
|
on(eventName, handler) {
|
|
404
767
|
return this.client.on(eventName, handler);
|
|
405
768
|
}
|
|
406
|
-
/**
|
|
769
|
+
/**
|
|
770
|
+
* 移除小程序生命周期或业务事件。
|
|
771
|
+
*
|
|
772
|
+
* @param eventName 要移除的事件名。
|
|
773
|
+
* @param handler 对应的事件处理函数。
|
|
774
|
+
*/
|
|
407
775
|
off(eventName, handler) {
|
|
408
776
|
this.client.off(eventName, handler);
|
|
409
777
|
}
|
|
410
|
-
/**
|
|
778
|
+
/**
|
|
779
|
+
* 销毁 SDK 实例。
|
|
780
|
+
*
|
|
781
|
+
* @remarks
|
|
782
|
+
* 销毁后会移除 message 监听,并拒绝尚未完成的 bridge 请求。
|
|
783
|
+
* 已销毁实例不应继续复用。
|
|
784
|
+
*/
|
|
411
785
|
destroy() {
|
|
412
786
|
this.client.destroy();
|
|
413
787
|
}
|
|
414
788
|
}
|
|
415
|
-
/**
|
|
789
|
+
/**
|
|
790
|
+
* 创建独立 SDK 实例。
|
|
791
|
+
*
|
|
792
|
+
* @param options SDK 运行配置,例如超时时间、nonce 或测试环境注入的 window。
|
|
793
|
+
* @returns 可独立管理生命周期的 `MiniProgramSDK` 实例。
|
|
794
|
+
*
|
|
795
|
+
* @remarks
|
|
796
|
+
* 适用于测试、多实例场景,或需要自定义 `timeout`、`targetWindow` 等运行参数的场景。
|
|
797
|
+
*
|
|
798
|
+
* @example
|
|
799
|
+
* ```ts
|
|
800
|
+
* import { createMiniProgramSDK } from '@heybox/hb-sdk'
|
|
801
|
+
*
|
|
802
|
+
* const sdk = createMiniProgramSDK({
|
|
803
|
+
* timeout: 15000,
|
|
804
|
+
* })
|
|
805
|
+
* ```
|
|
806
|
+
*/
|
|
416
807
|
function createMiniProgramSDK(options) {
|
|
417
808
|
return new MiniProgramSDK(options);
|
|
418
809
|
}
|
|
@@ -424,42 +815,72 @@ function getDefaultSDK() {
|
|
|
424
815
|
}
|
|
425
816
|
return defaultSDK;
|
|
426
817
|
}
|
|
427
|
-
/**
|
|
818
|
+
/**
|
|
819
|
+
* 等待默认 SDK 实例与父容器完成握手。
|
|
820
|
+
*
|
|
821
|
+
* @returns 当默认 SDK 单例与父容器握手成功后 resolve。
|
|
822
|
+
* @throws {HbMiniProgramSDKError} 当当前页面不在 iframe 中、缺少 nonce 或握手超时时抛出。
|
|
823
|
+
*/
|
|
428
824
|
function ready() {
|
|
429
825
|
return getDefaultSDK().ready();
|
|
430
826
|
}
|
|
431
|
-
/**
|
|
827
|
+
/**
|
|
828
|
+
* 注册默认 SDK 实例的事件监听。
|
|
829
|
+
*
|
|
830
|
+
* @param eventName 要监听的事件名。
|
|
831
|
+
* @param handler 事件处理函数。
|
|
832
|
+
* @returns 事件解绑函数。
|
|
833
|
+
*/
|
|
432
834
|
function on(eventName, handler) {
|
|
433
835
|
return getDefaultSDK().on(eventName, handler);
|
|
434
836
|
}
|
|
435
|
-
/**
|
|
837
|
+
/**
|
|
838
|
+
* 移除默认 SDK 实例的事件监听。
|
|
839
|
+
*
|
|
840
|
+
* @param eventName 要移除的事件名。
|
|
841
|
+
* @param handler 对应的事件处理函数。
|
|
842
|
+
* @returns 无返回值。
|
|
843
|
+
*/
|
|
436
844
|
function off(eventName, handler) {
|
|
437
845
|
getDefaultSDK().off(eventName, handler);
|
|
438
846
|
}
|
|
439
|
-
/** 默认 SDK
|
|
847
|
+
/** 默认 SDK 实例的授权模块。 */
|
|
848
|
+
const auth = {
|
|
849
|
+
login: () => getDefaultSDK().auth.login(),
|
|
850
|
+
};
|
|
851
|
+
/** 默认 SDK 实例的用户资料模块。 */
|
|
440
852
|
const user = {
|
|
441
853
|
getInfo: () => getDefaultSDK().user.getInfo(),
|
|
442
|
-
login: () => getDefaultSDK().user.login(),
|
|
443
854
|
};
|
|
444
855
|
/** 默认 SDK 实例的分享模块。 */
|
|
445
856
|
const share = {
|
|
446
857
|
showShareMenu: options => getDefaultSDK().share.showShareMenu(options),
|
|
447
858
|
screenshot: options => getDefaultSDK().share.screenshot(options),
|
|
448
859
|
};
|
|
449
|
-
/** 默认 SDK
|
|
450
|
-
const
|
|
451
|
-
getWindowInfo: () => getDefaultSDK().
|
|
452
|
-
|
|
453
|
-
|
|
860
|
+
/** 默认 SDK 实例的 Viewport 模块。 */
|
|
861
|
+
const viewport = {
|
|
862
|
+
getWindowInfo: () => getDefaultSDK().viewport.getWindowInfo(),
|
|
863
|
+
};
|
|
864
|
+
/** 默认 SDK 实例的 storage 模块。 */
|
|
865
|
+
const storage = {
|
|
866
|
+
getStorage: options => getDefaultSDK().storage.getStorage(options),
|
|
867
|
+
setStorage: options => getDefaultSDK().storage.setStorage(options),
|
|
868
|
+
};
|
|
869
|
+
/** 默认 SDK 实例的 network 模块。 */
|
|
870
|
+
const network = {
|
|
871
|
+
request: config => getDefaultSDK().network.request(config),
|
|
454
872
|
};
|
|
455
873
|
|
|
456
874
|
const hbSDK = {
|
|
457
875
|
ready,
|
|
458
876
|
on,
|
|
459
877
|
off,
|
|
878
|
+
auth,
|
|
460
879
|
user,
|
|
461
880
|
share,
|
|
462
|
-
|
|
881
|
+
viewport,
|
|
882
|
+
storage,
|
|
883
|
+
network,
|
|
463
884
|
};
|
|
464
885
|
|
|
465
|
-
export { HbMiniProgramSDKError, MINI_PROGRAM_BRIDGE_NONCE_PARAM, MINI_PROGRAM_MESSAGE_NAMESPACE, MINI_PROGRAM_MESSAGE_VERSION, MiniProgramSDK, SDK_HANDSHAKE_METHOD, SHARE_SCREENSHOT_METHOD, SHARE_SHOW_SHARE_MENU_METHOD,
|
|
886
|
+
export { AUTH_LOGIN_METHOD, HbMiniProgramNetworkError, HbMiniProgramSDKError, MINI_PROGRAM_BRIDGE_NONCE_PARAM, MINI_PROGRAM_MESSAGE_NAMESPACE, MINI_PROGRAM_MESSAGE_VERSION, MiniProgramSDK, NETWORK_REQUEST_METHOD, SDK_HANDSHAKE_METHOD, SHARE_SCREENSHOT_METHOD, SHARE_SHOW_SHARE_MENU_METHOD, STORAGE_GET_STORAGE_METHOD, STORAGE_SET_STORAGE_METHOD, USER_GET_INFO_METHOD, VIEWPORT_GET_WINDOW_INFO_METHOD, auth, createAuthModule, createMiniProgramSDK, createNetworkModule, createShareModule, createStorageModule, createUserModule, createViewportModule, hbSDK as default, getInfo, getStorage, getWindowInfo, isMiniProgramBridgeMessage, login, network, off, on, ready, request, screenshot, setStorage, share, showShareMenu, storage, user, viewport };
|