@heybox/hb-sdk 0.1.3 → 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 +167 -37
- 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 +477 -75
- package/dist/index.esm.js +463 -70
- 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 +23 -3
- 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
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/** 小程序沙盒通信命名空间,父容器与 iframe 内 SDK 必须保持一致。 */
|
|
4
|
+
const MINI_PROGRAM_MESSAGE_NAMESPACE = 'heybox:miniprogram';
|
|
5
|
+
/** 小程序沙盒通信协议版本。 */
|
|
6
|
+
const MINI_PROGRAM_MESSAGE_VERSION = 1;
|
|
7
|
+
/** 父容器注入到小程序 URL 上的通信 nonce 参数名。 */
|
|
8
|
+
const MINI_PROGRAM_BRIDGE_NONCE_PARAM = 'hb_mini_bridge_nonce';
|
|
9
|
+
/** SDK 初始化时发给父容器的握手方法名。 */
|
|
10
|
+
const SDK_HANDSHAKE_METHOD = 'sdk.handshake';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 判断未知数据是否符合小程序 bridge 消息信封。
|
|
14
|
+
*
|
|
15
|
+
* @param value 待判断的未知数据。
|
|
16
|
+
* @returns 当数据满足小程序 bridge 消息基础结构时返回 `true`。
|
|
17
|
+
*/
|
|
18
|
+
function isMiniProgramBridgeMessage(value) {
|
|
19
|
+
if (!value || typeof value !== 'object') {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
const message = value;
|
|
23
|
+
return (message.namespace === MINI_PROGRAM_MESSAGE_NAMESPACE &&
|
|
24
|
+
message.version === MINI_PROGRAM_MESSAGE_VERSION &&
|
|
25
|
+
typeof message.nonce === 'string' &&
|
|
26
|
+
typeof message.type === 'string');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 登录授权能力方法名。
|
|
31
|
+
*
|
|
32
|
+
* @remarks
|
|
33
|
+
* 供 SDK 与父容器 runtime 共享同一 bridge method 标识。
|
|
34
|
+
*/
|
|
35
|
+
const AUTH_LOGIN_METHOD = 'auth.login';
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 用户信息能力方法名。
|
|
39
|
+
*
|
|
40
|
+
* @remarks
|
|
41
|
+
* 供 SDK 与父容器 runtime 共享同一 bridge method 标识。
|
|
42
|
+
*/
|
|
43
|
+
const USER_GET_INFO_METHOD = 'user.getInfo';
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 截图分享能力方法名。
|
|
47
|
+
*
|
|
48
|
+
* @remarks
|
|
49
|
+
* 供 SDK 与父容器 runtime 共享同一 bridge method 标识。
|
|
50
|
+
*/
|
|
51
|
+
const SHARE_SCREENSHOT_METHOD = 'share.screenshot';
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 展示分享面板能力方法名。
|
|
55
|
+
*
|
|
56
|
+
* @remarks
|
|
57
|
+
* 供 SDK 与父容器 runtime 共享同一 bridge method 标识。
|
|
58
|
+
*/
|
|
59
|
+
const SHARE_SHOW_SHARE_MENU_METHOD = 'share.showShareMenu';
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* 读取小程序隔离 storage 能力方法名。
|
|
63
|
+
*
|
|
64
|
+
* @remarks
|
|
65
|
+
* 供 SDK 与父容器 runtime 共享同一 bridge method 标识。
|
|
66
|
+
*/
|
|
67
|
+
const STORAGE_GET_STORAGE_METHOD = 'storage.getStorage';
|
|
68
|
+
/**
|
|
69
|
+
* 写入小程序隔离 storage 能力方法名。
|
|
70
|
+
*
|
|
71
|
+
* @remarks
|
|
72
|
+
* 供 SDK 与父容器 runtime 共享同一 bridge method 标识。
|
|
73
|
+
*/
|
|
74
|
+
const STORAGE_SET_STORAGE_METHOD = 'storage.setStorage';
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* 视口窗口信息能力方法名。
|
|
78
|
+
*
|
|
79
|
+
* @remarks
|
|
80
|
+
* 供 SDK 与父容器 runtime 共享同一 bridge method 标识。
|
|
81
|
+
*/
|
|
82
|
+
const VIEWPORT_GET_WINDOW_INFO_METHOD = 'viewport.getWindowInfo';
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 发起网络请求能力方法名。
|
|
86
|
+
*
|
|
87
|
+
* @remarks
|
|
88
|
+
* 供 SDK 与父容器 runtime 共享同一 bridge method 标识。
|
|
89
|
+
*/
|
|
90
|
+
const NETWORK_REQUEST_METHOD = 'network.request';
|
|
91
|
+
|
|
92
|
+
exports.AUTH_LOGIN_METHOD = AUTH_LOGIN_METHOD;
|
|
93
|
+
exports.MINI_PROGRAM_BRIDGE_NONCE_PARAM = MINI_PROGRAM_BRIDGE_NONCE_PARAM;
|
|
94
|
+
exports.MINI_PROGRAM_MESSAGE_NAMESPACE = MINI_PROGRAM_MESSAGE_NAMESPACE;
|
|
95
|
+
exports.MINI_PROGRAM_MESSAGE_VERSION = MINI_PROGRAM_MESSAGE_VERSION;
|
|
96
|
+
exports.NETWORK_REQUEST_METHOD = NETWORK_REQUEST_METHOD;
|
|
97
|
+
exports.SDK_HANDSHAKE_METHOD = SDK_HANDSHAKE_METHOD;
|
|
98
|
+
exports.SHARE_SCREENSHOT_METHOD = SHARE_SCREENSHOT_METHOD;
|
|
99
|
+
exports.SHARE_SHOW_SHARE_MENU_METHOD = SHARE_SHOW_SHARE_MENU_METHOD;
|
|
100
|
+
exports.STORAGE_GET_STORAGE_METHOD = STORAGE_GET_STORAGE_METHOD;
|
|
101
|
+
exports.STORAGE_SET_STORAGE_METHOD = STORAGE_SET_STORAGE_METHOD;
|
|
102
|
+
exports.USER_GET_INFO_METHOD = USER_GET_INFO_METHOD;
|
|
103
|
+
exports.VIEWPORT_GET_WINDOW_INFO_METHOD = VIEWPORT_GET_WINDOW_INFO_METHOD;
|
|
104
|
+
exports.isMiniProgramBridgeMessage = isMiniProgramBridgeMessage;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/** 小程序沙盒通信命名空间,父容器与 iframe 内 SDK 必须保持一致。 */
|
|
2
|
+
const MINI_PROGRAM_MESSAGE_NAMESPACE = 'heybox:miniprogram';
|
|
3
|
+
/** 小程序沙盒通信协议版本。 */
|
|
4
|
+
const MINI_PROGRAM_MESSAGE_VERSION = 1;
|
|
5
|
+
/** 父容器注入到小程序 URL 上的通信 nonce 参数名。 */
|
|
6
|
+
const MINI_PROGRAM_BRIDGE_NONCE_PARAM = 'hb_mini_bridge_nonce';
|
|
7
|
+
/** SDK 初始化时发给父容器的握手方法名。 */
|
|
8
|
+
const SDK_HANDSHAKE_METHOD = 'sdk.handshake';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 判断未知数据是否符合小程序 bridge 消息信封。
|
|
12
|
+
*
|
|
13
|
+
* @param value 待判断的未知数据。
|
|
14
|
+
* @returns 当数据满足小程序 bridge 消息基础结构时返回 `true`。
|
|
15
|
+
*/
|
|
16
|
+
function isMiniProgramBridgeMessage(value) {
|
|
17
|
+
if (!value || typeof value !== 'object') {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
const message = value;
|
|
21
|
+
return (message.namespace === MINI_PROGRAM_MESSAGE_NAMESPACE &&
|
|
22
|
+
message.version === MINI_PROGRAM_MESSAGE_VERSION &&
|
|
23
|
+
typeof message.nonce === 'string' &&
|
|
24
|
+
typeof message.type === 'string');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 登录授权能力方法名。
|
|
29
|
+
*
|
|
30
|
+
* @remarks
|
|
31
|
+
* 供 SDK 与父容器 runtime 共享同一 bridge method 标识。
|
|
32
|
+
*/
|
|
33
|
+
const AUTH_LOGIN_METHOD = 'auth.login';
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 用户信息能力方法名。
|
|
37
|
+
*
|
|
38
|
+
* @remarks
|
|
39
|
+
* 供 SDK 与父容器 runtime 共享同一 bridge method 标识。
|
|
40
|
+
*/
|
|
41
|
+
const USER_GET_INFO_METHOD = 'user.getInfo';
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 截图分享能力方法名。
|
|
45
|
+
*
|
|
46
|
+
* @remarks
|
|
47
|
+
* 供 SDK 与父容器 runtime 共享同一 bridge method 标识。
|
|
48
|
+
*/
|
|
49
|
+
const SHARE_SCREENSHOT_METHOD = 'share.screenshot';
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 展示分享面板能力方法名。
|
|
53
|
+
*
|
|
54
|
+
* @remarks
|
|
55
|
+
* 供 SDK 与父容器 runtime 共享同一 bridge method 标识。
|
|
56
|
+
*/
|
|
57
|
+
const SHARE_SHOW_SHARE_MENU_METHOD = 'share.showShareMenu';
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 读取小程序隔离 storage 能力方法名。
|
|
61
|
+
*
|
|
62
|
+
* @remarks
|
|
63
|
+
* 供 SDK 与父容器 runtime 共享同一 bridge method 标识。
|
|
64
|
+
*/
|
|
65
|
+
const STORAGE_GET_STORAGE_METHOD = 'storage.getStorage';
|
|
66
|
+
/**
|
|
67
|
+
* 写入小程序隔离 storage 能力方法名。
|
|
68
|
+
*
|
|
69
|
+
* @remarks
|
|
70
|
+
* 供 SDK 与父容器 runtime 共享同一 bridge method 标识。
|
|
71
|
+
*/
|
|
72
|
+
const STORAGE_SET_STORAGE_METHOD = 'storage.setStorage';
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* 视口窗口信息能力方法名。
|
|
76
|
+
*
|
|
77
|
+
* @remarks
|
|
78
|
+
* 供 SDK 与父容器 runtime 共享同一 bridge method 标识。
|
|
79
|
+
*/
|
|
80
|
+
const VIEWPORT_GET_WINDOW_INFO_METHOD = 'viewport.getWindowInfo';
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* 发起网络请求能力方法名。
|
|
84
|
+
*
|
|
85
|
+
* @remarks
|
|
86
|
+
* 供 SDK 与父容器 runtime 共享同一 bridge method 标识。
|
|
87
|
+
*/
|
|
88
|
+
const NETWORK_REQUEST_METHOD = 'network.request';
|
|
89
|
+
|
|
90
|
+
export { AUTH_LOGIN_METHOD, MINI_PROGRAM_BRIDGE_NONCE_PARAM, MINI_PROGRAM_MESSAGE_NAMESPACE, MINI_PROGRAM_MESSAGE_VERSION, 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, isMiniProgramBridgeMessage };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# <%= projectName %>
|
|
2
|
+
|
|
3
|
+
这是通过 `hb-sdk create` 生成的黑盒外部小程序开发模板。项目使用 Vue 3、Vite、TypeScript 和 `@heybox/hb-sdk`。
|
|
4
|
+
|
|
5
|
+
## 使用命令
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install
|
|
9
|
+
npm run dev:mock
|
|
10
|
+
npm run dev
|
|
11
|
+
npm run typecheck
|
|
12
|
+
npm run test:unit
|
|
13
|
+
npm run build
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## 开发模式
|
|
17
|
+
|
|
18
|
+
- `npm run dev:mock`:启动本地 Vite 服务和 `hb-sdk` 内置 mock runtime host,适合本地调试 SDK 能力。
|
|
19
|
+
- `npm run dev`:只启动小程序页面服务,适合被真实黑盒小程序容器加载。
|
|
20
|
+
- `npm run build`:先执行 TypeScript 检查,再构建生产产物。
|
|
21
|
+
|
|
22
|
+
普通浏览器直接打开 `npm run dev` 的页面时,SDK 会因为缺少小程序 iframe 容器或 bridge nonce 而显示错误状态。开发时请优先使用 `npm run dev:mock`。
|
|
23
|
+
|
|
24
|
+
## 更多能力
|
|
25
|
+
|
|
26
|
+
模板页面只保留最小接入示例。其他常用能力可以直接从 `@heybox/hb-sdk` 调用:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import hbSDK from '@heybox/hb-sdk';
|
|
30
|
+
|
|
31
|
+
await hbSDK.share.showShareMenu({
|
|
32
|
+
title: '<%= projectName %>',
|
|
33
|
+
desc: '分享描述',
|
|
34
|
+
url: window.location.href,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
await hbSDK.storage.setStorage({
|
|
38
|
+
key: 'settings',
|
|
39
|
+
data: { theme: 'dark' },
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const response = await hbSDK.network.request({
|
|
43
|
+
method: 'GET',
|
|
44
|
+
url: 'https://jsonplaceholder.typicode.com/todos/1',
|
|
45
|
+
});
|
|
46
|
+
```
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title><%= projectName %></title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="app"></div>
|
|
10
|
+
<script type="module" src="/src/main.ts"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "<%= packageName %>",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "hb-sdk dev",
|
|
8
|
+
"dev:mock": "hb-sdk dev --mock --open",
|
|
9
|
+
"build": "vue-tsc --noEmit && vite build",
|
|
10
|
+
"preview": "vite preview",
|
|
11
|
+
"typecheck": "vue-tsc --noEmit",
|
|
12
|
+
"test:unit": "vitest run",
|
|
13
|
+
"test:unit:watch": "vitest"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@heybox/hb-sdk": "^<%= sdkVersion %>",
|
|
17
|
+
"vue": "^3.5.34"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/node": "^25.7.0",
|
|
21
|
+
"@vitejs/plugin-vue": "^6.0.6",
|
|
22
|
+
"@vue/test-utils": "^2.4.10",
|
|
23
|
+
"happy-dom": "^20.9.0",
|
|
24
|
+
"typescript": "^6.0.3",
|
|
25
|
+
"vite": "^8.0.12",
|
|
26
|
+
"vitest": "^4.1.6",
|
|
27
|
+
"vue-tsc": "^3.2.9"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<main class="page">
|
|
3
|
+
<section class="card">
|
|
4
|
+
<p class="eyebrow">Heybox Mini Program</p>
|
|
5
|
+
<h1><%= projectName %></h1>
|
|
6
|
+
<p class="intro">
|
|
7
|
+
这个模板只保留最小接入示例:等待 SDK ready、读取用户信息,并在需要时唤起登录。
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
<p class="status" data-testid="status">{{ status }}</p>
|
|
11
|
+
|
|
12
|
+
<button type="button" :disabled="loading" data-testid="login" @click="login">
|
|
13
|
+
登录并刷新用户信息
|
|
14
|
+
</button>
|
|
15
|
+
|
|
16
|
+
<pre data-testid="output">{{ output }}</pre>
|
|
17
|
+
</section>
|
|
18
|
+
</main>
|
|
19
|
+
</template>
|
|
20
|
+
|
|
21
|
+
<script setup lang="ts">
|
|
22
|
+
import hbSDK from '@heybox/hb-sdk';
|
|
23
|
+
import { onMounted, ref } from 'vue';
|
|
24
|
+
|
|
25
|
+
const loading = ref(false);
|
|
26
|
+
const status = ref('正在连接 SDK...');
|
|
27
|
+
const output = ref('等待 user.getInfo 返回结果。');
|
|
28
|
+
|
|
29
|
+
onMounted(() => {
|
|
30
|
+
void loadUserInfo();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
async function loadUserInfo() {
|
|
34
|
+
await runSdkAction('user.getInfo', async () => {
|
|
35
|
+
await hbSDK.ready();
|
|
36
|
+
return hbSDK.user.getInfo();
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function login() {
|
|
41
|
+
await runSdkAction('auth.login', () => hbSDK.auth.login());
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function runSdkAction(label: string, action: () => Promise<unknown>) {
|
|
45
|
+
loading.value = true;
|
|
46
|
+
status.value = `${label} 调用中...`;
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
const result = await action();
|
|
50
|
+
status.value = `${label} 调用成功`;
|
|
51
|
+
output.value = JSON.stringify(result, null, 2);
|
|
52
|
+
} catch (error) {
|
|
53
|
+
status.value = `${label} 调用失败`;
|
|
54
|
+
output.value = readErrorMessage(error);
|
|
55
|
+
} finally {
|
|
56
|
+
loading.value = false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function readErrorMessage(error: unknown) {
|
|
61
|
+
return error instanceof Error ? `${error.name}: ${error.message}` : String(error);
|
|
62
|
+
}
|
|
63
|
+
</script>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { flushPromises, mount } from '@vue/test-utils';
|
|
2
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import App from '../App.vue';
|
|
4
|
+
|
|
5
|
+
const sdkMock = vi.hoisted(() => ({
|
|
6
|
+
authLogin: vi.fn(),
|
|
7
|
+
ready: vi.fn(),
|
|
8
|
+
userGetInfo: vi.fn(),
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
vi.mock('@heybox/hb-sdk', () => ({
|
|
12
|
+
default: {
|
|
13
|
+
auth: {
|
|
14
|
+
login: sdkMock.authLogin,
|
|
15
|
+
},
|
|
16
|
+
ready: sdkMock.ready,
|
|
17
|
+
user: {
|
|
18
|
+
getInfo: sdkMock.userGetInfo,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
describe('App', () => {
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
vi.resetAllMocks();
|
|
26
|
+
|
|
27
|
+
sdkMock.ready.mockResolvedValue(undefined);
|
|
28
|
+
sdkMock.userGetInfo.mockResolvedValue({
|
|
29
|
+
isLogin: true,
|
|
30
|
+
userInfo: {
|
|
31
|
+
avatar: '',
|
|
32
|
+
heybox_id: '10001',
|
|
33
|
+
nickname: '模板用户',
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
sdkMock.authLogin.mockResolvedValue({
|
|
37
|
+
isLogin: true,
|
|
38
|
+
userInfo: {
|
|
39
|
+
avatar: '',
|
|
40
|
+
heybox_id: '10002',
|
|
41
|
+
nickname: '登录用户',
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('connects to hb-sdk and renders user info', async () => {
|
|
47
|
+
const wrapper = mount(App);
|
|
48
|
+
await flushPromises();
|
|
49
|
+
|
|
50
|
+
expect(sdkMock.ready).toHaveBeenCalledTimes(1);
|
|
51
|
+
expect(sdkMock.userGetInfo).toHaveBeenCalledTimes(1);
|
|
52
|
+
expect(wrapper.get('[data-testid="status"]').text()).toBe('user.getInfo 调用成功');
|
|
53
|
+
expect(wrapper.get('[data-testid="output"]').text()).toContain('模板用户');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('logs in and refreshes the output', async () => {
|
|
57
|
+
const wrapper = mount(App);
|
|
58
|
+
await flushPromises();
|
|
59
|
+
|
|
60
|
+
await wrapper.get('[data-testid="login"]').trigger('click');
|
|
61
|
+
await flushPromises();
|
|
62
|
+
|
|
63
|
+
expect(sdkMock.authLogin).toHaveBeenCalledTimes(1);
|
|
64
|
+
expect(wrapper.get('[data-testid="status"]').text()).toBe('auth.login 调用成功');
|
|
65
|
+
expect(wrapper.get('[data-testid="output"]').text()).toContain('登录用户');
|
|
66
|
+
});
|
|
67
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
color: #1f2933;
|
|
3
|
+
background: #f4f6f8;
|
|
4
|
+
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
5
|
+
line-height: 1.5;
|
|
6
|
+
}
|
|
7
|
+
* {
|
|
8
|
+
box-sizing: border-box;
|
|
9
|
+
}
|
|
10
|
+
body {
|
|
11
|
+
margin: 0; min-width: 320px;
|
|
12
|
+
}
|
|
13
|
+
.page {
|
|
14
|
+
width: min(100%, 720px);
|
|
15
|
+
margin: 0 auto;
|
|
16
|
+
padding: 40px 20px;
|
|
17
|
+
}
|
|
18
|
+
.card {
|
|
19
|
+
border: 1px solid #d8dee6;
|
|
20
|
+
border-radius: 8px;
|
|
21
|
+
background: #fff;
|
|
22
|
+
padding: 24px;
|
|
23
|
+
}
|
|
24
|
+
.eyebrow {
|
|
25
|
+
margin: 0 0 8px;
|
|
26
|
+
color: #287a4b;
|
|
27
|
+
font-size: 13px;
|
|
28
|
+
font-weight: 800;
|
|
29
|
+
}
|
|
30
|
+
h1 {
|
|
31
|
+
margin: 0; font-size: 36px; line-height: 1.1;
|
|
32
|
+
}
|
|
33
|
+
.intro,
|
|
34
|
+
.status {
|
|
35
|
+
color: #52616f;
|
|
36
|
+
}
|
|
37
|
+
button {
|
|
38
|
+
width: 100%;
|
|
39
|
+
min-height: 42px;
|
|
40
|
+
border: 0;
|
|
41
|
+
border-radius: 6px;
|
|
42
|
+
background: #1f2933;
|
|
43
|
+
color: #fff;
|
|
44
|
+
cursor: pointer;
|
|
45
|
+
font: inherit;
|
|
46
|
+
font-weight: 700;
|
|
47
|
+
}
|
|
48
|
+
button:disabled {
|
|
49
|
+
cursor: not-allowed; opacity: 0.6;
|
|
50
|
+
}
|
|
51
|
+
pre {
|
|
52
|
+
margin: 16px 0 0;
|
|
53
|
+
overflow: auto;
|
|
54
|
+
border-radius: 6px;
|
|
55
|
+
background: #101820;
|
|
56
|
+
color: #f7fbff;
|
|
57
|
+
padding: 14px;
|
|
58
|
+
white-space: pre-wrap;
|
|
59
|
+
word-break: break-word;
|
|
60
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"moduleResolution": "Bundler",
|
|
7
|
+
"strict": true,
|
|
8
|
+
"jsx": "preserve",
|
|
9
|
+
"sourceMap": true,
|
|
10
|
+
"resolveJsonModule": true,
|
|
11
|
+
"isolatedModules": true,
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
14
|
+
"types": ["vite/client"]
|
|
15
|
+
},
|
|
16
|
+
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
|
|
17
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heybox/hb-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0-alpha.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -9,25 +9,44 @@
|
|
|
9
9
|
"node": "./dist/index.cjs.js",
|
|
10
10
|
"browser": "./dist/index.esm.js",
|
|
11
11
|
"default": "./dist/index.esm.js"
|
|
12
|
+
},
|
|
13
|
+
"./protocol": {
|
|
14
|
+
"types": "./types/protocol.d.ts",
|
|
15
|
+
"heybox": "./src/protocol.ts",
|
|
16
|
+
"node": "./dist/protocol.cjs.js",
|
|
17
|
+
"browser": "./dist/protocol.esm.js",
|
|
18
|
+
"default": "./dist/protocol.esm.js"
|
|
12
19
|
}
|
|
13
20
|
},
|
|
21
|
+
"bin": {
|
|
22
|
+
"hb-sdk": "./bin/hb-sdk.cjs"
|
|
23
|
+
},
|
|
14
24
|
"files": [
|
|
25
|
+
"bin",
|
|
15
26
|
"dist",
|
|
16
27
|
"types"
|
|
17
28
|
],
|
|
18
29
|
"keywords": [],
|
|
19
30
|
"author": "",
|
|
20
31
|
"license": "ISC",
|
|
21
|
-
"dependencies": {
|
|
22
|
-
"@heybox/utils": "^2.1.1"
|
|
23
|
-
},
|
|
24
32
|
"devDependencies": {
|
|
33
|
+
"@rollup/plugin-commonjs": "^28.0.6",
|
|
34
|
+
"@rollup/plugin-json": "^6.1.0",
|
|
35
|
+
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
25
36
|
"@heybox/hb-types": "^1.0.1",
|
|
26
37
|
"@vitejs/plugin-vue2": "^2.3.3",
|
|
27
38
|
"@rollup/plugin-typescript": "^11.1.6",
|
|
39
|
+
"@types/ejs": "^3.1.5",
|
|
40
|
+
"@types/fs-extra": "^11.0.4",
|
|
28
41
|
"@types/node": "24.10.1",
|
|
29
42
|
"@vitest/coverage-v8": "^3.2.4",
|
|
43
|
+
"commander": "^12.1.0",
|
|
44
|
+
"ejs": "^3.1.10",
|
|
45
|
+
"env-paths": "^2.2.1",
|
|
46
|
+
"fs-extra": "^11.3.0",
|
|
47
|
+
"get-port": "^7.1.0",
|
|
30
48
|
"happy-dom": "^19.0.2",
|
|
49
|
+
"open": "^10.2.0",
|
|
31
50
|
"rimraf": "^5.0.5",
|
|
32
51
|
"rollup": "^4.52.4",
|
|
33
52
|
"typescript": "^5.9.3",
|
|
@@ -57,10 +76,14 @@
|
|
|
57
76
|
},
|
|
58
77
|
"scripts": {
|
|
59
78
|
"dev": "vite",
|
|
60
|
-
"build:package": "nx exec -- sh -c \"pnpm run clean && pnpm run build:lib && pnpm run build:types\"",
|
|
79
|
+
"build:package": "nx exec -- sh -c \"pnpm run clean && pnpm run build:lib && pnpm run build:cli && pnpm run build:mock-host && pnpm run build:templates && pnpm run build:types\"",
|
|
61
80
|
"build:watch": "pnpm run build:lib -w & pnpm run build:types -w",
|
|
62
81
|
"build:lib": "rollup -c rollup.config.ts --configPlugin 'typescript={\"tsconfig\":\"tsconfig.build.json\"}'",
|
|
82
|
+
"build:cli": "rollup -c rollup.config.ts --environment HB_SDK_BUILD:cli --configPlugin 'typescript={\"tsconfig\":\"tsconfig.build.json\"}'",
|
|
83
|
+
"build:mock-host": "node scripts/copy-mock-host.cjs",
|
|
84
|
+
"build:templates": "node scripts/copy-cli-templates.cjs",
|
|
63
85
|
"build:types": "tsc -p tsconfig.dts.json",
|
|
86
|
+
"check:boundary": "node scripts/check-boundary.cjs",
|
|
64
87
|
"clean": "rimraf ./dist && rimraf ./types",
|
|
65
88
|
"test:unit": "NODE_OPTIONS='--conditions=heybox' vitest run",
|
|
66
89
|
"test:unit:coverage": "NODE_OPTIONS='--conditions=heybox' vitest run --coverage",
|
package/types/core/client.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { MiniProgramEventHandler, MiniProgramEventName } from '../protocol/types';
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* 创建 SDK bridge client 的配置项。
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* 该配置主要用于独立实例、自定义宿主环境注入和测试场景。
|
|
7
|
+
*/
|
|
3
8
|
export interface MiniProgramSDKOptions {
|
|
4
9
|
/** 请求与握手超时时间,单位毫秒。 */
|
|
5
10
|
timeout?: number;
|
|
@@ -9,10 +14,24 @@ export interface MiniProgramSDKOptions {
|
|
|
9
14
|
selfWindow?: Window;
|
|
10
15
|
/** 父窗口,测试环境可注入;显式传 null 可模拟非 iframe 环境。 */
|
|
11
16
|
targetWindow?: Window | null;
|
|
17
|
+
/** 精准 postMessage 目标 origin;未传时尝试推断,失败则回退为 `*`。 */
|
|
18
|
+
targetOrigin?: string;
|
|
12
19
|
}
|
|
13
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* 模块 API 发起请求所需的最小能力。
|
|
22
|
+
*
|
|
23
|
+
* @remarks
|
|
24
|
+
* 各公开模块只依赖该最小接口发起 bridge 请求,以保持模块层与底层实现解耦。
|
|
25
|
+
*/
|
|
14
26
|
export interface MiniProgramRequester {
|
|
15
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* 向父容器调用指定开放能力。
|
|
29
|
+
*
|
|
30
|
+
* @typeParam T 标准化后的返回值类型。
|
|
31
|
+
* @param method bridge method 名称。
|
|
32
|
+
* @param payload 可序列化请求载荷。
|
|
33
|
+
* @returns 由父容器返回的标准化结果。
|
|
34
|
+
*/
|
|
16
35
|
request<T>(method: string, payload?: unknown): Promise<T>;
|
|
17
36
|
}
|
|
18
37
|
/** 底层 bridge client,负责握手、请求响应、事件分发与超时清理。 */
|
|
@@ -20,6 +39,7 @@ export declare class MiniProgramBridgeClient implements MiniProgramRequester {
|
|
|
20
39
|
private readonly timeout;
|
|
21
40
|
private readonly selfWindow?;
|
|
22
41
|
private readonly targetWindow;
|
|
42
|
+
private readonly targetOrigin;
|
|
23
43
|
private readonly nonce;
|
|
24
44
|
private readonly pendingRequests;
|
|
25
45
|
private readonly eventBus;
|